root/branches/streaming-rework/tests/test-timestampedbuffer.cpp

Revision 393, 16.1 kB (checked in by pieterpalmers, 16 years ago)

- fixed some bugs in the timestampedbuffer
- cleaned up the amdtpstreamprocessor
- updated test-sytmonitor and test-cycletimer

to the new threading structure

- implemented test for timestampedbuffer

Line 
1 /***************************************************************************
2 Copyright (C) 2007 by Pieter Palmers   *
3                                                                         *
4 This program is free software; you can redistribute it and/or modify  *
5 it under the terms of the GNU General Public License as published by  *
6 the Free Software Foundation; either version 2 of the License, or     *
7 (at your option) any later version.                                   *
8                                                                         *
9 This program is distributed in the hope that it will be useful,       *
10 but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12 GNU General Public License for more details.                          *
13                                                                         *
14 You should have received a copy of the GNU General Public License     *
15 along with this program; if not, write to the                         *
16 Free Software Foundation, Inc.,                                       *
17 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <argp.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <endian.h>
29
30 #include <signal.h>
31 #include "src/debugmodule/debugmodule.h"
32
33 #include <netinet/in.h>
34
35 #include "src/libstreaming/cycletimer.h"
36
37 #include "src/libutil/TimestampedBuffer.h"
38
39 #include <pthread.h>
40
41 using namespace FreebobUtil;
42
43 class TimestampedBufferTestClient
44     : public TimestampedBufferClient {
45 public:
46     bool processReadBlock(char *data, unsigned int nevents, unsigned int offset) {return true;};
47     bool processWriteBlock(char *data, unsigned int nevents, unsigned int offset) {return true;};
48    
49     void setVerboseLevel(int l) {setDebugLevel(l);};
50 private:
51     DECLARE_DEBUG_MODULE;
52 };
53
54 IMPL_DEBUG_MODULE( TimestampedBufferTestClient, TimestampedBufferTestClient, DEBUG_LEVEL_VERBOSE );
55
56 DECLARE_GLOBAL_DEBUG_MODULE;
57
58 int run;
59 // Program documentation.
60 static char doc[] = "FreeBoB -- Timestamped buffer test\n\n";
61
62 // A description of the arguments we accept.
63 static char args_doc[] = "";
64
65
66 struct arguments
67 {
68     short verbose;
69     uint64_t wrap_at;
70     uint64_t frames_per_packet;
71     uint64_t events_per_frame;
72     float rate;
73     uint64_t total_cycles;
74     uint64_t buffersize;
75     uint64_t start_at_cycle;
76 };
77
78 // The options we understand.
79 static struct argp_option options[] = {
80     {"verbose",     'v',    "n",    0,  "Verbose level" },
81     {"wrap",        'w',    "n",    0,  "Wrap at (ticks) (3072000)" },
82     {"fpp",        'f',    "n",    0,  "Frames per packet (8)" },
83     {"epf",        'e',    "n",    0,  "Events per frame (10)" },
84     {"rate",        'r',    "n",    0,  "Rate (ticks/frame) (512.0)" },
85     {"cycles",        'c',    "n",    0,  "Total cycles to run (2000)" },
86     {"buffersize",        'b',    "n",    0,  "Buffer size (in frames) (1024)" },
87     {"startcycle",        's',    "n",    0,  "Start at cycle (0)" },
88     { 0 }
89 };
90
91 //-------------------------------------------------------------
92
93 // Parse a single option.
94 static error_t
95 parse_opt( int key, char* arg, struct argp_state* state )
96 {
97     // Get the input argument from `argp_parse', which we
98     // know is a pointer to our arguments structure.
99     struct arguments* arguments = ( struct arguments* ) state->input;
100     char* tail;
101
102     switch (key) {
103         case 'v':
104             if (arg) {
105                 arguments->verbose = strtoll( arg, &tail, 0 );
106                 if ( errno ) {
107                     fprintf( stderr, "Could not parse 'verbose' argument\n" );
108                     return ARGP_ERR_UNKNOWN;
109                 }
110             } else {
111                 if ( errno ) {
112                     fprintf( stderr, "Could not parse 'verbose' argument\n" );
113                     return ARGP_ERR_UNKNOWN;
114                 }
115             }
116             break;
117         case 'w':
118             if (arg) {
119                 arguments->wrap_at = strtoll( arg, &tail, 0 );
120                 if ( errno ) {
121                     fprintf( stderr, "Could not parse 'wrap' argument\n" );
122                     return ARGP_ERR_UNKNOWN;
123                 }
124             } else {
125                 if ( errno ) {
126                     fprintf( stderr, "Could not parse 'wrap' argument\n" );
127                     return ARGP_ERR_UNKNOWN;
128                 }
129             }
130             break;
131         case 'f':
132             if (arg) {
133                 arguments->frames_per_packet = strtoll( arg, &tail, 0 );
134                 if ( errno ) {
135                     fprintf( stderr, "Could not parse 'fpp' argument\n" );
136                     return ARGP_ERR_UNKNOWN;
137                 }
138             } else {
139                 if ( errno ) {
140                     fprintf( stderr, "Could not parse 'fpp' argument\n" );
141                     return ARGP_ERR_UNKNOWN;
142                 }
143             }
144             break;
145         case 'e':
146             if (arg) {
147                 arguments->events_per_frame = strtoll( arg, &tail, 0 );
148                 if ( errno ) {
149                     fprintf( stderr, "Could not parse 'epf' argument\n" );
150                     return ARGP_ERR_UNKNOWN;
151                 }
152             } else {
153                 if ( errno ) {
154                     fprintf( stderr, "Could not parse 'epf' argument\n" );
155                     return ARGP_ERR_UNKNOWN;
156                 }
157             }
158             break;
159         case 'c':
160             if (arg) {
161                 arguments->total_cycles = strtoll( arg, &tail, 0 );
162                 if ( errno ) {
163                     fprintf( stderr, "Could not parse 'cycles' argument\n" );
164                     return ARGP_ERR_UNKNOWN;
165                 }
166             } else {
167                 if ( errno ) {
168                     fprintf( stderr, "Could not parse 'cycles' argument\n" );
169                     return ARGP_ERR_UNKNOWN;
170                 }
171             }
172             break;
173         case 's':
174             if (arg) {
175                 arguments->start_at_cycle = strtoll( arg, &tail, 0 );
176                 if ( errno ) {
177                     fprintf( stderr, "Could not parse 'startcycle' argument\n" );
178                     return ARGP_ERR_UNKNOWN;
179                 }
180             } else {
181                 if ( errno ) {
182                     fprintf( stderr, "Could not parse 'startcycle' argument\n" );
183                     return ARGP_ERR_UNKNOWN;
184                 }
185             }
186             break;
187         case 'b':
188             if (arg) {
189                 arguments->buffersize = strtoll( arg, &tail, 0 );
190                 if ( errno ) {
191                     fprintf( stderr, "Could not parse 'buffersize' argument\n" );
192                     return ARGP_ERR_UNKNOWN;
193                 }
194             } else {
195                 if ( errno ) {
196                     fprintf( stderr, "Could not parse 'buffersize' argument\n" );
197                     return ARGP_ERR_UNKNOWN;
198                 }
199             }
200             break;
201         case 'r':
202             if (arg) {
203                 arguments->rate = strtof( arg, &tail );
204                 if ( errno ) {
205                     fprintf( stderr, "Could not parse 'rate' argument\n" );
206                     return ARGP_ERR_UNKNOWN;
207                 }
208             } else {
209                 if ( errno ) {
210                     fprintf( stderr, "Could not parse 'rate' argument\n" );
211                     return ARGP_ERR_UNKNOWN;
212                 }
213             }
214             break;                       
215        default:
216             return ARGP_ERR_UNKNOWN;
217     }
218     return 0;
219 }
220
221 // Our argp parser.
222 static struct argp argp = { options, parse_opt, args_doc, doc };
223
224
225 static void sighandler (int sig)
226 {
227         run = 0;
228 }
229
230 int main(int argc, char *argv[])
231 {
232    
233     TimestampedBuffer *t=NULL;
234     TimestampedBufferTestClient *c=NULL;
235    
236     struct arguments arguments;
237
238     // Default values.
239     arguments.verbose        = 0;
240     arguments.wrap_at = 3072000LLU; // 1000 cycles
241     arguments.frames_per_packet = 8;
242     arguments.events_per_frame = 10;
243     arguments.rate = 512.0;
244     arguments.total_cycles = 2000;
245     arguments.buffersize = 1024;
246     arguments.start_at_cycle = 0;
247    
248     // Parse our arguments; every option seen by `parse_opt' will
249     // be reflected in `arguments'.
250     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
251         fprintf( stderr, "Could not parse command line\n" );
252         exit(1);
253     }
254    
255     setDebugLevel(arguments.verbose);
256    
257     run=1;
258
259     signal (SIGINT, sighandler);
260     signal (SIGPIPE, sighandler);
261    
262     c=new TimestampedBufferTestClient();
263    
264     if(!c) {
265         debugOutput(DEBUG_LEVEL_NORMAL, "Could not create TimestampedBufferTestClient\n");
266         exit(1);
267     }
268     c->setVerboseLevel(arguments.verbose);
269    
270     t=new TimestampedBuffer(c);
271    
272     if(!t) {
273         debugOutput(DEBUG_LEVEL_NORMAL, "Could not create TimestampedBuffer\n");
274         delete c;
275         exit(1);
276     }
277     t->setVerboseLevel(arguments.verbose);
278
279     t->init();
280    
281     // Setup the buffer
282     t->setBufferSize(arguments.buffersize);
283     t->setEventSize(sizeof(int));
284     t->setEventsPerFrame(arguments.events_per_frame);
285
286     t->setUpdatePeriod(arguments.frames_per_packet);
287     t->setNominalRate(arguments.rate);
288    
289     t->setWrapValue(arguments.wrap_at);
290    
291     t->prepare();
292    
293     usleep(1000);
294    
295     debugOutput(DEBUG_LEVEL_NORMAL, "Start test 1...\n");
296
297     int dummyframe_in[arguments.events_per_frame*arguments.frames_per_packet];
298     int dummyframe_out[arguments.events_per_frame*arguments.frames_per_packet];
299    
300     for (unsigned int i=0;i<arguments.events_per_frame*arguments.frames_per_packet;i++) {
301         dummyframe_in[i]=i;
302     }
303    
304     uint64_t time=arguments.start_at_cycle*3072;
305    
306     // initialize the timestamp
307     uint64_t timestamp=time;
308     if (timestamp >= arguments.wrap_at) {
309         // here we need a modulo because start_at_cycle can be large
310         timestamp %= arguments.wrap_at;
311     }
312     t->setBufferTailTimestamp(timestamp);
313    
314     timestamp += (uint64_t)(arguments.rate * arguments.frames_per_packet);
315     if (timestamp >= arguments.wrap_at) {
316         timestamp -= arguments.wrap_at;
317     }
318    
319     for(unsigned int cycle=arguments.start_at_cycle;
320         cycle < arguments.start_at_cycle+arguments.total_cycles;
321         cycle++) {
322        
323         // simulate the rate adaptation
324         int64_t diff=(time%arguments.wrap_at)-timestamp;
325        
326         if (diff>(int64_t)arguments.wrap_at/2) {
327             diff -= arguments.wrap_at;
328         } else if (diff<(-(int64_t)arguments.wrap_at)/2){
329             diff += arguments.wrap_at;
330         }
331        
332         debugOutput(DEBUG_LEVEL_NORMAL, "Simulating cycle %d @ time=%011llu, diff=%lld\n",cycle,time,diff);
333        
334         if(diff>0) {
335             uint64_t ts_head, fc_head;
336             uint64_t ts_tail, fc_tail;
337            
338             // write one packet
339             t->writeFrames(arguments.frames_per_packet, (char *)&dummyframe_in, timestamp);
340
341             // read the buffer head timestamp
342             t->getBufferHeadTimestamp(&ts_head, &fc_head);
343             t->getBufferTailTimestamp(&ts_tail, &fc_tail);
344             debugOutput(DEBUG_LEVEL_NORMAL,
345                     " TS after write: HEAD: %011llu, FC=%04u\n",
346                     ts_head,fc_head);
347             debugOutput(DEBUG_LEVEL_NORMAL,
348                     "                 TAIL: %011llu, FC=%04u\n",
349                     ts_tail,fc_tail);
350
351             // read one packet
352             t->readFrames(arguments.frames_per_packet, (char *)&dummyframe_out);
353
354             // read the buffer head timestamp
355             t->getBufferHeadTimestamp(&ts_head, &fc_head);
356             t->getBufferTailTimestamp(&ts_tail, &fc_tail);
357             debugOutput(DEBUG_LEVEL_NORMAL,
358                     " TS after write: HEAD: %011llu, FC=%04u\n",
359                     ts_head,fc_head);
360             debugOutput(DEBUG_LEVEL_NORMAL,
361                     "                 TAIL: %011llu, FC=%04u\n",
362                     ts_tail,fc_tail);
363
364             // check
365             bool pass=true;
366             for (unsigned int i=0;i<arguments.events_per_frame*arguments.frames_per_packet;i++) {
367                 pass = pass && (dummyframe_in[i]==dummyframe_out[i]);
368             }
369             if (!pass) {
370                 debugOutput(DEBUG_LEVEL_NORMAL, "write/read check for cycle %d failed\n",cycle);
371             }
372
373             // update the timestamp
374             timestamp += (uint64_t)(arguments.rate * arguments.frames_per_packet);
375             if (timestamp >= arguments.wrap_at) {
376                 timestamp -= arguments.wrap_at;
377             }
378         }
379
380         // simulate the cycle timer clock in ticks
381         time += 3072;
382         if (time >= arguments.wrap_at) {
383             time -= arguments.wrap_at;
384         }
385        
386         // allow for the messagebuffer thread to catch up
387         usleep(200);
388        
389         if(!run) break;
390     }
391
392     // second run, now do block processing
393     debugOutput(DEBUG_LEVEL_NORMAL, "Start test 2...\n");
394     unsigned int blocksize=32;
395     int dummyframe_out_block[arguments.events_per_frame*arguments.frames_per_packet*blocksize];
396    
397     time=arguments.start_at_cycle*3072;
398    
399     // initialize the timestamp
400     timestamp=time;
401     if (timestamp >= arguments.wrap_at) {
402         // here we need a modulo because start_at_cycle can be large
403         timestamp %= arguments.wrap_at;
404     }
405     t->setBufferTailTimestamp(timestamp);
406    
407     timestamp += (uint64_t)(arguments.rate * arguments.frames_per_packet);
408     if (timestamp >= arguments.wrap_at) {
409         timestamp -= arguments.wrap_at;
410     }
411    
412     for(unsigned int cycle=arguments.start_at_cycle;
413         cycle < arguments.start_at_cycle+arguments.total_cycles;
414         cycle++) {
415        
416         // simulate the rate adaptation
417         int64_t diff=(time%arguments.wrap_at)-timestamp;
418        
419         if (diff>(int64_t)arguments.wrap_at/2) {
420             diff -= arguments.wrap_at;
421         } else if (diff<(-(int64_t)arguments.wrap_at)/2){
422             diff += arguments.wrap_at;
423         }
424        
425         debugOutput(DEBUG_LEVEL_NORMAL, "Simulating cycle %d @ time=%011llu, diff=%lld\n",cycle,time,diff);
426        
427         if(diff>0) {
428             uint64_t ts_head, fc_head;
429             uint64_t ts_tail, fc_tail;
430            
431             // write one packet
432             t->writeFrames(arguments.frames_per_packet, (char *)&dummyframe_in, timestamp);
433
434             // read the buffer head timestamp
435             t->getBufferHeadTimestamp(&ts_head, &fc_head);
436             t->getBufferTailTimestamp(&ts_tail, &fc_tail);
437             debugOutput(DEBUG_LEVEL_NORMAL,
438                     " TS after write: HEAD: %011llu, FC=%04u\n",
439                     ts_head,fc_head);
440             debugOutput(DEBUG_LEVEL_NORMAL,
441                     "                 TAIL: %011llu, FC=%04u\n",
442                     ts_tail,fc_tail);
443
444             if (fc_head > blocksize) {
445                 debugOutput(DEBUG_LEVEL_NORMAL,"Reading one block (%u frames)\n",blocksize);
446                
447                 // read one block
448                 t->readFrames(blocksize, (char *)&dummyframe_out_block);
449    
450                 // read the buffer head timestamp
451                 t->getBufferHeadTimestamp(&ts_head, &fc_head);
452                 t->getBufferTailTimestamp(&ts_tail, &fc_tail);
453                 debugOutput(DEBUG_LEVEL_NORMAL,
454                         " TS after read: HEAD: %011llu, FC=%04u\n",
455                         ts_head,fc_head);
456                 debugOutput(DEBUG_LEVEL_NORMAL,
457                         "                TAIL: %011llu, FC=%04u\n",
458                         ts_tail,fc_tail);
459             }
460            
461             // update the timestamp
462             timestamp += (uint64_t)(arguments.rate * arguments.frames_per_packet);
463             if (timestamp >= arguments.wrap_at) {
464                 timestamp -= arguments.wrap_at;
465             }
466         }
467
468         // simulate the cycle timer clock in ticks
469         time += 3072;
470         if (time >= arguments.wrap_at) {
471             time -= arguments.wrap_at;
472         }
473        
474         // allow for the messagebuffer thread to catch up
475         usleep(200);
476        
477         if(!run) break;
478     }
479    
480
481     delete t;
482     delete c;
483        
484     return EXIT_SUCCESS;
485 }
486
487
Note: See TracBrowser for help on using the browser.