1
1

Improved support for OSX timers.

Этот коммит содержится в:
George Bosilca 2014-11-24 17:15:49 -05:00
родитель b7fa0e312f
Коммит 261684858f
2 изменённых файлов: 57 добавлений и 46 удалений

Просмотреть файл

@ -27,17 +27,29 @@ typedef uint64_t opal_timer_t;
/* frequency in mhz */
OPAL_DECLSPEC extern opal_timer_t opal_timer_darwin_freq;
OPAL_DECLSPEC extern mach_timebase_info_data_t opal_timer_darwin_info;
OPAL_DECLSPEC extern opal_timer_t opal_timer_darwin_bias;
/**
* Use the pragmatic solution proposed at
* http://stackoverflow.com/questions/23378063/how-can-i-use-mach-absolute-time-without-overflowing/23378064#23378064
*/
static inline opal_timer_t
opal_timer_base_get_cycles(void)
{
uint64_t now = mach_absolute_time();
if( opal_timer_darwin_info.denom == 0 ) {
(void) mach_timebase_info(&opal_timer_darwin_info);
(void)mach_timebase_info(&opal_timer_darwin_info);
if( opal_timer_darwin_info.denom > 1024 ) {
double frac = (double)opal_timer_darwin_info.numer/opal_timer_darwin_info.denom;
opal_timer_darwin_info.denom = 1024;
opal_timer_darwin_info.numer = opal_timer_darwin_info.denom * frac + 0.5;
}
opal_timer_darwin_bias = now;
}
/* this is basically a wrapper around the "right" assembly to get
the tick counter off the PowerPC Time Base. I believe it's
something similar on x86 */
return mach_absolute_time() * opal_timer_darwin_info.numer / opal_timer_darwin_info.denom / 1000;
/* this is basically a wrapper around the "right" assembly to convert
the tick counter off the PowerPC Time Base into nanos. */
return (now - opal_timer_darwin_bias) * opal_timer_darwin_info.numer / opal_timer_darwin_info.denom;
}
@ -45,7 +57,7 @@ static inline opal_timer_t
opal_timer_base_get_usec(void)
{
/* freq is in Hz, so this gives usec */
return mach_absolute_time() * 1000000 / opal_timer_darwin_freq;
return opal_timer_base_get_cycles() / 1000;
}

Просмотреть файл

@ -26,6 +26,7 @@
opal_timer_t opal_timer_darwin_freq;
mach_timebase_info_data_t opal_timer_darwin_info = {.denom = 0};
opal_timer_t opal_timer_darwin_bias;
static int opal_timer_darwin_open(void);
@ -51,50 +52,48 @@ const opal_timer_base_component_2_0_0_t mca_timer_darwin_component = {
},
};
/* mach_timebase_info() returns a fraction that can be multiplied
by the difference between two calls to mach_absolute_time() to
get the number of nanoseconds that passed between the two
calls.
On PPC, mach_timebase_info returns numer = 1000000000 and denom
= 33333335 (or possibly 25000000, depending on the machine).
mach_absolute_time() returns a cycle count from the global
clock, which runs at 25 - 33MHz, so dividing the cycle count by
the frequency gives you seconds between the interval, then
multiplying by 1000000000 gives you nanoseconds. Of course,
you should do the multiply first, then the divide to reduce
arithmetic errors due to integer math. But since we want the
least amount of math in the critical path as possible and
mach_absolute_time is already a cycle counter, we claim we have
native cycle count support and set the frequencey to be the
frequencey of the global clock, which is sTBI.denom *
(1000000000 / sTBI.numer), which is sTBI.denom * (1 / 1), or
sTBI.denom.
On Intel, mach_timebase_info returns numer = 1 nd denom = 1,
meaning that mach_absolute_time() returns some global clock
time in nanoseconds. Because PPC returns a frequency and
returning a time in microseconds would still require math in
the critical path (a divide, at that), we pretend that the
nanosecond timer is instead a cycle counter for a 1GHz clock
and that we're returning a cycle count natively. so sTBI.denom
* (1000000000 / sTBI.numer) gives us 1 * (1000000000 / 1), or
1000000000, meaning we have a 1GHz clock.
More generally, since mach_timebase_info() gives the "keys" to
transition the return from mach_absolute_time() into
nanoseconds, taking the reverse of that and multipling by
1000000000 will give you a frequency in cycles / second if you
think of mach_absolute_time() always returning a cycle count.
*/
int opal_timer_darwin_open(void)
{
mach_timebase_info_data_t sTBI;
/* Call the opal_timer_base_get_cycles once to start the enging */
(void)opal_timer_base_get_cycles();
mach_timebase_info(&sTBI);
/* mach_timebase_info() returns a fraction that can be multiplied
by the difference between two calls to mach_absolute_time() to
get the number of nanoseconds that passed between the two
calls.
On PPC, mach_timebase_info returns numer = 1000000000 and denom
= 33333335 (or possibly 25000000, depending on the machine).
mach_absolute_time() returns a cycle count from the global
clock, which runs at 25 - 33MHz, so dividing the cycle count by
the frequency gives you seconds between the interval, then
multiplying by 1000000000 gives you nanoseconds. Of course,
you should do the multiply first, then the divide to reduce
arithmetic errors due to integer math. But since we want the
least amount of math in the critical path as possible and
mach_absolute_time is already a cycle counter, we claim we have
native cycle count support and set the frequencey to be the
frequencey of the global clock, which is sTBI.denom *
(1000000000 / sTBI.numer), which is sTBI.denom * (1 / 1), or
sTBI.denom.
On Intel, mach_timebase_info returns numer = 1 nd denom = 1,
meaning that mach_absolute_time() returns some global clock
time in nanoseconds. Because PPC returns a frequency and
returning a time in microseconds would still require math in
the critical path (a divide, at that), we pretend that the
nanosecond timer is instead a cycle counter for a 1GHz clock
and that we're returning a cycle count natively. so sTBI.denom
* (1000000000 / sTBI.numer) gives us 1 * (1000000000 / 1), or
1000000000, meaning we have a 1GHz clock.
More generally, since mach_timebase_info() gives the "keys" to
transition the return from mach_absolute_time() into
nanoseconds, taking the reverse of that and multipling by
1000000000 will give you a frequency in cycles / second if you
think of mach_absolute_time() always returning a cycle count.
*/
opal_timer_darwin_freq = sTBI.denom * (1000000000 / sTBI.numer);
opal_timer_darwin_freq = opal_timer_darwin_info.denom * (1000000000 / opal_timer_darwin_info.numer);
return OPAL_SUCCESS;
}