root/branches/api-cleanup/tests/test-timestampedbuffer.cpp

Revision 813, 19.5 kB (checked in by ppalmers, 16 years ago)

small simplification

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