Belle II Software development
dummy_data_distrib.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include <iostream>
9#include <vector>
10#include <stdio.h>
11#include <stdlib.h>
12#include <netinet/in.h>
13#include <sys/types.h>
14#include <sys/socket.h>
15#include <sys/time.h>
16#include <time.h>
17#include <string.h>
18#include <unistd.h>
19#include <arpa/inet.h>
20#include <limits.h>
21#include <signal.h>
22#include <poll.h>
23
24
26// Parameter for data-contents
28//#define REDUCED_DATA
29//#define CRC_ON
30#define LISTENQ 1
31#define NUM_CLIENTS 5
32#define MAX_EVENT 1000
33
34// Format (PCIe40)
35#define NW_SEND_HEADER 6
36#define NW_SEND_TRAILER 2
37
38#define NW_RAW_HEADER 8
39#define NW_RAW_TRAILER 4
40
41#ifdef REDUCED_DATA
42#define NW_B2L_HEADER 3
43#define NW_B2L_TRAILER 2
44#else
45#define NW_B2L_HEADER 7
46#define NW_B2L_TRAILER 3
47#endif
48
49#define CTIME_VAL 0x12345601
50
51using namespace std;
52
53unsigned short CalcCRC16LittleEndian(unsigned short crc16, const int buf[], int nwords)
54{
55
56 if (nwords < 0) {
57 char err_buf[500];
58 sprintf(err_buf, "nwords value(%d) is invalid. Cannot calculate CRC16. Exiting...\n %s %s %d\n",
59 nwords, __FILE__, __PRETTY_FUNCTION__, __LINE__);
60 printf("%s", err_buf); fflush(stdout);
61 string err_str = err_buf;
62 throw (err_str);
63 }
64
65 const unsigned short CRC16Table0x1021[ 256 ] = {
66 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
67 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
68 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
69 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
70 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
71 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
72 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
73 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
74
75 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
76 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
77 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
78 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
79 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
80 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
81 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
82 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
83
84 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
85 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
86 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
87 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
88 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
89 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
90 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
91 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
92
93 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
94 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
95 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
96 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
97 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
98 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
99 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
100 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
101 };
102
103 int cnt = 0, nints = 0;
104 // printf("### %.8x %.4x\n", buf[ 0 ], crc16);
105 while (nwords != 0) {
106
107 unsigned char temp_buf = *((unsigned char*)(buf + nints) + (-(cnt % 4) + 3));
108 crc16 = CRC16Table0x1021[(crc16 >> (16 - CHAR_BIT)) ^ temp_buf ] ^ (crc16 << CHAR_BIT);
109 // printf("%.2x %.4x\n", temp_buf, crc16);
110 if ((cnt % 4) == 3) {
111 nwords--;
112 nints++;
113 // printf("### %.8x\n", buf[ nints ] );
114 }
115
116 cnt++;
117 }
118
119
120 return crc16;
121
122}
123
124
125double getTimeSec()
126{
127 struct timeval t;
128 gettimeofday(&t, NULL);
129 return (t.tv_sec + t.tv_usec * 1.e-6 - 1417570000.);
130}
131
132int fillDataContents(int* buf, int nwords_per_fee, unsigned int node_id, int ncpr, int nhslb, int run)
133{
134 int nwords = NW_SEND_HEADER + NW_SEND_TRAILER +
135 ncpr * (NW_RAW_HEADER +
136 (NW_B2L_HEADER + NW_B2L_TRAILER + nwords_per_fee) * nhslb
137 + NW_RAW_TRAILER);
138
139 // Send Header
140 int offset = 0;
141 buf[ offset + 0 ] = nwords;
142 buf[ offset + 1 ] = 6;
143 buf[ offset + 2 ] = (1 << 16) | ncpr;
144 unsigned int exp_run = run << 8;
145 buf[ offset + 3 ] = exp_run;
146 buf[ offset + 5 ] = node_id;
147 offset += NW_SEND_HEADER;
148
149 for (int k = 0; k < ncpr; k++) {
150 //
151 // RawHeader
152 //
153 int cpr_nwords = NW_RAW_HEADER +
154 (NW_B2L_HEADER + NW_B2L_TRAILER + nwords_per_fee) * nhslb
155 + NW_RAW_TRAILER;
156 unsigned int ctime = CTIME_VAL;
157 unsigned int utime = 0x98765432;
158
159 buf[ offset + 0 ] = cpr_nwords;
160#ifdef REDUCED_DATA
161 buf[ offset + 1 ] = 0x7f7f020c;
162#else
163 buf[ offset + 1 ] = 0x7f7f820c;
164#endif
165 buf[ offset + 2 ] = exp_run;
166 printf("run_no %u\n", exp_run); fflush(stdout);
167 buf[ offset + 4 ] = ctime;
168 buf[ offset + 5 ] = utime;
169 buf[ offset + 6 ] = node_id + k;
170 buf[ offset + 7 ] = 0x34567890;
171 offset += NW_RAW_HEADER;
172
173 for (int i = 0; i < nhslb ; i++) {
174#ifdef REDUCED_DATA
175 buf[ offset + 0 ] = nwords_per_fee + 3;
176 buf[ offset + 1 ] = 0xffaa0000;
177 buf[ offset + 2 ] = ctime;
178#else
179 buf[ offset + 0 ] = nwords_per_fee + 7;
180 buf[ offset + 1 ] = 0xffaa0000;
181 buf[ offset + 3 ] = ctime;
182 buf[ offset + 4 ] = utime;
183 buf[ offset + 5 ] = exp_run;
184 buf[ offset + 6 ] = ctime;
185#endif
186 offset += NW_B2L_HEADER;
187
188 for (int j = offset; j < offset + nwords_per_fee; j++) {
189 buf[ j ] = rand();
190 }
191 offset += nwords_per_fee;
192
193#ifdef REDUCED_DATA
194 buf[ offset ] = 0;
195 buf[ offset + 1 ] = 0xff550000;
196#else
197 buf[ offset ] = ctime;
198 buf[ offset + 1 ] = 0;
199 buf[ offset + 2 ] = 0xff550000;
200#endif
201
202 offset += NW_B2L_TRAILER;
203 }
204 buf[ offset ] = 0x0; // error bits
205 buf[ offset + 1 ] = 0x0; // error slots
206 buf[ offset + 2 ] = 0x0; // XOR checksum
207 buf[ offset + 3 ] = 0x7fff0006;
208 offset += NW_RAW_TRAILER;
209 }
210
211 // Send trailer
212 buf[ offset ] = 0;
213 buf[ offset + 1 ] = 0x7fff0000;
214 offset += NW_SEND_TRAILER;
215 return offset;
216}
217
218
219
220inline void addEvent(int* buf, int nwords_per_fee, unsigned int event, int ncpr, int nhslb)
221//inline void addEvent(int* buf, int nwords, unsigned int event)
222{
223 int offset = 0;
224 buf[ offset + 4 ] = event;
225 offset += NW_SEND_HEADER;
226
227 for (int k = 0; k < ncpr; k++) {
228 int nwords = buf[ offset ];
229 int posback_xorchksum = 2;
230 int pos_xorchksum = offset + nwords - posback_xorchksum;
231 if (buf[ offset + 4 ] != CTIME_VAL) {
232 printf("[FATAL] data-production error 2 0x%.x", buf[ offset + 4 ]);
233 fflush(stdout);
234 exit(1);
235 }
236 // RawHeader
237 buf[ pos_xorchksum ] ^= buf[ offset + 3];
238 buf[ offset + 3] = event;
239 buf[ pos_xorchksum ] ^= buf[ offset + 3];
240
241 // COPPER header
242 offset += NW_RAW_HEADER;
243 for (int i = 0; i < nhslb ; i++) {
244 if ((buf[ offset + 1 ] & 0xffff0000) != 0xffaa0000) {
245 printf("[FATAL] data-production error 3 : 0x%.x hslb %d cpr %d\n", buf[ offset ], i, k);
246 fflush(stdout);
247 exit(1);
248 }
249 buf[ offset + 1 ] = 0xffaa0000 + (event & 0xffff);
250 buf[ offset + 3 ] = event;
251
252#ifdef CRC_ON
253 int* crc_buf = buf + offset + 2; // 1 => size of HSLB B2L header
254 int crc_nwords = nwords_per_fee + 5; // 5 => size of FEE B2L header
255 unsigned short temp_crc16 = CalcCRC16LittleEndian(0xffff, crc_buf, crc_nwords);
256 buf[ offset + NW_B2L_HEADER + nwords_per_fee + 1 ] = ((event & 0x0000ffff) << 16) | temp_crc16;
257#endif
258
259#ifdef REDUCED_DATA
260 offset += NW_B2L_HEADER + nwords_per_fee + NW_B2L_TRAILER;
261#else
262 offset += NW_B2L_HEADER + nwords_per_fee + NW_B2L_TRAILER;
263#endif
264 }
265 offset += NW_RAW_TRAILER;
266 }
267
268}
269
270
271int main(int argc, char** argv)
272{
273
274 printf("###################################################\n");
275#ifdef REDUCED_DATA
276 printf("# PCIe40 data after reduction (#define REDUCED_DATA) #\n");
277#else
278 printf("# PCIe40 data before reduction (//#define REDUCED_DATA) #\n");
279#endif
280 printf("###################################################\n");
281
282 if (argc != 6) {
283 printf("Usage : %s <node ID> <run#> <nwords of det. buf per FEE> <# of CPR per COPPER> <# of HSLBs>\n", argv[ 0 ]);
284 exit(1);
285 }
286
287 //
288 // network connection
289 //
290 int listenfd;
291 struct sockaddr_in servaddr;
292 struct pollfd client[NUM_CLIENTS + 1];
293
294 //
295 // dummy data
296 //
297 unsigned int node_id = 0;
298 sscanf(argv[1], "0x%x", &node_id);
299
300 int run_no = atoi(argv[2]);
301 int nwords_per_fee = atoi(argv[3]);
302 int ncpr = atoi(argv[4]);
303 int nhslb = atoi(argv[5]);
304
305 int total_words = NW_SEND_HEADER + NW_SEND_TRAILER +
306 ncpr * (NW_RAW_HEADER + (NW_B2L_HEADER + NW_B2L_TRAILER + nwords_per_fee) * nhslb +
307 NW_RAW_TRAILER);
308 printf("TET %d %d %d %d %d\n ", NW_SEND_HEADER + NW_SEND_TRAILER, ncpr,
309 NW_RAW_HEADER, (NW_B2L_HEADER + NW_B2L_TRAILER + nwords_per_fee) * nhslb, NW_RAW_TRAILER);
310 vector<int> buff(total_words);
311
312 //
313 // Prepare header
314 //
315 int temp_ret = fillDataContents(buff.data(), nwords_per_fee, node_id, ncpr, nhslb, run_no);
316 if (temp_ret != total_words) {
317 printf("[FATAL] data-production error 1 %d %d\n", total_words, temp_ret);
318 fflush(stdout);
319 exit(1);
320 }
321
322 listenfd = socket(AF_INET, SOCK_STREAM, 0);
323 memset(&servaddr, 0, sizeof(servaddr));
324 servaddr.sin_family = AF_INET;
325 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
326 servaddr.sin_port = htons(30000);
327
328 int flags = 1;
329 int ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &flags, (socklen_t)sizeof(flags));
330 if (ret < 0) {
331 perror("Failed to set REUSEADDR");
332 }
333
334 bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
335
336 listen(listenfd, LISTENQ);
337
338 client[0].fd = listenfd;
339 client[0].events = POLLRDNORM;
340
341 for (int i = 1; i <= NUM_CLIENTS; i++) {
342 client[i].fd = -1;
343 }
344
345 int maxi = 0;
346 int nconn = 0;
347
348 while (1) {
349 //int nready = poll(client, maxi + 1, -1);
350 if (client[0].revents & POLLRDNORM) {
351 printf("Accepting..."); fflush(stdout);
352 int connfd = accept(listenfd, (struct sockaddr*) NULL, NULL);
353 int id;
354 for (id = 1; id <= NUM_CLIENTS; id++) {
355 if (client[id].fd < 0) {
356 client[id].fd = connfd;
357 client[id].events = POLLRDNORM;
358 nconn++;
359 printf("Done. connections (%d/%d)", nconn, NUM_CLIENTS); fflush(stdout);
360 break;
361 }
362 }
363 if (id > NUM_CLIENTS) {
364 perror("[FATAL] too many clients.");
365 exit(1);
366 }
367 if (id > maxi) maxi = id;
368 if (nconn >= NUM_CLIENTS) break;
369 // if( -nready <= 0 ) continue;
370
371 } else {
372 printf("No connection request. Still waiting..."); fflush(stdout);
373 }
374 }
375
376 printf("All connections accepted\n"); fflush(stdout);
377
378 double init_time = getTimeSec();
379 double prev_time = init_time;
380
381 unsigned long long int cnt = 0;
382 unsigned long long int prev_cnt = 0;
383 unsigned long long int start_cnt = 300000;
384
385#ifdef MAX_EVENT
386 for (int j = 0; j < MAX_EVENT; j++) {
387#else
388 for (;;) {
389#endif
390 // addEvent(buff, total_words, cnt);
391 addEvent(buff.data(), nwords_per_fee, cnt, ncpr, nhslb);
392 // printf("cnt %d bytes\n", cnt*total_words); fflush(stdout);
393 // sprintf( buff, "event %d dessa", cnt );
394
395 // for(int i = 0 ; i < total_words ; i++){
396 // printf("%.8x ", buff[ i ]);
397 // if( i % 10 == 9 ) printf("\n");
398 // }
399
400 for (int i = 1 ; i <= NUM_CLIENTS ; i++) {
401 int Ret = 0;
402 if ((Ret = write(client[i].fd, buff.data(), total_words * sizeof(int))) <= 0) {
403 printf("[FATAL] Return value %d\n", Ret);
404 fflush(stdout);
405 exit(1);
406 }
407 }
408
409 cnt++;
410
411 if (cnt == start_cnt) init_time = getTimeSec();
412 if (cnt % 10000 == 1) {
413 if (cnt > start_cnt) {
414 double cur_time = getTimeSec();
415 printf("run %d evt %llu time %.1lf dataflow %.1lf MB/s rate %.2lf kHz : so far dataflow %.1lf MB/s rate %.2lf kHz size %d\n",
416 run_no,
417 cnt,
418 cur_time - init_time,
419 NUM_CLIENTS * (cnt - prev_cnt)*total_words * sizeof(int) / 1000000. / (cur_time - prev_time),
420 (cnt - prev_cnt) / (cur_time - prev_time) / 1000.,
421 NUM_CLIENTS * (cnt - start_cnt)*total_words * sizeof(int) / 1000000. / (cur_time - init_time),
422 (cnt - start_cnt) / (cur_time - init_time) / 1000., total_words);
423
424 fflush(stdout);
425 prev_time = cur_time;
426 prev_cnt = cnt;
427 } else {
428 // printf("Eve %lld\n", cnt);fflush(stdout);
429 }
430 }
431 }
432
433
434 for (int i = 1; i <= NUM_CLIENTS; i++) {
435 close(client[i].fd);
436 }
437
438
439}
STL namespace.