Skip to content

Commit

Permalink
Merge pull request #285 from bosilca/master
Browse files Browse the repository at this point in the history
Reenable high accuracy timers
  • Loading branch information
bosilca committed Nov 25, 2014
2 parents f48b901 + 43901fa commit 8cae899
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 90 deletions.
4 changes: 3 additions & 1 deletion ompi/mpi/c/wtick.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ double MPI_Wtick(void)
{
OPAL_CR_NOOP_PROGRESS();

#if OPAL_TIMER_USEC_NATIVE
#if OPAL_TIMER_CYCLE_NATIVE
return opal_timer_base_get_freq();
#elif OPAL_TIMER_USEC_NATIVE
return 0.000001;
#else
/* Otherwise, we already return usec precision. */
Expand Down
4 changes: 3 additions & 1 deletion ompi/mpi/c/wtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ double MPI_Wtime(void)
{
double wtime;

#if OPAL_TIMER_USEC_NATIVE
#if OPAL_TIMER_CYCLE_NATIVE
wtime = ((double) opal_timer_base_get_cycles()) / opal_timer_base_get_freq();
#elif OPAL_TIMER_USEC_NATIVE
wtime = ((double) opal_timer_base_get_usec()) / 1000000.0;
#else
/* Fall back to gettimeofday() if we have nothing else */
Expand Down
39 changes: 22 additions & 17 deletions opal/include/opal/sys/amd64/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand All @@ -25,29 +25,34 @@ typedef uint64_t opal_timer_t;

#if OPAL_GCC_INLINE_ASSEMBLY

#if 0
/**
* http://www.intel.com/content/www/us/en/intelligent-systems/embedded-systems-training/ia-32-ia-64-benchmark-code-execution-paper.html
*/
static inline opal_timer_t
opal_sys_timer_get_cycles(void)
{
opal_timer_t ret;

__asm__ __volatile__("rdtsc" : "=A"(ret));

return ret;
}

unsigned a, d;
#if 0
__asm__ __volatile__ ("cpuid\n\t"
"rdtsc\n\t"
: "=a" (a), "=d" (d)
:: "rbx", "rcx");
#else

static inline opal_timer_t
opal_sys_timer_get_cycles(void)
{
unsigned a, d;
__asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d));
/* If we need higher accuracy we should implement the algorithm proposed
* on the Intel document referenced above. However, in the context of MPI
* this function will be used as the backend for MPI_Wtime and as such
* can afford a small inaccuracy.
*/
__asm__ __volatile__ ("rdtscp\n\t"
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t"
"cpuid\n\t"
: "=r" (a), "=r" (d)
:: "rax", "rbx", "rcx", "rdx");
#endif
return ((opal_timer_t)a) | (((opal_timer_t)d) << 32);
}

#endif

#define OPAL_HAVE_SYS_TIMER_GET_CYCLES 1

#else
Expand Down
7 changes: 5 additions & 2 deletions opal/include/opal/sys/ia32/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand Down Expand Up @@ -30,7 +30,10 @@ opal_sys_timer_get_cycles(void)
{
opal_timer_t ret;

__asm__ __volatile__("rdtsc" : "=A"(ret));
__asm__ __volatile__("cpuid\n"
"rdtsc\n"
: "=A"(ret)
:: "ebx", "ecx", "edx");

return ret;
}
Expand Down
4 changes: 2 additions & 2 deletions opal/mca/timer/aix/timer_aix.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2006 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand Down Expand Up @@ -39,7 +39,7 @@ opal_timer_base_get_usec()
retval = (t.tb_high * 1000000) + t.tb_low / 1000;

return retval;
}
}

static inline opal_timer_t
opal_timer_base_get_cycles()
Expand Down
4 changes: 2 additions & 2 deletions opal/mca/timer/altix/timer_altix.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand Down Expand Up @@ -36,7 +36,7 @@ static inline opal_timer_t
opal_timer_base_get_usec(void)
{
return opal_timer_base_get_cycles() / opal_timer_altix_usec_conv;
}
}


static inline opal_timer_t
Expand Down
35 changes: 25 additions & 10 deletions opal/mca/timer/darwin/timer_darwin.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand All @@ -26,24 +26,39 @@ 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)
{
/* 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();
uint64_t now = mach_absolute_time();

if( opal_timer_darwin_info.denom == 0 ) {
(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 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;
}


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;
}


static inline opal_timer_t
Expand All @@ -53,9 +68,9 @@ opal_timer_base_get_freq(void)
}


#define OPAL_TIMER_CYCLE_NATIVE 1
#define OPAL_TIMER_CYCLE_NATIVE 0
#define OPAL_TIMER_CYCLE_SUPPORTED 1
#define OPAL_TIMER_USEC_NATIVE 0
#define OPAL_TIMER_USEC_NATIVE 1
#define OPAL_TIMER_USEC_SUPPORTED 1

#endif
92 changes: 42 additions & 50 deletions opal/mca/timer/darwin/timer_darwin_component.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand All @@ -20,17 +20,16 @@

#include "opal_config.h"

#include <mach/mach_time.h>

#include "opal/mca/timer/timer.h"
#include "opal/mca/timer/darwin/timer_darwin.h"
#include "opal/constants.h"

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);


const opal_timer_base_component_2_0_0_t mca_timer_darwin_component = {
/* First, the mca_component_t struct containing meta information
about the component itself */
Expand All @@ -53,55 +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;

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.
/* Call the opal_timer_base_get_cycles once to start the enging */
(void)opal_timer_base_get_cycles();

By the way, it's interesting to note that because these are
library functions and because of how rosetta works, a PPC
binary running under rosetta on an Intel Mac will behave
exactly like an Intel binary running on an Intel Mac.
*/
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;
}
6 changes: 3 additions & 3 deletions opal/mca/timer/linux/timer_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand Down Expand Up @@ -44,7 +44,7 @@ opal_timer_base_get_usec(void)
#else
return 0;
#endif
}
}


static inline opal_timer_t
Expand All @@ -56,7 +56,7 @@ opal_timer_base_get_freq(void)

#define OPAL_TIMER_CYCLE_NATIVE OPAL_HAVE_SYS_TIMER_GET_CYCLES
#define OPAL_TIMER_CYCLE_SUPPORTED OPAL_HAVE_SYS_TIMER_GET_CYCLES
#define OPAL_TIMER_USEC_NATIVE 0
#define OPAL_TIMER_USEC_NATIVE OPAL_HAVE_SYS_TIMER_GET_CYCLES
#define OPAL_TIMER_USEC_SUPPORTED OPAL_HAVE_SYS_TIMER_GET_CYCLES

#endif
4 changes: 2 additions & 2 deletions opal/mca/timer/solaris/timer_solaris.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2005 The University of Tennessee and The University
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
Expand Down Expand Up @@ -35,7 +35,7 @@ opal_timer_base_get_usec(void)
{
/* gethrtime returns nanoseconds */
return gethrtime() / 1000;
}
}

static inline opal_timer_t
opal_timer_base_get_freq(void)
Expand Down

8 comments on commit 8cae899

@elenash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bosilca it looks like this commit is causing "ILLEGAL INSTRUCTION" failure at start.

@rhc54
Copy link
Contributor

@rhc54 rhc54 commented on 8cae899 Nov 26, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW: it seems to be working okay on my cluster (x86, CentOS7).

@elenash can you provide further info on the environment and failure?

@elenash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rhc54 @bosilca Linux version 2.6.32-358.23.2.el6.x86_64
no output at all at start, just Illegal instruction (core dumped)

@bosilca
Copy link
Member Author

@bosilca bosilca commented on 8cae899 Nov 26, 2014 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elenash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bosilca
gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC)
It looks you're right, see the stack trace:

Program received signal SIGILL, Illegal instruction.
opal_sys_timer_get_cycles () at ../../opal/include/opal/sys/amd64/timer.h:46
46 asm volatile ("rdtscp\n\t"
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.107.el6.x86_64 libpciaccess-0.13.1-2.el6.x86_64 numactl-2.0.7-6.el6.x86_64
(gdb) bt
#0 opal_sys_timer_get_cycles () at ../../opal/include/opal/sys/amd64/timer.h:46
#1 0x00007ffff7a0cd93 in opal_timer_base_get_usec () at ../../opal/mca/timer/linux/timer_linux.h:43
#2 0x00007ffff7a0d12c in opal_progress_set_event_poll_rate (polltime=10000) at ../../opal/runtime/opal_progress.c:271
#3 0x00007ffff7a0cddd in opal_progress_init () at ../../opal/runtime/opal_progress.c:98
#4 0x00007ffff7a0ddd1 in opal_init (pargc=0x7fffffffde1c, pargv=0x7fffffffde10) at ../../opal/runtime/opal_init.c:461
#5 0x00000000004044f5 in orterun (argc=12, argv=0x7fffffffe1f8) at ../../../../orte/tools/orterun/orterun.c:687
#6 0x0000000000403a74 in main (argc=12, argv=0x7fffffffe1f8) at ../../../../orte/tools/orterun/main.c:13

@elenash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bosilca
Dump of assembler code for function opal_sys_timer_get_cycles:
0x00007ffff7a0cd62 <+0>: push %rbp
0x00007ffff7a0cd63 <+1>: mov %rsp,%rbp
0x00007ffff7a0cd66 <+4>: push %rbx
=> 0x00007ffff7a0cd67 <+5>: rdtscp
0x00007ffff7a0cd6a <+8>: mov %edx,%edi
0x00007ffff7a0cd6c <+10>: mov %eax,%esi
0x00007ffff7a0cd6e <+12>: cpuid
0x00007ffff7a0cd70 <+14>: mov %edi,-0x10(%rbp)
0x00007ffff7a0cd73 <+17>: mov %esi,-0xc(%rbp)
0x00007ffff7a0cd76 <+20>: mov -0x10(%rbp),%eax
0x00007ffff7a0cd79 <+23>: mov -0xc(%rbp),%edx
0x00007ffff7a0cd7c <+26>: shl $0x20,%rdx
0x00007ffff7a0cd80 <+30>: or %rdx,%rax
0x00007ffff7a0cd83 <+33>: pop %rbx
0x00007ffff7a0cd84 <+34>: leaveq
0x00007ffff7a0cd85 <+35>: retq

@bosilca
Copy link
Member Author

@bosilca bosilca commented on 8cae899 Nov 26, 2014 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bosilca
Copy link
Member Author

@bosilca bosilca commented on 8cae899 Nov 27, 2014 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.