>From 49f8827eff8ce94e7e1fb62ebfa0add419238850 Mon Sep 17 00:00:00 2001
From: Maria Guseva <m.guseva@samsung.com>
Date: Wed, 13 Jan 2016 19:58:24 +0300
Subject: [PATCH 2/2] Generic time implementation.

	* elf/dl-support.c (_dl_non_dynamic_init) [HP_TIMING_AVAIL]:
    Time _dl_cpuclock_offset.
	* elf/rtld.c (relocate_time, load_time, start_time): Declare when
    (HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL) is defined instead of
    HP_TIMING_AVAIL.
    (dl_start_final_info): Check (HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL)
    instead of HP_TIMING_AVAIL.
	(DL_STATISTICS_TIMING_NOW): New macro to define timing
	in case of DL_DEBUG_STATISTICS set.
	(DL_STATISTICS_TIMING_DIFF): Likewise.
	(DL_STATISTICS_TIMING_ACCUM_NT): Likewise.
    (_dl_start_final) [HP_TIMING_AVAIL]: Time dl_cpuclock_offset.
    (_dl_start_final): Check (HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL)
    instead of HP_TIMING_AVAIL.
    (dl_main): Likewise. Use DL_STATISTICS_TIMING_NOW, DL_STATISTICS_TIMING_DIFF,
    DL_STATISTICS_TIMING_ACCUM_NT instead of HP_TIMING_NOW, HP_TIMING_DIFF,
    HP_TIMING_ACCUM_NT.
	(dl_main) [HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL]: Initialize start
    with 0 to prevent warnings.
    (print_statistics): Check (HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL)
    instead of HP_TIMING_AVAIL.
	* sysdeps/generic/hp-timing-common.h (HP_TIMING_UNIT): New.
	Define to "cycles".
	(HP_TIMING_PRINT): Print HP_TIMING_UNIT instead of "cycles".
	* sysdeps/generic/hp-timing.h: Add includes <stdint.h>, <sysdep.h>,
    <hp-timing-common.h>.
	(HP_SMALL_TIMING_AVAIL): Define to 1.
	(HP_GENERIC_TIMING_AVAIL): New. Define to 1.
	(hp_timing_t): Add typedef.
    [!HAVE_CLOCK_GETTIME_VSYSCALL](__INTERNAL_SYSCALL): New.
    Define to INTERNAL_SYSCALL.
    [HAVE_CLOCK_GETTIME_VSYSCALL]: Add include <sysdep-vdso.h>.
	[HAVE_CLOCK_GETTIME_VSYSCALL](__INTERNAL_SYSCALL): New.
	Define to INTERNAL_VSYSCALL.
	[__NR_clock_gettime] (HP_TIMING_NOW): Define using clock_gettime.
	[__NR_clock_gettime] (HP_TIMING_UNIT): Define to "nsec".
	[!__NR_clock_gettime]: Add include <sys/time.h>.
	[!__NR_clock_gettime] (HP_TIMING_NOW): Define using __gettimeofday.
	[!__NR_clock_gettime] (HP_TIMING_UNIT): Define to "usec".
---
 elf/dl-support.c                   |   2 +
 elf/rtld.c                         | 115 ++++++++++++++++++++++++-------------
 sysdeps/generic/hp-timing-common.h |   9 ++-
 sysdeps/generic/hp-timing.h        |  64 +++++++++++++++++----
 4 files changed, 137 insertions(+), 53 deletions(-)

diff --git a/elf/dl-support.c b/elf/dl-support.c
index 303e5d0..f2b4788 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -311,8 +311,10 @@ _dl_non_dynamic_init (void)
   _dl_main_map.l_phdr = GL(dl_phdr);
   _dl_main_map.l_phnum = GL(dl_phnum);
 
+#if HP_TIMING_AVAIL
   if (HP_SMALL_TIMING_AVAIL)
     HP_TIMING_NOW (_dl_cpuclock_offset);
+#endif
 
   _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
 
diff --git a/elf/rtld.c b/elf/rtld.c
index b1125d9..34c4ab5 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -195,7 +195,7 @@ static struct libname_list _dl_rtld_libname;
 static struct libname_list _dl_rtld_libname2;
 
 /* Variable for statistics.  */
-#if HP_TIMING_AVAIL
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
 static hp_timing_t relocate_time;
 static hp_timing_t load_time attribute_relro;
 static hp_timing_t start_time attribute_relro;
@@ -227,7 +227,7 @@ static ElfW(Addr) _dl_start_final (void *arg);
 struct dl_start_final_info
 {
   struct link_map l;
-#if HP_TIMING_AVAIL && HP_TIMING_INLINE
+#if (HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL) && HP_TIMING_INLINE
   hp_timing_t start_time;
 #endif
 };
@@ -240,6 +240,35 @@ extern char _begin[] attribute_hidden;
 extern char _etext[] attribute_hidden;
 extern char _end[] attribute_hidden;
 
+/* Macros to define timing in case of DL_DEBUG_STATISTICS set.  */
+# if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
+#define DL_STATISTICS_TIMING_NOW(tval)  \
+do {    \
+    if (__glibc_unlikely (HP_SMALL_TIMING_AVAIL &&                  \
+                      (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))) \
+      HP_TIMING_NOW (tval); \
+} while (0)
+
+#define DL_STATISTICS_TIMING_DIFF(tdiff, tval1, tval2) \
+do {    \
+if (__glibc_unlikely (HP_SMALL_TIMING_AVAIL &&                      \
+                      (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))) \
+  HP_TIMING_DIFF (tdiff, tval1, tval2); \
+} while (0)
+
+#define DL_STATISTICS_TIMING_ACCUM_NT(tsum, tval) \
+do {    \
+if (__glibc_unlikely (HP_SMALL_TIMING_AVAIL &&                       \
+                      (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS)))  \
+  HP_TIMING_ACCUM_NT (tsum, tval);  \
+} while (0)
+
+# else
+#define DL_STATISTICS_TIMING_NOW(tval)
+#define DL_STATISTICS_TIMING_DIFF(tdiff, tval1, tval2)
+#define DL_STATISTICS_TIMING_ACCUM(tsum, tval)
+# endif
+
 
 #ifdef RTLD_START
 RTLD_START
@@ -295,7 +324,9 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
 # endif
 #endif
 
+#if HP_TIMING_AVAIL
   HP_TIMING_NOW (GL(dl_cpuclock_offset));
+#endif
 
   /* Initialize the stack end variable.  */
   __libc_stack_end = __builtin_frame_address (0);
@@ -306,23 +337,23 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
      entry point on the same stack we entered on.  */
   start_addr = _dl_sysdep_start (arg, &dl_main);
 
-#if HP_TIMING_AVAIL
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
   hp_timing_t rtld_total_time;
   if (HP_SMALL_TIMING_AVAIL)
     {
       hp_timing_t end_time;
 
       /* Get the current time.  */
-      HP_TIMING_NOW (end_time);
+      DL_STATISTICS_TIMING_NOW (end_time);
 
       /* Compute the difference.  */
-      HP_TIMING_DIFF (rtld_total_time, start_time, end_time);
+      DL_STATISTICS_TIMING_DIFF (rtld_total_time, start_time, end_time);
     }
 #endif
 
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS))
     {
-#if HP_TIMING_AVAIL
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
       print_statistics (&rtld_total_time);
 #else
       print_statistics (NULL);
@@ -350,12 +381,14 @@ _dl_start (void *arg)
 #define RESOLVE_MAP(sym, version, flags) (&bootstrap_map)
 #include "dynamic-link.h"
 
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
   if (HP_TIMING_INLINE && HP_SMALL_TIMING_AVAIL)
 #ifdef DONT_USE_BOOTSTRAP_MAP
     HP_TIMING_NOW (start_time);
 #else
     HP_TIMING_NOW (info.start_time);
 #endif
+#endif
 
   /* Partly clean the `bootstrap_map' structure up.  Don't use
      `memset' since it might not be built in or inlined and we cannot
@@ -745,8 +778,8 @@ dl_main (const ElfW(Phdr) *phdr,
   unsigned int i;
   bool prelinked = false;
   bool rtld_is_main = false;
-#if HP_TIMING_AVAIL
-  hp_timing_t start;
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
+  hp_timing_t start = 0;
   hp_timing_t stop;
   hp_timing_t diff;
 #endif
@@ -922,12 +955,12 @@ of this helper program; chances are you did not intend to run this program.\n\
 	}
       else
 	{
-	  HP_TIMING_NOW (start);
+	  DL_STATISTICS_TIMING_NOW (start);
 	  _dl_map_object (NULL, rtld_progname, lt_executable, 0,
 			  __RTLD_OPENEXEC, LM_ID_BASE);
-	  HP_TIMING_NOW (stop);
+	  DL_STATISTICS_TIMING_NOW (stop);
 
-	  HP_TIMING_DIFF (load_time, start, stop);
+	  DL_STATISTICS_TIMING_DIFF (load_time, start, stop);
 	}
 
       /* Now the map for the main executable is available.  */
@@ -1489,7 +1522,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
       char *list = strdupa (preloadlist);
       char *p;
 
-      HP_TIMING_NOW (start);
+      DL_STATISTICS_TIMING_NOW (start);
 
       /* Prevent optimizing strsep.  Speed is not important here.  */
       while ((p = (strsep) (&list, " :")) != NULL)
@@ -1498,9 +1531,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 		|| strchr (p, '/') == NULL))
 	  npreloads += do_preload (p, main_map, "LD_PRELOAD");
 
-      HP_TIMING_NOW (stop);
-      HP_TIMING_DIFF (diff, start, stop);
-      HP_TIMING_ACCUM_NT (load_time, diff);
+      DL_STATISTICS_TIMING_NOW (stop);
+      DL_STATISTICS_TIMING_DIFF (diff, start, stop);
+      DL_STATISTICS_TIMING_ACCUM_NT (load_time, diff);
     }
 
   /* There usually is no ld.so.preload file, it should only be used
@@ -1560,7 +1593,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	      file[file_size - 1] = '\0';
 	    }
 
-	  HP_TIMING_NOW (start);
+	  DL_STATISTICS_TIMING_NOW (start);
 
 	  if (file != problem)
 	    {
@@ -1578,9 +1611,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	      npreloads += do_preload (p, main_map, preload_file);
 	    }
 
-	  HP_TIMING_NOW (stop);
-	  HP_TIMING_DIFF (diff, start, stop);
-	  HP_TIMING_ACCUM_NT (load_time, diff);
+	  DL_STATISTICS_TIMING_NOW (stop);
+	  DL_STATISTICS_TIMING_DIFF (diff, start, stop);
+	  DL_STATISTICS_TIMING_ACCUM_NT (load_time, diff);
 
 	  /* We don't need the file anymore.  */
 	  __munmap (file, file_size);
@@ -1604,11 +1637,11 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
   /* Load all the libraries specified by DT_NEEDED entries.  If LD_PRELOAD
      specified some libraries to load, these are inserted before the actual
      dependencies in the executable's searchlist for symbol resolution.  */
-  HP_TIMING_NOW (start);
+  DL_STATISTICS_TIMING_NOW (start);
   _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
-  HP_TIMING_NOW (stop);
-  HP_TIMING_DIFF (diff, start, stop);
-  HP_TIMING_ACCUM_NT (load_time, diff);
+  DL_STATISTICS_TIMING_NOW (stop);
+  DL_STATISTICS_TIMING_DIFF (diff, start, stop);
+  DL_STATISTICS_TIMING_ACCUM_NT (load_time, diff);
 
   /* Mark all objects as being in the global scope.  */
   for (i = main_map->l_searchlist.r_nlist; i > 0; )
@@ -1997,12 +2030,12 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
       if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
 	{
 	  ElfW(Rela) *conflict, *conflictend;
-#if HP_TIMING_AVAIL
-	  hp_timing_t start;
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
+	  hp_timing_t start = 0;
 	  hp_timing_t stop;
 #endif
 
-	  HP_TIMING_NOW (start);
+	  DL_STATISTICS_TIMING_NOW(start);
 	  assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
 	  conflict = (ElfW(Rela) *)
 	    main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
@@ -2010,8 +2043,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	    ((char *) conflict
 	     + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
 	  _dl_resolve_conflicts (main_map, conflict, conflictend);
-	  HP_TIMING_NOW (stop);
-	  HP_TIMING_DIFF (relocate_time, start, stop);
+	  DL_STATISTICS_TIMING_NOW (stop);
+	  DL_STATISTICS_TIMING_DIFF (relocate_time, start, stop);
 	}
 
 
@@ -2039,15 +2072,15 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	 know that because it is self-contained).  */
 
       int consider_profiling = GLRO(dl_profile) != NULL;
-#if HP_TIMING_AVAIL
-      hp_timing_t start;
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
+      hp_timing_t start = 0;
       hp_timing_t stop;
 #endif
 
       /* If we are profiling we also must do lazy reloaction.  */
       GLRO(dl_lazy) |= consider_profiling;
 
-      HP_TIMING_NOW (start);
+      DL_STATISTICS_TIMING_NOW (start);
       unsigned i = main_map->l_searchlist.r_nlist;
       while (i-- > 0)
 	{
@@ -2074,9 +2107,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	  if (l->l_tls_blocksize != 0 && tls_init_tp_called)
 	    _dl_add_to_slotinfo (l);
 	}
-      HP_TIMING_NOW (stop);
+      DL_STATISTICS_TIMING_NOW (stop);
 
-      HP_TIMING_DIFF (relocate_time, start, stop);
+      DL_STATISTICS_TIMING_DIFF (relocate_time, start, stop);
 
       /* Now enable profiling if needed.  Like the previous call,
 	 this has to go here because the calls it makes should use the
@@ -2117,19 +2150,19 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
 	 re-relocation, we might call a user-supplied function
 	 (e.g. calloc from _dl_relocate_object) that uses TLS data.  */
 
-#if HP_TIMING_AVAIL
-      hp_timing_t start;
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
+      hp_timing_t start = 0;
       hp_timing_t stop;
       hp_timing_t add;
 #endif
 
-      HP_TIMING_NOW (start);
+      DL_STATISTICS_TIMING_NOW (start);
       /* Mark the link map as not yet relocated again.  */
       GL(dl_rtld_map).l_relocated = 0;
       _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
-      HP_TIMING_NOW (stop);
-      HP_TIMING_DIFF (add, start, stop);
-      HP_TIMING_ACCUM_NT (relocate_time, add);
+      DL_STATISTICS_TIMING_NOW (stop);
+      DL_STATISTICS_TIMING_DIFF (add, start, stop);
+      DL_STATISTICS_TIMING_ACCUM_NT (relocate_time, add);
     }
 
   /* Do any necessary cleanups for the startup OS interface code.
@@ -2568,7 +2601,7 @@ static void
 __attribute ((noinline))
 print_statistics (hp_timing_t *rtld_total_timep)
 {
-#if HP_TIMING_AVAIL
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
   char buf[200];
   char *cp;
   char *wp;
@@ -2640,7 +2673,7 @@ print_statistics (hp_timing_t *rtld_total_timep)
 		    GL(dl_num_cache_relocations),
 		    num_relative_relocations);
 
-#if HP_TIMING_AVAIL
+#if HP_TIMING_AVAIL || HP_GENERIC_TIMING_AVAIL
   /* Time spend while loading the object and the dependencies.  */
   if (HP_SMALL_TIMING_AVAIL)
     {
diff --git a/sysdeps/generic/hp-timing-common.h b/sysdeps/generic/hp-timing-common.h
index 257cdd3..77cdeba 100644
--- a/sysdeps/generic/hp-timing-common.h
+++ b/sysdeps/generic/hp-timing-common.h
@@ -47,6 +47,11 @@
 /* Accumulate ADD into SUM.  No attempt is made to be thread-safe.  */
 #define HP_TIMING_ACCUM_NT(Sum, Diff)		((Sum) += (Diff))
 
+/* Define timing unit name to be printed, default is cycles.  */
+#ifndef HP_TIMING_UNIT
+#define HP_TIMING_UNIT "cycles"
+#endif
+
 /* Write a decimal representation of the timing value into the given string.  */
 #define HP_TIMING_PRINT(Dest, Len, Val) 				\
   do {									\
@@ -56,7 +61,7 @@
     char *__cp = _itoa ((Val), __buf + sizeof (__buf), 10, 0);		\
     size_t __cp_len = MIN (__buf + sizeof (__buf) - __cp, __len);	\
     memcpy (__dest, __cp, __cp_len);					\
-    memcpy (__dest + __cp_len, " cycles",				\
-	    MIN (__len - __cp_len, sizeof (" cycles")));		\
+    memcpy (__dest + __cp_len, " " HP_TIMING_UNIT,		\
+	    MIN (__len - __cp_len, sizeof (" " HP_TIMING_UNIT)));	\
     __dest[__len - 1] = '\0';						\
   } while (0)
diff --git a/sysdeps/generic/hp-timing.h b/sysdeps/generic/hp-timing.h
index 5597378..a9905c0 100644
--- a/sysdeps/generic/hp-timing.h
+++ b/sysdeps/generic/hp-timing.h
@@ -20,18 +20,62 @@
 #ifndef _HP_TIMING_H
 #define _HP_TIMING_H	1
 
-/* There are no generic definitions for the times.  We could write something
-   using the `gettimeofday' system call where available but the overhead of
-   the system call might be too high.  */
+/* Generic definitions for the times using the `clock_gettime'
+   system or vdso call where available
+   or gettimeofday function call in  other cases.  */
 
-/* Provide dummy definitions.  */
 #define HP_TIMING_AVAIL		(0)
-#define HP_SMALL_TIMING_AVAIL	(0)
+#define HP_GENERIC_TIMING_AVAIL	(1)
+#define HP_SMALL_TIMING_AVAIL	(1)
 #define HP_TIMING_INLINE	(0)
-typedef int hp_timing_t;
-#define HP_TIMING_NOW(var)
-#define HP_TIMING_DIFF(Diff, Start, End)
-#define HP_TIMING_ACCUM_NT(Sum, Diff)
-#define HP_TIMING_PRINT(Buf, Len, Val)
+
+/* Use 64bit values for the times in nano- or microseconds.  */
+#include <stdint.h>
+typedef uint64_t hp_timing_t;
+
+/* Use vdso syscall where available.  */
+#include <sysdep.h>
+#ifndef HAVE_CLOCK_GETTIME_VSYSCALL
+# define __INTERNAL_SYSCALL INTERNAL_SYSCALL
+#else
+# include <sysdep-vdso.h>
+# define __INTERNAL_SYSCALL INTERNAL_VSYSCALL
+#endif
+
+# ifdef __NR_clock_gettime
+
+/* Use clockgettime where available.  */
+#define HP_TIMING_NOW(var)                                              \
+do                                                                      \
+  {                                                                     \
+    struct timespec __t;                                                \
+    INTERNAL_SYSCALL_DECL (__err);                                      \
+    __INTERNAL_SYSCALL (clock_gettime, __err, 2, CLOCK_MONOTONIC, &__t);\
+    var = (uint64_t)__t.tv_nsec + (uint64_t)__t.tv_sec * 1000000000L;   \
+  }                                                                     \
+while (0)
+
+/* Define timing unit name to be printed.  */
+#define HP_TIMING_UNIT "nsec"
+
+# else
+
+/* Use gettimeofday function in other cases.  */
+#include <sys/time.h>
+#define HP_TIMING_NOW(var)                                              \
+do                                                                      \
+  {                                                                     \
+    struct timeval __t;                                                 \
+    __gettimeofday (&__t, NULL);                                        \
+    var = (uint64_t)__t.tv_usec + (uint64_t)__t.tv_sec * 1000000L;      \
+  }                                                                     \
+while (0)
+
+/* Define timing unit name to be printed. */
+#define HP_TIMING_UNIT "usec"
+
+# endif /* __NR_clock_gettime */
+
+#include <hp-timing-common.h>
 
 #endif	/* hp-timing.h */
-- 
1.9.1

