From d5dc5584884488c8fcb5710997a14c2c418692f3 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 15 May 2018 16:32:26 +0200 Subject: erts: Make cpu_timestamp use per thread on Linux If we don't use per thread the value becomes completely nonsensical on systems with more than one scheduler. We keep the old solaris behaviour in order to support the option, but it only really works when using a single scheduler. --- erts/aclocal.m4 | 8 ++++---- erts/emulator/beam/erl_bif_trace.c | 4 ++-- erts/emulator/beam/erl_time_sup.c | 2 +- erts/emulator/beam/erl_trace.c | 14 -------------- erts/emulator/sys/unix/erl_unix_sys.h | 10 ++++++---- lib/tools/doc/src/fprof.xml | 10 ++++++++-- 6 files changed, 21 insertions(+), 27 deletions(-) diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index a4d09810bd..99b96eb5bc 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -2645,7 +2645,7 @@ case $erl_gethrvtime in dnl Check if clock_gettime (linux) is working dnl - AC_MSG_CHECKING([if clock_gettime can be used to get process CPU time]) + AC_MSG_CHECKING([if clock_gettime can be used to get thread CPU time]) save_libs=$LIBS LIBS="-lrt" AC_TRY_RUN([ @@ -2659,11 +2659,11 @@ case $erl_gethrvtime in int i; struct timespec tp; - if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) < 0) + if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp) < 0) exit(1); start = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec; for (i = 0; i < 100; i++) - clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp); stop = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec; if (start == 0) exit(4); @@ -2686,7 +2686,7 @@ case $erl_gethrvtime in case $erl_clock_gettime_cpu_time in yes) AC_DEFINE(HAVE_CLOCK_GETTIME_CPU_TIME,[], - [define if clock_gettime() works for getting process time]) + [define if clock_gettime() works for getting thread time]) LIBRT=-lrt ;; cross) diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 1953f79d79..fd3400ab71 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -643,12 +643,12 @@ Eterm erts_internal_trace_3(BIF_ALIST_3) SysTimespec tp; int i; - if (sys_get_proc_cputime(start, tp) < 0) + if (sys_get_cputime(start, tp) < 0) goto error; start = ((SysCpuTime)tp.tv_sec * 1000000000LL) + (SysCpuTime)tp.tv_nsec; for (i = 0; i < 100; i++) - sys_get_proc_cputime(stop, tp); + sys_get_cputime(stop, tp); stop = ((SysCpuTime)tp.tv_sec * 1000000000LL) + (SysCpuTime)tp.tv_nsec; if (start == 0) goto error; diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 4f91d9ad07..29c698e34f 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -1860,7 +1860,7 @@ void erts_get_now_cpu(Uint* megasec, Uint* sec, Uint* microsec) { SysCpuTime t; SysTimespec tp; - sys_get_proc_cputime(t, tp); + sys_get_cputime(t, tp); *microsec = (Uint)(tp.tv_nsec / 1000); t = (tp.tv_sec / 1000000); *megasec = (Uint)(t % 1000000); diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 065a560b52..e9a413904b 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -625,20 +625,6 @@ erts_get_system_profile(void) { return profile; } - -#ifdef HAVE_ERTS_NOW_CPU -# define GET_NOW(m, s, u) \ -do { \ - if (erts_cpu_timestamp) \ - erts_get_now_cpu(m, s, u); \ - else \ - get_now(m, s, u); \ -} while (0) -#else -# define GET_NOW(m, s, u) do {get_now(m, s, u);} while (0) -#endif - - static void write_sys_msg_to_port(Eterm unused_to, Port* trace_port, diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index 10adf80875..5bfe5a8e2d 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -292,6 +292,8 @@ erts_sys_perf_counter() /* * Functions for measuring CPU time + * + * Note that gethrvtime is time per process and clock_gettime is per thread. */ #if (defined(HAVE_GETHRVTIME) || defined(HAVE_CLOCK_GETTIME_CPU_TIME)) @@ -300,15 +302,15 @@ typedef struct timespec SysTimespec; #if defined(HAVE_GETHRVTIME) #define sys_gethrvtime() gethrvtime() -#define sys_get_proc_cputime(t,tp) (t) = sys_gethrvtime(), \ - (tp).tv_sec = (time_t)((t)/1000000000LL), \ - (tp).tv_nsec = (long)((t)%1000000000LL) +#define sys_get_cputime(t,tp) (t) = sys_gethrvtime(), \ + (tp).tv_sec = (time_t)((t)/1000000000LL), \ + (tp).tv_nsec = (long)((t)%1000000000LL) int sys_start_hrvtime(void); int sys_stop_hrvtime(void); #elif defined(HAVE_CLOCK_GETTIME_CPU_TIME) #define sys_clock_gettime(cid,tp) clock_gettime((cid),&(tp)) -#define sys_get_proc_cputime(t,tp) sys_clock_gettime(CLOCK_PROCESS_CPUTIME_ID,(tp)) +#define sys_get_cputime(t,tp) sys_clock_gettime(CLOCK_THREAD_CPUTIME_ID,(tp)) #endif #endif diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml index 4c9e48045e..72624bd33b 100644 --- a/lib/tools/doc/src/fprof.xml +++ b/lib/tools/doc/src/fprof.xml @@ -328,10 +328,16 @@ purposes. This option is only allowed with the start option. cpu_time| {cpu_time, bool()} - The options cpu_time or {cpu_time, true> + The options cpu_time or {cpu_time, true} makes the timestamps in the trace be in CPU time instead of wallclock time which is the default. This option is - only allowed with the start option. + only allowed with the start option. +

Getting correct values out of cpu_time can be difficult. + The best way to get correct values is to run using a single + scheduler and bind that scheduler to a specific CPU, + i.e. erl +S 1 +sbt db.

+
+
{procs, PidSpec}| {procs, [PidSpec]} Specifies which processes that shall be traced. If this option is not given, the calling process is -- cgit v1.2.3