root/trunk/libffado/tests/test-timestampedbuffer.cpp

Revision 742, 19.4 kB (checked in by ppalmers, 13 years ago)

- Remove some obsolete support files and dirs

- Clean up the license statements in the source files. Everything is

GPL version 3 now.

- Add license and copyright notices to scons scripts

- Clean up some other text files

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