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

Revision 919, 12.6 kB (checked in by ppalmers, 16 years ago)

fix concurrency issue in cycle timer updater

Line 
1 /*
2  * Copyright (C) 2005-2008 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 2 of the License, or
12  * (at your option) version 3 of the License.
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 <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <endian.h>
32
33 #include <signal.h>
34 #include "src/debugmodule/debugmodule.h"
35
36 #include <netinet/in.h>
37
38 #include "src/libieee1394/cycletimer.h"
39 #include "src/libieee1394/configrom.h"
40 #include "src/libieee1394/ieee1394service.h"
41 #include "src/libieee1394/ARMHandler.h"
42
43 #include "src/libutil/Thread.h"
44 #include "src/libutil/PosixThread.h"
45 #include <libraw1394/raw1394.h>
46 #include "libutil/Time.h"
47
48
49 #define NB_THREADS 2
50 #define THREAD_RT  true
51 #define THREAD_PRIO 51
52 #define THREAD_SLEEP_US 125
53
54 #define DISP_CYCLE_SLEEP_SECS 2
55
56 using namespace Util;
57
58 DECLARE_GLOBAL_DEBUG_MODULE;
59
60 #define DIFF_CONSIDERED_LARGE (TICKS_PER_CYCLE/2)
61 int PORT_TO_USE = 1;
62
63 int max_diff=-99999;
64 int min_diff= 99999;
65
66 int run=1;
67 static void sighandler (int sig)
68 {
69     run = 0;
70 }
71
72 class MyFunctor : public Functor
73 {
74 public:
75     MyFunctor() {}
76     virtual ~MyFunctor() {}
77
78     void operator() () {
79         printf("hello from the functor (%p)\n", this);
80     };
81 };
82
83 class CtrThread : public Util::RunnableInterface
84 {
85     public:
86         CtrThread(Ieee1394Service *s)
87         : m_service(s)
88         {};
89         virtual ~CtrThread() {};
90         virtual bool Init()
91         {
92             debugOutput(DEBUG_LEVEL_NORMAL, "(%p) Execute\n", this);
93             ctr = 0;
94             ctr_dll = 0;
95        
96             ctr_prev = 0;
97             ctr_dll_prev = 0;
98             nb_checks = 0;
99             summed_diff = 0;
100             avg_diff = 0;
101             m_reset_avg = 1;
102             m_handle = raw1394_new_handle_on_port( PORT_TO_USE );
103             if ( !m_handle ) {
104                 if ( !errno ) {
105                     debugFatal("libraw1394 not compatible\n");
106                 } else {
107                     debugFatal("Ieee1394Service::initialize: Could not get 1394 handle: %s\n",
108                         strerror(errno) );
109                     debugFatal("Is ieee1394 and raw1394 driver loaded?\n");
110                 }
111                 return false;
112             }
113             return true;
114         }
115         virtual bool Execute();
116
117         Ieee1394Service *m_service;
118         raw1394handle_t m_handle;
119         uint64_t ctr;
120         uint64_t ctr_dll;
121
122         uint64_t ctr_prev;
123         uint64_t ctr_dll_prev;
124        
125         uint64_t nb_checks;
126         int64_t summed_diff;
127         double avg_diff;
128         int m_reset_avg;
129 };
130
131 bool CtrThread::Execute() {
132     debugOutput(DEBUG_LEVEL_VERBOSE, "(%p) Execute\n", this);
133    
134     SleepRelativeUsec(THREAD_SLEEP_US);
135
136     uint32_t cycle_timer;
137     uint64_t local_time;
138     uint32_t cycle_timer2;
139     uint64_t local_time2;
140     uint64_t ticks1, ticks2;
141     int err;
142
143     do {
144         // read the CTR 'raw' from a handle
145         // and read it from the 1394 service, which uses a DLL
146         err = raw1394_read_cycle_timer(m_handle, &cycle_timer2, &local_time2);
147         err = raw1394_read_cycle_timer(m_handle, &cycle_timer, &local_time);
148        
149         ticks1 = CYCLE_TIMER_TO_TICKS(cycle_timer);
150         ticks2 = CYCLE_TIMER_TO_TICKS(cycle_timer2);
151     } while (diffTicks(ticks1, ticks2) < 0);
152    
153     ctr_prev = ctr;
154     ctr_dll_prev = ctr_dll;
155    
156     ctr = CYCLE_TIMER_TO_TICKS( cycle_timer );
157     ctr_dll = m_service->getCycleTimerTicks(local_time);
158
159     if(err) {
160         debugError("(%p) CTR read error\n", this);
161     }
162     debugOutput ( DEBUG_LEVEL_VERBOSE,
163                 "(%p) Cycle timer: %011llu (%03us %04ucy %04uticks)\n",
164                 this, ctr,
165                 (unsigned int)TICKS_TO_SECS( ctr ),
166                 (unsigned int)TICKS_TO_CYCLES( ctr ),
167                 (unsigned int)TICKS_TO_OFFSET( ctr ) );
168     debugOutput ( DEBUG_LEVEL_VERBOSE,
169                 "(%p)    from DLL: %011llu (%03us %04ucy %04uticks)\n",
170                 this, ctr_dll,
171                 (unsigned int)TICKS_TO_SECS( ctr_dll ),
172                 (unsigned int)TICKS_TO_CYCLES( ctr_dll ),
173                 (unsigned int)TICKS_TO_OFFSET( ctr_dll ) );
174     int64_t diff = diffTicks(ctr, ctr_dll);
175     uint64_t abs_diff;
176     // for jitter plots
177     //     debugOutput(DEBUG_LEVEL_NORMAL, "9876543210: %lld\n", diff);
178
179     if(m_reset_avg) {
180         m_reset_avg = 0;
181         summed_diff = 0;
182         nb_checks = 0;
183     }
184
185     // not 100% thread safe, but will do
186     if (diff > max_diff) max_diff = diff;
187     if (diff < min_diff) min_diff = diff;
188     summed_diff += diff;
189     nb_checks++;
190     avg_diff = ((double)summed_diff)/((double)nb_checks);
191    
192     if (diff < 0) {
193         abs_diff = -diff;
194     } else {
195         abs_diff = diff;
196     }
197     debugOutput ( DEBUG_LEVEL_VERBOSE,
198                 "(%p)       diff: %s%011llu (%03us %04ucy %04uticks)\n", this,
199                 ((int64_t)abs_diff==diff?" ":"-"), abs_diff, (unsigned int)TICKS_TO_SECS( abs_diff ),
200                 (unsigned int)TICKS_TO_CYCLES( abs_diff ), (unsigned int)TICKS_TO_OFFSET( abs_diff ) );
201     if (abs_diff > DIFF_CONSIDERED_LARGE) {
202         debugWarning("(%p) Alert, large diff: %lld\n", this, diff);
203         debugOutput ( DEBUG_LEVEL_NORMAL,
204                     "(%p)  Cycle timer: %011llu (%03us %04ucy %04uticks)\n",
205                     this, ctr,
206                     (unsigned int)TICKS_TO_SECS( ctr ),
207                     (unsigned int)TICKS_TO_CYCLES( ctr ),
208                     (unsigned int)TICKS_TO_OFFSET( ctr ) );
209         debugOutput ( DEBUG_LEVEL_NORMAL,
210                     "(%p)   from DLL: %011llu (%03us %04ucy %04uticks)\n",
211                     this, ctr_dll,
212                     (unsigned int)TICKS_TO_SECS( ctr_dll ),
213                     (unsigned int)TICKS_TO_CYCLES( ctr_dll ),
214                     (unsigned int)TICKS_TO_OFFSET( ctr_dll ) );
215     }
216    
217     diff = diffTicks(ctr, ctr_prev);
218     if (diff < 0) {
219         debugWarning("(%p) Alert, non-monotonic ctr (direct): %llu - %llu = %lld\n",
220                      this, ctr, ctr_prev, diff);
221         debugOutput ( DEBUG_LEVEL_NORMAL,
222                     "(%p)  Cycle timer now : %011llu (%03us %04ucy %04uticks)\n",
223                     this, ctr,
224                     (unsigned int)TICKS_TO_SECS( ctr ),
225                     (unsigned int)TICKS_TO_CYCLES( ctr ),
226                     (unsigned int)TICKS_TO_OFFSET( ctr ) );
227         debugOutput ( DEBUG_LEVEL_NORMAL,
228                     "(%p)  Cycle timer prev: %011llu (%03us %04ucy %04uticks)\n",
229                     this, ctr_prev,
230                     (unsigned int)TICKS_TO_SECS( ctr_prev ),
231                     (unsigned int)TICKS_TO_CYCLES( ctr_prev ),
232                     (unsigned int)TICKS_TO_OFFSET( ctr_prev ) );
233     }
234     diff = diffTicks(ctr_dll, ctr_dll_prev);
235     if (diff < 0) {
236         debugWarning("(%p) Alert, non-monotonic ctr (dll): %llu - %llu = %lld\n",
237                      this, ctr_dll, ctr_dll_prev, diff);
238         debugOutput ( DEBUG_LEVEL_NORMAL,
239                     "(%p)  Cycle timer now : %011llu (%03us %04ucy %04uticks)\n",
240                     this, ctr_dll,
241                     (unsigned int)TICKS_TO_SECS( ctr_dll ),
242                     (unsigned int)TICKS_TO_CYCLES( ctr_dll ),
243                     (unsigned int)TICKS_TO_OFFSET( ctr_dll ) );
244         debugOutput ( DEBUG_LEVEL_NORMAL,
245                     "(%p)  Cycle timer prev: %011llu (%03us %04ucy %04uticks)\n",
246                     this, ctr_dll_prev,
247                     (unsigned int)TICKS_TO_SECS( ctr_dll_prev ),
248                     (unsigned int)TICKS_TO_CYCLES( ctr_dll_prev ),
249                     (unsigned int)TICKS_TO_OFFSET( ctr_dll_prev ) );
250     }
251    
252     // check some calculations
253     uint32_t tmp_orig = m_service->getCycleTimer();
254     uint32_t tmp_ticks = CYCLE_TIMER_TO_TICKS(tmp_orig);
255     uint32_t tmp_ctr = TICKS_TO_CYCLE_TIMER(tmp_ticks);
256    
257     if (tmp_orig != tmp_ctr) {
258         debugError("CTR => TICKS => CTR failed\n");
259         debugOutput ( DEBUG_LEVEL_VERBOSE,
260                     "(%p) orig CTR : %08X (%03us %04ucy %04uticks)\n",
261                     this, (uint32_t)tmp_orig,
262                     (unsigned int)CYCLE_TIMER_GET_SECS( tmp_orig ),
263                     (unsigned int)CYCLE_TIMER_GET_CYCLES( tmp_orig ),
264                     (unsigned int)CYCLE_TIMER_GET_OFFSET( tmp_orig ) );
265         debugOutput ( DEBUG_LEVEL_VERBOSE,
266                     "(%p) TICKS: %011llu (%03us %04ucy %04uticks)\n",
267                     this, tmp_ticks,
268                     (unsigned int)TICKS_TO_SECS( tmp_ticks ),
269                     (unsigned int)TICKS_TO_CYCLES( tmp_ticks ),
270                     (unsigned int)TICKS_TO_OFFSET( tmp_ticks ) );
271         debugOutput ( DEBUG_LEVEL_VERBOSE,
272                     "(%p) new CTR : %08X (%03us %04ucy %04uticks)\n",
273                     this, (uint32_t)tmp_ctr,
274                     (unsigned int)CYCLE_TIMER_GET_SECS( tmp_ctr ),
275                     (unsigned int)CYCLE_TIMER_GET_CYCLES( tmp_ctr ),
276                     (unsigned int)CYCLE_TIMER_GET_OFFSET( tmp_ctr ) );
277     }
278    
279     debugOutput ( DEBUG_LEVEL_VERBOSE,
280                 "(%p)  wait...\n", this);
281     return true;
282 }
283
284 int main(int argc, char *argv[])
285 {
286     int i=0;
287     setDebugLevel(DEBUG_LEVEL_NORMAL);
288     signal (SIGINT, sighandler);
289     signal (SIGPIPE, sighandler);
290
291
292     printf("FFADO Ieee1394Service test application\n");
293
294     Ieee1394Service *m_service=NULL;
295
296     m_service = new Ieee1394Service();
297     m_service->setVerboseLevel(DEBUG_LEVEL_VERBOSE);
298     if(!m_service->initialize(PORT_TO_USE)) {
299         printf("Could not initialize 1394 service\n");
300         delete m_service;
301         exit(-1);
302     }
303     m_service->setThreadParameters(true, 60);
304
305     MyFunctor *test_busreset=new MyFunctor();
306
307     printf(" adding (%p) as busreset handler\n", test_busreset);
308
309     m_service->addBusResetHandler(test_busreset);
310
311     nodeaddr_t addr =  m_service->findFreeARMBlock(0x0000FFFFE0000000ULL, 4, 4 );
312
313     ARMHandler *test_arm=new ARMHandler(addr,
314                          4,
315                          RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
316                          RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
317                          0);
318
319     printf(" adding (%p) as arm handler\n", test_arm);
320
321     if (!m_service->registerARMHandler(test_arm)) {
322         printf("  failed\n");
323     }
324
325     addr =  m_service->findFreeARMBlock(0x0000FFFFE0000000ULL, 4, 4 );
326
327     ARMHandler *test_arm2=new ARMHandler(addr,
328                          4,
329                          RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
330                          RAW1394_ARM_READ | RAW1394_ARM_WRITE | RAW1394_ARM_LOCK,
331                          0);
332
333     printf(" adding (%p) as arm handler\n", test_arm2);
334
335     if (!m_service->registerARMHandler(test_arm2)) {
336         printf("  failed\n");
337     }
338
339     CtrThread *thread_runners[NB_THREADS];
340     Thread* threads[NB_THREADS];
341     for (i=0; i < NB_THREADS; i++) {
342         thread_runners[i] = new CtrThread(m_service);
343         if (thread_runners[i] == NULL) {
344             debugError("could not create thread runner %d\n", i);
345             exit(-1);
346         }
347         threads[i] = new PosixThread(thread_runners[i], THREAD_RT, THREAD_PRIO, PTHREAD_CANCEL_DEFERRED);
348         if (threads[i] == NULL) {
349             debugError("could not create thread %d\n", i);
350             exit(-1);
351         }
352     }
353    
354     for (i=0; i < NB_THREADS; i++) {
355         threads[i]->Start();
356     }
357
358     int cnt=0;
359     while(run) {
360         cnt++;
361         debugOutput(DEBUG_LEVEL_NORMAL, "%08d: (max: %6d, min: %6d)\n", cnt, max_diff, min_diff);
362         m_service->show();
363         max_diff = -999999;
364         min_diff = 999999;
365        
366         for (i=0; i < NB_THREADS; i++) {
367             debugOutput(DEBUG_LEVEL_NORMAL, "%2d: avg: %6f\n", i,  thread_runners[i]->avg_diff);
368             thread_runners[i]->m_reset_avg = 1;
369         }
370        
371        
372         sleep(DISP_CYCLE_SLEEP_SECS);
373     }
374
375     for (i=0; i < NB_THREADS; i++) {
376         threads[i]->Stop();
377     }
378
379     for (i=0; i < NB_THREADS; i++) {
380         delete threads[i];
381         delete thread_runners[i];
382     }
383
384     delete m_service;
385     delete test_busreset;
386     delete test_arm;
387     delete test_arm2;
388
389     printf("Bye...\n");
390
391     return EXIT_SUCCESS;
392 }
Note: See TracBrowser for help on using the browser.