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

Revision 932, 24.6 kB (checked in by ppalmers, 16 years ago)

- implement bus reset handling for the CTR DLL
- move the functor header to libutil

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 #include "libutil/Atomic.h"
30
31 #define DLL_PI        (3.141592653589793238)
32 #define DLL_SQRT2     (1.414213562373095049)
33
34 // the high-bandwidth coefficients are used
35 // to speed up inital tracking
36 #define DLL_BANDWIDTH_HIGH (0.2)
37 #define DLL_OMEGA_HIGH     (2.0*DLL_PI*DLL_BANDWIDTH_HIGH)
38 #define DLL_COEFF_B_HIGH   (DLL_SQRT2 * DLL_OMEGA_HIGH)
39 #define DLL_COEFF_C_HIGH   (DLL_OMEGA_HIGH * DLL_OMEGA_HIGH)
40
41 // the low-bandwidth coefficients are used once we have a
42 // good estimate of the internal parameters
43 #define DLL_BANDWIDTH (0.01)
44 #define DLL_OMEGA     (2.0*DLL_PI*DLL_BANDWIDTH)
45 #define DLL_COEFF_B   (DLL_SQRT2 * DLL_OMEGA)
46 #define DLL_COEFF_C   (DLL_OMEGA * DLL_OMEGA)
47
48 // is 5 sec
49 #define UPDATES_WITH_HIGH_BANDWIDTH \
50          (5000000 / IEEE1394SERVICE_CYCLETIMER_DLL_UPDATE_INTERVAL_USEC)
51
52 IMPL_DEBUG_MODULE( CycleTimerHelper, CycleTimerHelper, DEBUG_LEVEL_NORMAL );
53
54 CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us)
55     : m_Parent ( parent )
56     , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL )
57     , m_usecs_per_update ( update_period_us )
58     , m_avg_wakeup_delay ( 0.0 )
59     , m_dll_e2 ( 0.0 )
60     , m_current_time_usecs ( 0 )
61     , m_next_time_usecs ( 0 )
62     , m_current_time_ticks ( 0 )
63     , m_next_time_ticks ( 0 )
64     , m_first_run ( true )
65     , m_sleep_until ( 0 )
66     , m_cycle_timer_prev ( 0 )
67     , m_cycle_timer_ticks_prev ( 0 )
68     , m_high_bw_updates ( UPDATES_WITH_HIGH_BANDWIDTH )
69     , m_current_shadow_idx ( 0 )
70     , m_Thread ( NULL )
71     , m_realtime ( false )
72     , m_priority ( 0 )
73     , m_busreset_functor ( NULL)
74     , m_unhandled_busreset ( false )
75 {
76     debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this);
77     pthread_mutex_init(&mb_update_lock, NULL);
78 }
79
80 CycleTimerHelper::CycleTimerHelper(Ieee1394Service &parent, unsigned int update_period_us, bool rt, int prio)
81     : m_Parent ( parent )
82     , m_ticks_per_update ( ((uint64_t)TICKS_PER_SECOND) * ((uint64_t)update_period_us) / 1000000ULL )
83     , m_usecs_per_update ( update_period_us )
84     , m_avg_wakeup_delay ( 0.0 )
85     , m_dll_e2 ( 0.0 )
86     , m_current_time_usecs ( 0 )
87     , m_next_time_usecs ( 0 )
88     , m_current_time_ticks ( 0 )
89     , m_next_time_ticks ( 0 )
90     , m_first_run ( true )
91     , m_sleep_until ( 0 )
92     , m_cycle_timer_prev ( 0 )
93     , m_cycle_timer_ticks_prev ( 0 )
94     , m_high_bw_updates ( UPDATES_WITH_HIGH_BANDWIDTH )
95     , m_current_shadow_idx ( 0 )
96     , m_Thread ( NULL )
97     , m_realtime ( rt )
98     , m_priority ( prio )
99     , m_busreset_functor ( NULL)
100     , m_unhandled_busreset ( false )
101 {
102     debugOutput( DEBUG_LEVEL_VERBOSE, "Create %p...\n", this);
103     pthread_mutex_init(&mb_update_lock, NULL);
104 }
105
106 CycleTimerHelper::~CycleTimerHelper()
107 {
108     if (m_Thread) {
109         m_Thread->Stop();
110         delete m_Thread;
111     }
112
113     // unregister the bus reset handler
114     if(m_busreset_functor) {
115         m_Parent.remBusResetHandler( m_busreset_functor );
116         delete m_busreset_functor;
117     }
118     pthread_mutex_destroy(&mb_update_lock);
119 }
120
121 bool
122 CycleTimerHelper::Start()
123 {
124     debugOutput( DEBUG_LEVEL_VERBOSE, "Start %p...\n", this);
125
126     if(!initValues()) {
127         debugFatal("(%p) Could not init values\n", this);
128         return false;
129     }
130
131     m_Thread = new Util::PosixThread(this, m_realtime, m_priority,
132                                      PTHREAD_CANCEL_DEFERRED);
133     if(!m_Thread) {
134         debugFatal("No thread\n");
135         return false;
136     }
137     if (m_Thread->Start() != 0) {
138         debugFatal("Could not start update thread\n");
139         return false;
140     }
141     return true;
142 }
143
144 bool
145 CycleTimerHelper::initValues()
146 {
147     debugOutput( DEBUG_LEVEL_VERBOSE, "Init values...\n" );
148     pthread_mutex_lock(&mb_update_lock);
149     // initialize the 'prev ctr' values
150     uint64_t local_time;
151     int maxtries2 = 10;
152     do {
153         debugOutput( DEBUG_LEVEL_VERBOSE, "Read CTR...\n" );
154         if(!m_Parent.readCycleTimerReg(&m_cycle_timer_prev, &local_time)) {
155             debugError("Could not read cycle timer register\n");
156             pthread_mutex_unlock(&mb_update_lock);
157             return false;
158         }
159         if (m_cycle_timer_prev == 0) {
160             debugOutput(DEBUG_LEVEL_VERBOSE,
161                         "Bogus CTR: %08X on try %02d\n",
162                         m_cycle_timer_prev, maxtries2);
163         }
164         debugOutput( DEBUG_LEVEL_VERBOSE, " read : CTR: %11lu, local: %17llu\n",
165                             m_cycle_timer_prev, local_time);
166         debugOutput(DEBUG_LEVEL_VERBOSE,
167                            "  ctr   : 0x%08X %11llu (%03us %04ucy %04uticks)\n",
168                            (uint32_t)m_cycle_timer_prev, (uint64_t)CYCLE_TIMER_TO_TICKS(m_cycle_timer_prev),
169                            (unsigned int)CYCLE_TIMER_GET_SECS( m_cycle_timer_prev ),
170                            (unsigned int)CYCLE_TIMER_GET_CYCLES( m_cycle_timer_prev ),
171                            (unsigned int)CYCLE_TIMER_GET_OFFSET( m_cycle_timer_prev ) );
172        
173     } while (m_cycle_timer_prev == 0 && maxtries2--);
174     m_cycle_timer_ticks_prev = CYCLE_TIMER_TO_TICKS(m_cycle_timer_prev);
175
176 #if IEEE1394SERVICE_USE_CYCLETIMER_DLL
177     debugOutput( DEBUG_LEVEL_VERBOSE, "requesting DLL re-init...\n" );
178     m_TimeSource.SleepUsecRelative(1000); // some time to settle
179     m_high_bw_updates = UPDATES_WITH_HIGH_BANDWIDTH;
180     if(!initDLL()) {
181         debugError("(%p) Could not init DLL\n", this);
182         pthread_mutex_unlock(&mb_update_lock);
183         return false;
184     }
185     // make the DLL re-init itself as if it were started up
186     m_first_run = true;
187 #endif
188     pthread_mutex_unlock(&mb_update_lock);
189     debugOutput( DEBUG_LEVEL_VERBOSE, "ready...\n" );
190     return true;
191 }
192
193 bool
194 CycleTimerHelper::Init()
195 {
196     debugOutput( DEBUG_LEVEL_VERBOSE, "Initialize %p...\n", this);
197
198     // register a bus reset handler
199     Util::Functor* m_busreset_functor = new Util::MemberFunctor0< CycleTimerHelper*,
200                 void (CycleTimerHelper::*)() >
201                 ( this, &CycleTimerHelper::busresetHandler, false );
202     if ( !m_busreset_functor ) {
203         debugFatal( "(%p) Could not create busreset handler\n", this );
204         return false;
205     }
206     m_Parent.addBusResetHandler( m_busreset_functor );
207
208     return true;
209 }
210
211 void
212 CycleTimerHelper::busresetHandler()
213 {
214     debugOutput( DEBUG_LEVEL_VERBOSE, "Bus reset...\n" );
215     m_unhandled_busreset = true;
216     // whenever a bus reset occurs, the root node can change,
217     // and the CTR timer can be reset. We should hence reinit
218     // the DLL
219     if(!initValues()) {
220         debugError("(%p) Could not re-init values\n", this);
221     }
222     m_unhandled_busreset = false;
223 }
224
225 bool
226 CycleTimerHelper::setThreadParameters(bool rt, int priority) {
227     debugOutput( DEBUG_LEVEL_VERBOSE, "(%p) switch to: (rt=%d, prio=%d)...\n", this, rt, priority);
228     if (priority > THREAD_MAX_RTPRIO) priority = THREAD_MAX_RTPRIO; // cap the priority
229     m_realtime = rt;
230     m_priority = priority;
231
232 #if IEEE1394SERVICE_USE_CYCLETIMER_DLL
233     if (m_Thread) {
234         if (m_realtime) {
235             m_Thread->AcquireRealTime(m_priority);
236         } else {
237             m_Thread->DropRealTime();
238         }
239     }
240 #endif
241
242     return true;
243 }
244
245 #if IEEE1394SERVICE_USE_CYCLETIMER_DLL
246 float
247 CycleTimerHelper::getRate()
248 {
249     float rate = (float)(diffTicks((uint64_t)m_next_time_ticks, (uint64_t)m_current_time_ticks));
250     rate /= (float)(m_next_time_usecs - m_current_time_usecs);
251     return rate;
252 }
253
254 float
255 CycleTimerHelper::getNominalRate()
256 {
257     float rate = ((double)TICKS_PER_SECOND) / 1000000.0;
258     return rate;
259 }
260
261 bool
262 CycleTimerHelper::initDLL() {
263     uint32_t cycle_timer;
264     uint64_t local_time;
265     uint64_t cycle_timer_ticks;
266
267     if(!readCycleTimerWithRetry(&cycle_timer, &local_time, 10)) {
268         debugError("Could not read cycle timer register\n");
269         pthread_mutex_unlock(&mb_update_lock);
270         return false;
271     }
272     cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer);
273
274     debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, " read : CTR: %11lu, local: %17llu\n",
275                         cycle_timer, local_time);
276     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
277                        "  ctr   : 0x%08X %11llu (%03us %04ucy %04uticks)\n",
278                        (uint32_t)cycle_timer, (uint64_t)cycle_timer_ticks,
279                        (unsigned int)TICKS_TO_SECS( (uint64_t)cycle_timer_ticks ),
280                        (unsigned int)TICKS_TO_CYCLES( (uint64_t)cycle_timer_ticks ),
281                        (unsigned int)TICKS_TO_OFFSET( (uint64_t)cycle_timer_ticks ) );
282
283     m_sleep_until = local_time + m_usecs_per_update;
284     m_dll_e2 = m_ticks_per_update;
285     m_current_time_usecs = local_time;
286     m_next_time_usecs = m_current_time_usecs + m_usecs_per_update;
287     m_current_time_ticks = CYCLE_TIMER_TO_TICKS( cycle_timer );
288     m_next_time_ticks = addTicks( (uint64_t)m_current_time_ticks, (uint64_t)m_dll_e2);
289     debugOutput(DEBUG_LEVEL_VERBOSE, " First run\n");
290     debugOutput(DEBUG_LEVEL_VERBOSE,
291                 "  usecs/update: %lu, ticks/update: %lu, m_dll_e2: %f\n",
292                 m_usecs_per_update, m_ticks_per_update, m_dll_e2);
293     debugOutput(DEBUG_LEVEL_VERBOSE,
294                 "  usecs current: %f, next: %f\n",
295                 m_current_time_usecs, m_next_time_usecs);
296     debugOutput(DEBUG_LEVEL_VERBOSE,
297                 "  ticks current: %f, next: %f\n",
298                 m_current_time_ticks, m_next_time_ticks);
299     return true;
300 }
301
302 bool
303 CycleTimerHelper::Execute()
304 {
305     debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, "Execute %p...\n", this);
306
307     if (!m_first_run) {
308         // wait for the next update period
309         #if DEBUG_EXTREME_ENABLE
310         ffado_microsecs_t now = m_TimeSource.getCurrentTimeAsUsecs();
311         int sleep_time = m_sleep_until - now;
312         debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, "(%p) Sleep until %lld/%f (now: %lld, diff=%d) ...\n",
313                     this, m_sleep_until, m_next_time_usecs, now, sleep_time);
314         #endif
315         m_TimeSource.SleepUsecAbsolute(m_sleep_until);
316         debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, " (%p) back...\n", this);
317     }
318
319     // grab the lock after sleeping, otherwise we can't be interrupted by
320     // the busreset thread (lower prio)
321     pthread_mutex_lock(&mb_update_lock);
322
323     uint32_t cycle_timer;
324     uint64_t local_time;
325     int64_t usecs_late;
326     int ntries=2;
327     uint64_t cycle_timer_ticks;
328     double diff_ticks;
329
330     // if the difference between the predicted value and the
331     // actual value seems to be too large, retry reading the cycle timer
332     // some host controllers return bogus values on some reads
333     // (looks like a non-atomic update of the register)
334     do {
335         if(!readCycleTimerWithRetry(&cycle_timer, &local_time, 10)) {
336             debugError("Could not read cycle timer register\n");
337             pthread_mutex_unlock(&mb_update_lock);
338             return false;
339         }
340         usecs_late = local_time - m_sleep_until;
341         cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(cycle_timer);
342         diff_ticks = diffTicks(cycle_timer_ticks, (int64_t)m_next_time_ticks);
343
344         // check for unrealistic CTR reads (NEC controller does that sometimes)
345         if(diff_ticks < -((double)TICKS_PER_HALFCYCLE)) {
346             debugOutput(DEBUG_LEVEL_VERBOSE,
347                         "have to retry CTR read, diff unrealistic: diff: %f, max: %f\n",
348                         diff_ticks, -((double)TICKS_PER_HALFCYCLE));
349         }
350
351     } while( diff_ticks < -((double)TICKS_PER_HALFCYCLE)
352              && --ntries && !m_first_run && !m_unhandled_busreset);
353
354     if(m_unhandled_busreset) {
355         debugOutput(DEBUG_LEVEL_VERBOSE,
356                     "(%p) Skipping DLL update due to unhandled busreset\n", this);
357         m_sleep_until += m_usecs_per_update;
358         pthread_mutex_unlock(&mb_update_lock);
359         // keep the thread running
360         return true;
361     }
362
363     debugOutputExtreme( DEBUG_LEVEL_VERY_VERBOSE, " read : CTR: %11lu, local: %17llu\n",
364                         cycle_timer, local_time);
365     debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
366                        "  ctr   : 0x%08X %11llu (%03us %04ucy %04uticks)\n",
367                        (uint32_t)cycle_timer, (uint64_t)cycle_timer_ticks,
368                        (unsigned int)TICKS_TO_SECS( (uint64_t)cycle_timer_ticks ),
369                        (unsigned int)TICKS_TO_CYCLES( (uint64_t)cycle_timer_ticks ),
370                        (unsigned int)TICKS_TO_OFFSET( (uint64_t)cycle_timer_ticks ) );
371
372     if (m_first_run) {
373         if(!initDLL()) {
374             debugError("(%p) Could not init DLL\n", this);
375             pthread_mutex_unlock(&mb_update_lock);
376             return false;
377         }
378         m_first_run = false;
379     } else {
380         // calculate next sleep time
381         m_sleep_until += m_usecs_per_update;
382
383         // correct for the latency between the wakeup and the actual CTR
384         // read. The only time we can trust is the time returned by the
385         // CTR read kernel call, since that (should be) atomically read
386         // together with the ctr register itself.
387
388         // if we are usecs_late usecs late
389         // the cycle timer has ticked approx ticks_late ticks too much
390         // if we are woken up early (which shouldn't happen according to POSIX)
391         // the cycle timer has ticked approx -ticks_late too little
392         int64_t ticks_late = (usecs_late * TICKS_PER_SECOND) / 1000000LL;
393         // the corrected difference between predicted and actual ctr
394         // i.e. DLL error signal
395         double diff_ticks_corr;
396         if (ticks_late > 0) {
397             diff_ticks_corr = diff_ticks - ticks_late;
398             debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
399                                "diff_ticks_corr=%f, diff_ticks = %f, ticks_late = %lld\n",
400                                diff_ticks_corr, diff_ticks, ticks_late);
401         } else {
402             debugError("Early wakeup, should not happen!\n");
403             // recover
404             diff_ticks_corr = diff_ticks + ticks_late;
405         }
406
407         #ifdef DEBUG
408         // makes no sense if not running realtime
409         if(m_realtime && usecs_late > 200) {
410             debugOutput(DEBUG_LEVEL_VERBOSE, "Rather late wakeup: %lld usecs\n", usecs_late);
411         }
412         #endif
413
414         // update the x-axis values
415         m_current_time_ticks = m_next_time_ticks;
416
417         // decide what coefficients to use
418         double coeff_b, coeff_c;
419         if (m_high_bw_updates > 0) {
420             coeff_b = DLL_COEFF_B_HIGH;
421             coeff_c = DLL_COEFF_C_HIGH;
422             m_high_bw_updates--;
423             if (m_high_bw_updates == 0) {
424                 debugOutput(DEBUG_LEVEL_VERBOSE,
425                             "Switching to low-bandwidth coefficients\n");
426             }
427         } else {
428             coeff_b = DLL_COEFF_B;
429             coeff_c = DLL_COEFF_C;
430         }
431
432         // it should be ok to not do this in tick space
433         // since diff_ticks_corr should not be near wrapping
434         // (otherwise we are out of range. we need a few calls
435         //  w/o wrapping for this to work. That should not be
436         //  an issue as long as the update interval is smaller
437         //  than the wrapping interval.)
438         // and coeff_b < 1, hence tmp is not near wrapping
439
440         double step_ticks = (coeff_b * diff_ticks_corr);
441         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
442                            "diff_ticks_corr=%f, step_ticks=%f\n",
443                            diff_ticks_corr, step_ticks);
444
445         // the same goes for m_dll_e2, which should be approx equal
446         // to the ticks/usec rate (= 24.576) hence also not near
447         // wrapping
448         step_ticks += m_dll_e2;
449         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
450                            "add %f ticks to step_ticks => step_ticks=%f\n",
451                            m_dll_e2, step_ticks);
452
453         // it can't be that we have to update to a value in the past
454         if(step_ticks < 0) {
455             debugError("negative step: %f! (correcting to nominal)\n", step_ticks);
456             // recover to an estimated value
457             step_ticks = (double)m_ticks_per_update;
458         }
459
460         if(step_ticks > TICKS_PER_SECOND) {
461             debugWarning("rather large step: %f ticks (> 1sec)\n", step_ticks);
462         }
463
464         // now add the step ticks with wrapping.
465         m_next_time_ticks = (double)(addTicks((uint64_t)m_current_time_ticks, (uint64_t)step_ticks));
466
467         // update the DLL state
468         m_dll_e2 += coeff_c * diff_ticks_corr;
469
470         // update the y-axis values
471         m_current_time_usecs = m_next_time_usecs;
472         m_next_time_usecs += m_usecs_per_update;
473
474         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
475                            " usecs: current: %f next: %f usecs_late=%lld ticks_late=%lld\n",
476                            m_current_time_usecs, m_next_time_usecs, usecs_late, ticks_late);
477         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
478                            " ticks: current: %f next: %f diff=%f\n",
479                            m_current_time_ticks, m_next_time_ticks, diff_ticks);
480         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
481                            " ticks: current: %011llu (%03us %04ucy %04uticks)\n",
482                            (uint64_t)m_current_time_ticks,
483                            (unsigned int)TICKS_TO_SECS( (uint64_t)m_current_time_ticks ),
484                            (unsigned int)TICKS_TO_CYCLES( (uint64_t)m_current_time_ticks ),
485                            (unsigned int)TICKS_TO_OFFSET( (uint64_t)m_current_time_ticks ) );
486         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
487                            " ticks: next   : %011llu (%03us %04ucy %04uticks)\n",
488                            (uint64_t)m_next_time_ticks,
489                            (unsigned int)TICKS_TO_SECS( (uint64_t)m_next_time_ticks ),
490                            (unsigned int)TICKS_TO_CYCLES( (uint64_t)m_next_time_ticks ),
491                            (unsigned int)TICKS_TO_OFFSET( (uint64_t)m_next_time_ticks ) );
492
493         debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE,
494                            " state: local: %11llu, dll_e2: %f, rate: %f\n",
495                            local_time, m_dll_e2, getRate());
496     }
497
498     // prepare the new compute vars
499     struct compute_vars new_vars;
500     new_vars.ticks = (uint64_t)(m_current_time_ticks);
501     new_vars.usecs = (uint64_t)m_current_time_usecs;
502     new_vars.rate = getRate();
503
504     // get the next index
505     unsigned int next_idx = (m_current_shadow_idx + 1) % CTRHELPER_NB_SHADOW_VARS;
506
507     // update the next index position
508     m_shadow_vars[next_idx] = new_vars;
509
510     // then we can update the current index
511     m_current_shadow_idx = next_idx;
512
513     pthread_mutex_unlock(&mb_update_lock);
514     return true;
515 }
516
517 uint32_t
518 CycleTimerHelper::getCycleTimerTicks()
519 {
520     uint64_t now = m_Parent.getCurrentTimeAsUsecs();
521     return getCycleTimerTicks(now);
522 }
523
524 uint32_t
525 CycleTimerHelper::getCycleTimerTicks(uint64_t now)
526 {
527     uint32_t retval;
528     struct compute_vars my_vars;
529
530     // get pointer and copy the contents
531     // no locking should be needed since we have more than one
532     // of these vars available, and the copy will always be finished before
533     // m_current_shadow_idx changes since this thread's priority should
534     // be higher than the one of the writer thread. Even if not, we only have to ensure
535     // that the used dataset is consistent. We can use an older dataset if it's consistent
536     // since it will also provide a fairly decent extrapolation.
537     unsigned int curr_idx = m_current_shadow_idx; // NOTE: this needs ordering
538     my_vars = m_shadow_vars[curr_idx];
539
540     int64_t time_diff = now - my_vars.usecs;
541     double y_step_in_ticks = ((double)time_diff) * my_vars.rate;
542     int64_t y_step_in_ticks_int = (int64_t)y_step_in_ticks;
543     uint64_t offset_in_ticks_int = my_vars.ticks;
544
545     if (y_step_in_ticks_int > 0) {
546         retval = addTicks(offset_in_ticks_int, y_step_in_ticks_int);
547 /*        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "y_step_in_ticks_int > 0: %lld, time_diff: %f, rate: %f, retval: %lu\n",
548                     y_step_in_ticks_int, time_diff, my_vars.rate, retval);*/
549     } else {
550         retval = substractTicks(offset_in_ticks_int, -y_step_in_ticks_int);
551
552         // this can happen if the update thread was woken up earlier than it should have been
553 /*        debugOutputExtreme(DEBUG_LEVEL_VERY_VERBOSE, "y_step_in_ticks_int <= 0: %lld, time_diff: %f, rate: %f, retval: %lu\n",
554                     y_step_in_ticks_int, time_diff, my_vars.rate, retval);*/
555     }
556
557     return retval;
558 }
559
560 uint32_t
561 CycleTimerHelper::getCycleTimer()
562 {
563     uint64_t now = m_Parent.getCurrentTimeAsUsecs();
564     return getCycleTimer(now);
565 }
566
567 uint32_t
568 CycleTimerHelper::getCycleTimer(uint64_t now)
569 {
570     uint32_t ticks = getCycleTimerTicks(now);
571     uint32_t result = TICKS_TO_CYCLE_TIMER(ticks);
572 #ifdef DEBUG
573     if(CYCLE_TIMER_TO_TICKS(result) != ticks) {
574         debugWarning("Bad ctr conversion");
575     }
576 #endif
577     return result;
578 }
579
580 #else
581
582 float
583 CycleTimerHelper::getRate()
584 {
585     return getNominalRate();
586 }
587
588 float
589 CycleTimerHelper::getNominalRate()
590 {
591     float rate = ((double)TICKS_PER_SECOND) / 1000000.0;
592     return rate;
593 }
594
595 bool
596 CycleTimerHelper::Execute()
597 {
598     usleep(1000*1000);
599     return true;
600 }
601
602 uint32_t
603 CycleTimerHelper::getCycleTimerTicks()
604 {
605     return CYCLE_TIMER_TO_TICKS(getCycleTimer());
606 }
607
608 uint32_t
609 CycleTimerHelper::getCycleTimerTicks(uint64_t now)
610 {
611     debugWarning("not implemented!\n");
612     return getCycleTimerTicks();
613 }
614
615 uint32_t
616 CycleTimerHelper::getCycleTimer()
617 {
618     uint32_t cycle_timer;
619     uint64_t local_time;
620     readCycleTimerWithRetry(&cycle_timer, &local_time, 10);
621     return cycle_timer;
622 }
623
624 uint32_t
625 CycleTimerHelper::getCycleTimer(uint64_t now)
626 {
627     debugWarning("not implemented!\n");
628     return getCycleTimer();
629 }
630
631 #endif
632
633 bool
634 CycleTimerHelper::readCycleTimerWithRetry(uint32_t *cycle_timer, uint64_t *local_time, int ntries)
635 {
636     bool good=false;
637     int maxtries = ntries;
638
639     do {
640         // the ctr read can return 0 sometimes. if that happens, reread the ctr.
641         int maxtries2=ntries;
642         do {
643             if(!m_Parent.readCycleTimerReg(cycle_timer, local_time)) {
644                 debugError("Could not read cycle timer register\n");
645                 return false;
646             }
647             if (*cycle_timer == 0) {
648                 debugOutput(DEBUG_LEVEL_VERBOSE,
649                            "Bogus CTR: %08X on try %02d\n",
650                            *cycle_timer, maxtries2);
651             }
652         } while (*cycle_timer == 0 && maxtries2--);
653        
654         // catch bogus ctr reads (can happen)
655         uint64_t cycle_timer_ticks = CYCLE_TIMER_TO_TICKS(*cycle_timer);
656    
657         if (diffTicks(cycle_timer_ticks, m_cycle_timer_ticks_prev) < 0) {
658             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
659                         "non-monotonic CTR (try %02d): %llu -> %llu\n",
660                         maxtries, m_cycle_timer_ticks_prev, cycle_timer_ticks);
661             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
662                         "                            : %08X -> %08X\n",
663                         m_cycle_timer_prev, *cycle_timer);
664             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
665                         " current: %011llu (%03us %04ucy %04uticks)\n",
666                         cycle_timer_ticks,
667                         (unsigned int)TICKS_TO_SECS( cycle_timer_ticks ),
668                         (unsigned int)TICKS_TO_CYCLES( cycle_timer_ticks ),
669                         (unsigned int)TICKS_TO_OFFSET( cycle_timer_ticks ) );
670             debugOutput( DEBUG_LEVEL_VERY_VERBOSE,
671                         " prev   : %011llu (%03us %04ucy %04uticks)\n",
672                         m_cycle_timer_ticks_prev,
673                         (unsigned int)TICKS_TO_SECS( m_cycle_timer_ticks_prev ),
674                         (unsigned int)TICKS_TO_CYCLES( m_cycle_timer_ticks_prev ),
675                         (unsigned int)TICKS_TO_OFFSET( m_cycle_timer_ticks_prev ) );
676         } else {
677             good = true;
678             m_cycle_timer_prev = *cycle_timer;
679             m_cycle_timer_ticks_prev = cycle_timer_ticks;
680         }
681     } while (!good && maxtries--);
682     return true;
683 }
684
685 void
686 CycleTimerHelper::setVerboseLevel(int l)
687 {
688     setDebugLevel(l);
689 }
Note: See TracBrowser for help on using the browser.