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

Revision 879, 12.0 kB (checked in by ppalmers, 13 years ago)

- improve cycle timer DLL

  • make it robust against bogus CTR reads
  • remove offset introduced by delay between wakeup and CTR read

prediction performance is now around 100 ticks for a 50ms update loop.

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