root/trunk/libffado/src/libieee1394/CycleTimerHelper.cpp

Revision 912, 19.8 kB (checked in by ppalmers, 13 years ago)

fix bug in cycle timer dll

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 #include "config.h"
25
26 #include "CycleTimerHelper.h"
27 #include "ieee1394service.h"
28 #include "libutil/PosixThread.h"
29
30 #define DLL_PI        (3.141592653589793238)
31 #define DLL_SQRT2     (1.414213562373095049)
32
33 // the high-bandwidth coefficients are used
34 // to speed up inital tracking
35 #define DLL_BANDWIDTH_HIGH (0.1)
36 #define DLL_OMEGA_HIGH     (2.0*DLL_PI*DLL_BANDWIDTH_HIGH)
37 #define DLL_COEFF_B_HIGH   (DLL_SQRT2 * DLL_OMEGA_HIGH)
38 #define DLL_COEFF_C_HIGH   (DLL_OMEGA_HIGH * DLL_OMEGA_HIGH)
39
40 // the low-bandwidth coefficients are used once we have a
41 // good estimate of the internal parameters
42 #define DLL_BANDWIDTH (0.01)
43 #define DLL_OMEGA     (2.0*DLL_PI*DLL_BANDWIDTH)
44 #define DLL_COEFF_B   (DLL_SQRT2 * DLL_OMEGA)
45 #define DLL_COEFF_C   (DLL_OMEGA * DLL_OMEGA)
46
47 // is 5 sec
48 #define UPDATES_WITH_HIGH_BANDWIDTH \
49          (5000000 / IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC)
50
51 /*
52 #define ENTER_CRITICAL_SECTION { \
53     if (pthread_mutex_trylock(&m_compute_vars_lock) == EBUSY) { \
54         debugWarning(" (%p) lock clash\n", this); \
55         ENTER_CRITICAL_SECTION; \
56     } \
57     }
58 */
59 #define ENTER_CRITICAL_SECTION { \
60     pthread_mutex_lock(&m_compute_vars_lock); \
61     }
62 #define EXIT_CRITICAL_SECTION { \
63     pthread_mutex_unlock(&m_compute_vars_lock); \
64     }
65
66 IMPL_DEBUG_MODULE( CycleTimerHelper, CycleTimerHelper, DEBUG_LEVEL_NORMAL );
67
68 CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us)
69     : m_Parent ( parent )
70     , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL )
71     , m_usecs_per_update ( update_period_us )
72     , m_avg_wakeup_delay ( 0.0 )
73     , m_dll_e2 ( 0.0 )
74     , m_current_time_usecs ( 0 )
75     , m_next_time_usecs ( 0 )
76     , m_current_time_ticks ( 0 )
77     , m_next_time_ticks ( 0 )
78     , m_first_run ( true )
79     , m_sleep_until ( 0 )
80     , m_cycle_timer_prev ( 0 )
81     , m_cycle_timer_ticks_prev ( 0 )
82     , m_high_bw_updates ( UPDATES_WITH_HIGH_BANDWIDTH )
83     , m_Thread ( NULL )
84     , m_realtime ( false )
85     , m_priority ( 0 )
86 {
87     debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this);
88 }
89
90 CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us, bool rt, int prio)
91     : m_Parent ( parent )
92     , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL )
93     , m_usecs_per_update ( update_period_us )
94     , m_avg_wakeup_delay ( 0.0 )
95     , m_dll_e2 ( 0.0 )
96     , m_current_time_usecs ( 0 )
97     , m_next_time_usecs ( 0 )
98     , m_current_time_ticks ( 0 )
99     , m_next_time_ticks ( 0 )
100     , m_first_run ( true )
101     , m_sleep_until ( 0 )
102     , m_cycle_timer_prev ( 0 )
103     , m_cycle_timer_ticks_prev ( 0 )
104     , m_high_bw_updates ( UPDATES_WITH_HIGH_BANDWIDTH )
105     , m_Thread ( NULL )
106     , m_realtime ( rt )
107     , m_priority ( prio )
108 {
109     debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this);
110 }
111
112 CycleTimerHelper::~CycleTimerHelper()
113 {
114     if (m_Thread) {
115         m_Thread->Stop();
116         delete m_Thread;
117     }
118 }
119
120 bool
121 CycleTimerHelper::Start()
122 {
123     debugOutput( DEBUG_LEVEL_VERBOSE, "Start %p...\n", this);
124
125     // initialize the 'prev ctr' values
126     uint64_t local_time;
127     int maxtries2 = 10;
128     do {
129         if(!m_Parent.readCycleTimerReg(&m_cycle_timer_prev, &local_time)) {
130             debugError("Could not read cycle timer register\n");
131             return false;
132         }
133         if (m_cycle_timer_prev == 0) {
134             debugOutput(DEBUG_LEVEL_VERBOSE,
135                         "Bogus CTR: %08X on try %02d\n",
136                         m_cycle_timer_prev, maxtries2);
137         }
138     } while (m_cycle_timer_prev == 0 && maxtries2--);
139     m_cycle_timer_ticks_prev = CYCLE_TIMER_TO_TICKS(m_cycle_timer_prev);
140
141 #if IEEE1394SERVICE_USE_CYCLETIMER_DLL
142     m_high_bw_updates = UPDATES_WITH_HIGH_BANDWIDTH;
143     m_Thread = new Util::PosixThread(this, m_realtime, m_priority,
144                                      PTHREAD_CANCEL_DEFERRED);
145     if(!m_Thread) {
146         debugFatal("No thread\n");
147         return false;
148     }
149     if (m_Thread->Start() != 0) {
150         debugFatal("Could not start update thread\n");
151         return false;
152     }
153 #endif
154     return true;
155 }
156
157 bool
158 CycleTimerHelper::Init()
159 {
160     debugOutput( DEBUG_LEVEL_VERBOSE, "Initialize %p...\n", this);
161     pthread_mutex_init(&m_compute_vars_lock, NULL);
162     return true;
163 }
164
165 bool
166 CycleTimerHelper::setThreadParameters(bool rt, int priority) {
167     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
168     if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority
169     m_realtime = rt;
170     m_priority = priority;
171
172 #if IEEE1394SERVICE_USE_CYCLETIMER_DLL
173     if (m_Thread) {
174         if (m_realtime) {
175             m_Thread->AcquireRealTime(m_priority);
176         } else {
177             m_Thread->DropRealTime();
178         }
179     }
180 #endif
181
182     return true;
183 }
184
185 #if IEEE1394SERVICE_USE_CYCLETIMER_DLL
186 float
187 CycleTimerHelper::getRate()
188 {
189     float rate = (float)(diffTicks((uint64_t)m_next_time_ticks, (uint64_t)m_current_time_ticks));
190     rate /= (float)(m_next_time_usecs - m_current_time_usecs);
191     return rate;
192 }
193
194 float
195 CycleTimerHelper::getNominalRate()
196 {
197     float rate = ((double)TICKS_PER_SECOND) / 1000000.0;
198     return rate;
199 }
200
201 bool
202 CycleTimerHelper::Execute()
203 {
204     debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, "Execute %p...\n", this);
205     if (!m_first_run) {
206         // wait for the next update period
207         ffado_microsecs_t now = m_TimeSource.getCurrentTimeAsUsecs();
208         int sleep_time = m_sleep_until - now;
209         debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, "(%p) Sleep until %lld/%f (now: %lld, diff=%d) ...\n",
210                     this, m_sleep_until, m_next_time_usecs, now, sleep_time);
211         m_TimeSource.SleepUsecAbsolute(m_sleep_until);
212         debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, " (%p) back...\n", this);
213     }
214
215     uint32_t cycle_timer;
216     uint64_t local_time;
217     int64_t usecs_late;
218     int ntries=2;
219     uint64_t cycle_timer_ticks;
220     double diff_ticks;
221
222     // if the difference between the predicted value and the
223     // actual value seems to be too large, retry reading the cycle timer
224     // some host controllers return bogus values on some reads
225     // (looks like a non-atomic update of the register)
226     do {
227         if(!readCycleTimerWithRetry(&cycle_timer, &local_time, 10)) {
228             debugError("Could not read cycle timer register\n");
229             return false;
230         }
231         usecs_late = local_time - m_sleep_until;
232         cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer);
233         diff_ticks = diffTicks(cycle_timer_ticks, (int64_t)m_next_time_ticks);
234
235         // check for unrealistic CTR reads (NEC controller does that sometimes)
236         if(diff_ticks < -((double)TICKS_PER_HALFCYCLE)) {
237             debugOutput(DEBUG_LEVEL_VERBOSE,
238                         "have to retry CTR read, diff unrealistic: diff: %f, max: %f\n",
239                         diff_ticks, -((double)TICKS_PER_HALFCYCLE));
240         }
241
242     } while(diff_ticks < -((double)TICKS_PER_HALFCYCLE) && --ntries && !m_first_run);
243
244     debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, " read : CTR: %11lu, local: %17llu\n",
245                         cycle_timer, local_time);
246         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
247                            "  ctr   : 0x%08X %11llu (%03us %04ucy %04uticks)\n",
248                            (uint32_t)cycle_timer, (uint64_t)cycle_timer_ticks,
249                            (unsigned int)TICKS_TO_SECS( (uint64_t)cycle_timer_ticks ),
250                            (unsigned int)TICKS_TO_CYCLES( (uint64_t)cycle_timer_ticks ),
251                            (unsigned int)TICKS_TO_OFFSET( (uint64_t)cycle_timer_ticks ) );
252
253     if (m_first_run) {
254         m_sleep_until = local_time + m_usecs_per_update;
255         m_dll_e2 = m_ticks_per_update;
256         m_current_time_usecs = local_time;
257         m_next_time_usecs = m_current_time_usecs + m_usecs_per_update;
258         m_current_time_ticks = CYCLE_TIMER_TO_TICKS( cycle_timer );
259         m_next_time_ticks = addTicks( (uint64_t)m_current_time_ticks, (uint64_t)m_dll_e2);
260         debugOutput(DEBUG_LEVEL_VERBOSE, " First run\n");
261         debugOutput(DEBUG_LEVEL_VERBOSE,
262                     "  usecs/update: %lu, ticks/update: %lu, m_dll_e2: %f\n",
263                     m_usecs_per_update, m_ticks_per_update, m_dll_e2);
264         debugOutput(DEBUG_LEVEL_VERBOSE,
265                     "  usecs current: %f, next: %f\n",
266                     m_current_time_usecs, m_next_time_usecs);
267         debugOutput(DEBUG_LEVEL_VERBOSE,
268                     "  ticks current: %f, next: %f\n",
269                     m_current_time_ticks, m_next_time_ticks);
270         m_first_run = false;
271     } else {
272         // calculate next sleep time
273         m_sleep_until += m_usecs_per_update;
274
275         // correct for the latency between the wakeup and the actual CTR
276         // read. The only time we can trust is the time returned by the
277         // CTR read kernel call, since that (should be) atomically read
278         // together with the ctr register itself.
279
280         // if we are usecs_late usecs late
281         // the cycle timer has ticked approx ticks_late ticks too much
282         // if we are woken up early (which shouldn't happen according to POSIX)
283         // the cycle timer has ticked approx -ticks_late too little
284         int64_t ticks_late = (usecs_late * TICKS_PER_SECOND) / 1000000LL;
285         // the corrected difference between predicted and actual ctr
286         // i.e. DLL error signal
287         double diff_ticks_corr;
288         if (ticks_late > 0) {
289             diff_ticks_corr = diff_ticks - ticks_late;
290             debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
291                                "diff_ticks_corr=%f, diff_ticks = %f, ticks_late = %lld\n",
292                                diff_ticks_corr, diff_ticks, ticks_late);
293         } else {
294             debugError("Early wakeup, should not happen!\n");
295             // recover
296             diff_ticks_corr = diff_ticks + ticks_late;
297         }
298
299         #ifdef DEBUG
300         if(usecs_late > 200) {
301             debugWarning("Rather late wakeup: %lld usecs\n", usecs_late);
302         }
303         #endif
304
305         // update the x-axis values
306         m_current_time_ticks = m_next_time_ticks;
307
308         // decide what coefficients to use
309         double coeff_b, coeff_c;
310         if (m_high_bw_updates > 0) {
311             coeff_b = DLL_COEFF_B_HIGH;
312             coeff_c = DLL_COEFF_C_HIGH;
313             m_high_bw_updates--;
314             if (m_high_bw_updates == 0) {
315                 debugOutput(DEBUG_LEVEL_VERBOSE,
316                             "Switching to low-bandwidth coefficients\n");
317             }
318         } else {
319             coeff_b = DLL_COEFF_B;
320             coeff_c = DLL_COEFF_C;
321         }
322
323         // it should be ok to not do this in tick space
324         // since diff_ticks_corr should not be near wrapping
325         // (otherwise we are out of range. we need a few calls
326         //  w/o wrapping for this to work. That should not be
327         //  an issue as long as the update interval is smaller
328         //  than the wrapping interval.)
329         // and coeff_b < 1, hence tmp is not near wrapping
330
331         double step_ticks = (coeff_b * diff_ticks_corr);
332         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
333                            "diff_ticks_corr=%f, step_ticks=%f\n",
334                            diff_ticks_corr, step_ticks);
335
336         // the same goes for m_dll_e2, which should be approx equal
337         // to the ticks/usec rate (= 24.576) hence also not near
338         // wrapping
339         step_ticks += m_dll_e2;
340         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
341                            "add %f ticks to step_ticks => step_ticks=%f\n",
342                            m_dll_e2, step_ticks);
343
344         // it can't be that we have to update to a value in the past
345         if(step_ticks < 0) {
346             debugError("negative step: %f! (correcting to nominal)\n", step_ticks);
347             // recover to an estimated value
348             step_ticks = (double)m_ticks_per_update;
349         }
350
351         if(step_ticks > TICKS_PER_SECOND) {
352             debugWarning("rather large step: %f ticks (> 1sec)\n", step_ticks);
353         }
354
355         // now add the step ticks with wrapping.
356         m_next_time_ticks = (double)(addTicks((uint64_t)m_current_time_ticks, (uint64_t)step_ticks));
357
358         // update the DLL state
359         m_dll_e2 += coeff_c * diff_ticks_corr;
360
361         // update the y-axis values
362         m_current_time_usecs = m_next_time_usecs;
363         m_next_time_usecs += m_usecs_per_update;
364
365         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
366                            " usecs: current: %f next: %f usecs_late=%lld ticks_late=%lld\n",
367                            m_current_time_usecs, m_next_time_usecs, usecs_late, ticks_late);
368         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
369                            " ticks: current: %f next: %f diff=%f\n",
370                            m_current_time_ticks, m_next_time_ticks, diff_ticks);
371         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
372                            " ticks: current: %011llu (%03us %04ucy %04uticks)\n",
373                            (uint64_t)m_current_time_ticks,
374                            (unsigned int)TICKS_TO_SECS( (uint64_t)m_current_time_ticks ),
375                            (unsigned int)TICKS_TO_CYCLES( (uint64_t)m_current_time_ticks ),
376                            (unsigned int)TICKS_TO_OFFSET( (uint64_t)m_current_time_ticks ) );
377         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
378                            " ticks: next   : %011llu (%03us %04ucy %04uticks)\n",
379                            (uint64_t)m_next_time_ticks,
380                            (unsigned int)TICKS_TO_SECS( (uint64_t)m_next_time_ticks ),
381                            (unsigned int)TICKS_TO_CYCLES( (uint64_t)m_next_time_ticks ),
382                            (unsigned int)TICKS_TO_OFFSET( (uint64_t)m_next_time_ticks ) );
383
384         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
385                            " state: local: %11llu, dll_e2: %f, rate: %f\n",
386                            local_time, m_dll_e2, getRate());
387     }
388
389     // FIXME: priority inversion possible, run this at higher prio than client threads
390     ENTER_CRITICAL_SECTION;
391     m_current_vars.ticks = (uint64_t)(m_current_time_ticks);
392     m_current_vars.usecs = (uint64_t)m_current_time_usecs;
393     m_current_vars.rate = getRate();
394     EXIT_CRITICAL_SECTION;
395
396     return true;
397 }
398
399 uint32_t
400 CycleTimerHelper::getCycleTimerTicks()
401 {
402     uint64_t now = m_Parent.getCurrentTimeAsUsecs();
403     return getCycleTimerTicks(now);
404 }
405
406 uint32_t
407 CycleTimerHelper::getCycleTimerTicks(uint64_t now)
408 {
409     uint32_t retval;
410     struct compute_vars my_vars;
411
412     // reduce lock contention
413     ENTER_CRITICAL_SECTION;
414     my_vars = m_current_vars;
415     EXIT_CRITICAL_SECTION;
416
417     int64_t time_diff = now - my_vars.usecs;
418     double y_step_in_ticks = ((double)time_diff) * my_vars.rate;
419     int64_t y_step_in_ticks_int = (int64_t)y_step_in_ticks;
420     uint64_t offset_in_ticks_int = my_vars.ticks;
421
422     if (y_step_in_ticks_int > 0) {
423         retval = addTicks(offset_in_ticks_int, y_step_in_ticks_int);
424 /*        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "y_step_in_ticks_int > 0: %lld, time_diff: %f, rate: %f, retval: %lu\n",
425                     y_step_in_ticks_int, time_diff, my_vars.rate, retval);*/
426     } else {
427         retval = substractTicks(offset_in_ticks_int, -y_step_in_ticks_int);
428
429         // this can happen if the update thread was woken up earlier than it should have been
430 /*        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "y_step_in_ticks_int <= 0: %lld, time_diff: %f, rate: %f, retval: %lu\n",
431                     y_step_in_ticks_int, time_diff, my_vars.rate, retval);*/
432     }
433
434     return retval;
435 }
436
437 uint32_t
438 CycleTimerHelper::getCycleTimer()
439 {
440     uint64_t now = m_Parent.getCurrentTimeAsUsecs();
441     return getCycleTimer(now);
442 }
443
444 uint32_t
445 CycleTimerHelper::getCycleTimer(uint64_t now)
446 {
447     uint32_t ticks = getCycleTimerTicks(now);
448     uint32_t result = TICKS_TO_CYCLE_TIMER(ticks);
449 #ifdef DEBUG
450     if(CYCLE_TIMER_TO_TICKS(result) != ticks) {
451         debugWarning("Bad ctr conversion");
452     }
453 #endif
454     return result;
455 }
456
457 #else
458
459 float
460 CycleTimerHelper::getRate()
461 {
462     return getNominalRate();
463 }
464
465 float
466 CycleTimerHelper::getNominalRate()
467 {
468     float rate = ((double)TICKS_PER_SECOND) / 1000000.0;
469     return rate;
470 }
471
472 bool
473 CycleTimerHelper::Execute()
474 {
475     usleep(1000*1000);
476     return true;
477 }
478
479 uint32_t
480 CycleTimerHelper::getCycleTimerTicks()
481 {
482     return CYCLE_TIMER_TO_TICKS(getCycleTimer());
483 }
484
485 uint32_t
486 CycleTimerHelper::getCycleTimerTicks(uint64_t now)
487 {
488     debugWarning("not implemented!\n");
489     return getCycleTimerTicks();
490 }
491
492 uint32_t
493 CycleTimerHelper::getCycleTimer()
494 {
495     uint32_t cycle_timer;
496     uint64_t local_time;
497     readCycleTimerWithRetry(&cycle_timer, &local_time, 10);
498     return cycle_timer;
499 }
500
501 uint32_t
502 CycleTimerHelper::getCycleTimer(uint64_t now)
503 {
504     debugWarning("not implemented!\n");
505     return getCycleTimer();
506 }
507
508 #endif
509
510 bool
511 CycleTimerHelper::readCycleTimerWithRetry(uint32_t *cycle_timer, uint64_t *local_time, int ntries)
512 {
513     bool good=false;
514     int maxtries = ntries;
515
516     do {
517         // the ctr read can return 0 sometimes. if that happens, reread the ctr.
518         int maxtries2=ntries;
519         do {
520             if(!m_Parent.readCycleTimerReg(cycle_timer, local_time)) {
521                 debugError("Could not read cycle timer register\n");
522                 return false;
523             }
524             if (*cycle_timer == 0) {
525                 debugOutput(DEBUG_LEVEL_VERBOSE,
526                            "Bogus CTR: %08X on try %02d\n",
527                            *cycle_timer, maxtries2);
528             }
529         } while (*cycle_timer == 0 && maxtries2--);
530        
531         // catch bogus ctr reads (can happen)
532         uint64_t cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(*cycle_timer);
533    
534         if (diffTicks(cycle_timer_ticks, m_cycle_timer_ticks_prev) < 0) {
535             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
536                         "non-monotonic CTR (try %02d): %llu -> %llu\n",
537                         maxtries, m_cycle_timer_ticks_prev, cycle_timer_ticks);
538             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
539                         "                            : %08X -> %08X\n",
540                         m_cycle_timer_prev, *cycle_timer);
541             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
542                         " current: %011llu (%03us %04ucy %04uticks)\n",
543                         cycle_timer_ticks,
544                         (unsigned int)TICKS_TO_SECS( cycle_timer_ticks ),
545                         (unsigned int)TICKS_TO_CYCLES( cycle_timer_ticks ),
546                         (unsigned int)TICKS_TO_OFFSET( cycle_timer_ticks ) );
547             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
548                         " prev   : %011llu (%03us %04ucy %04uticks)\n",
549                         m_cycle_timer_ticks_prev,
550                         (unsigned int)TICKS_TO_SECS( m_cycle_timer_ticks_prev ),
551                         (unsigned int)TICKS_TO_CYCLES( m_cycle_timer_ticks_prev ),
552                         (unsigned int)TICKS_TO_OFFSET( m_cycle_timer_ticks_prev ) );
553         } else {
554             good = true;
555             m_cycle_timer_prev = *cycle_timer;
556             m_cycle_timer_ticks_prev = cycle_timer_ticks;
557         }
558     } while (!good && maxtries--);
559     return true;
560 }
561
562 void
563 CycleTimerHelper::setVerboseLevel(int l)
564 {
565     setDebugLevel(l);
566 }
Note: See TracBrowser for help on using the browser.