pastebin - collaborative debugging tool
rovema.kpaste.net RSS


linux_vdso_myclockgettime1.c - fast clock_gettime implementation
Posted by Anonymous on Wed 28th Sep 2022 16:49
raw | new post
view followups (newest first): linux_vdso_myclockgettime1.c - fast clock_gettime implementation by Anonymous
modification of post by Anonymous (view diff)

  1. /*
  2.  * linux_vdso_myclockgettime1.c - use Linux VDSO
  3.  * shortcut for |clock_gettime()|, even if userland (g)libc
  4.  * does not have support for VDSO
  5.  *
  6.  * Compile with:
  7.  * $ clang -std=c99 -g -m32 -Wall -Wextra linux_vdso_myclockgettime1.c \
  8.  *      -lpthread -o linux_vdso_myclockgettime1
  9.  *
  10.  * Written by Roland Mainz <roland.mainz@nrubsig.org>
  11.  *
  12.  */
  13.  
  14. #define _XOPEN_SOURCE 600
  15.  
  16. #include <stdio.h>
  17. #include <stddef.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <elf.h>
  21. #include <time.h>
  22. #include <pthread.h>
  23. #include <sys/auxv.h>
  24.  
  25. #if (_XOPEN_SOURCE < 600)
  26. #error _XOPEN_SOURCE wrong version
  27. #endif
  28.  
  29. #if (__PTRDIFF_WIDTH__ == 32)
  30. typedef Elf32_Ehdr      ElfXX_Ehdr;
  31. typedef Elf32_Shdr      ElfXX_Shdr;
  32. typedef Elf32_Sym       ElfXX_Sym;
  33. #elif (__PTRDIFF_WIDTH__ == 64)
  34. typedef Elf64_Ehdr      ElfXX_Ehdr;
  35. typedef Elf64_Shdr      ElfXX_Shdr;
  36. typedef Elf64_Sym       ElfXX_Sym;
  37. #else
  38. #error Unsupported __PTRDIFF_WIDTH__
  39. #endif
  40.  
  41. /* debug */
  42. #if 0
  43. #define D(x) x
  44. #else
  45. #define D(x)
  46. #endif
  47.  
  48. static
  49. void *get_linux_vdso_sym(const char *funcname)
  50. {
  51.         const char      *dynstr = NULL;
  52.         void            *ret = NULL;
  53.         unsigned char   *vdso_addr;
  54.         ssize_t         i;
  55.         size_t          si;
  56.         const char      *name;
  57.         ElfXX_Ehdr      *elf_header;
  58.         ElfXX_Shdr      *section_header;
  59.         ElfXX_Shdr      *s;
  60.         ElfXX_Shdr      *ss_;
  61.         ElfXX_Sym       *sym;
  62.  
  63.         /*
  64.          * valgrind can disable |AT_SYSINFO_EHDR| - see
  65.          * https://www.mail-archive.com/kde-bugs-dist@kde.org/msg550927.html
  66.          */
  67.         vdso_addr = (unsigned char *)getauxval(AT_SYSINFO_EHDR);
  68.         if (!vdso_addr) {
  69.                 D((void)fprintf(stderr, "get_linux_vdso_sym: getauxval(AT_SYSINFO_EHDR) failed.\n"));
  70.                 return NULL;
  71.         }
  72.    
  73.         elf_header = (ElfXX_Ehdr *)vdso_addr;
  74.         section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff);
  75.  
  76.         for (i=0L; i < elf_header->e_shnum; i++) {
  77.                 s = &section_header[i];
  78.                 ss_ = &section_header[elf_header->e_shstrndx];
  79.                 name = (const char*)(vdso_addr + ss_->sh_offset + s->sh_name);
  80.  
  81.                 if (strcmp(name, ".dynstr") == 0) {
  82.                         dynstr = (const char *)(vdso_addr + s->sh_offset);
  83.                         break;
  84.                 }
  85.         }
  86.  
  87.         for (i=0L; i < elf_header->e_shnum; i++) {
  88.                 s = &section_header[i];
  89.                 ss_ = &section_header[elf_header->e_shstrndx];
  90.                 name = (const char*)(vdso_addr + ss_->sh_offset + s->sh_name);
  91.  
  92.                 /* Not .dynsym ? Then look at next section... */
  93.                 if (strcmp(name, ".dynsym"))
  94.                         continue;
  95.  
  96.                 for (si=0L; si < (s->sh_size/s->sh_entsize); si++) {
  97.                         sym = &(((ElfXX_Sym*)(vdso_addr + s->sh_offset))[si]);
  98.                         name = dynstr + sym->st_name;
  99.  
  100.                         D((void)fprintf(stderr, "get_linux_vdso_sym: symbol=|%s| vs. |%s|\n",
  101.                                 funcname, name));
  102.                         if (!strcmp(name, funcname)) {
  103.                                 ret = (void *)(vdso_addr + sym->st_value);
  104.                                 break;
  105.                         }
  106.                 }
  107.                 if (ret)
  108.                         break;
  109.         }
  110.  
  111.         return ret;
  112. }
  113.  
  114. typedef int (clock_gettime_func_t)(clockid_t clk_id, struct timespec *tp);
  115.  
  116. static pthread_once_t my_clock_gettime_func_is_initialized = PTHREAD_ONCE_INIT;
  117. clock_gettime_func_t *my_clock_gettime_func = NULL;
  118.  
  119. void my_clock_gettime_func_init(void)
  120. {
  121.         my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("clock_gettime");
  122.         if (!my_clock_gettime_func)
  123.                 my_clock_gettime_func = (clock_gettime_func_t *)get_linux_vdso_sym("__vdso_clock_gettime");
  124.  
  125.         D((void)fprintf(stderr, "my_clock_gettime_func_init: "
  126.                 "my_clock_gettime_func = 0x%lx (%s)\n",
  127.                 (long)my_clock_gettime_func,
  128.                 (my_clock_gettime_func?
  129.                         "Using fast codepath":
  130.                         "Using slow codepath")));
  131.         if (!my_clock_gettime_func) {
  132.                 (void)fprintf(stderr, "my_clock_gettime_func_init: "
  133.                         "WARNING: aux symbol for clock_gettime not found"
  134.                         ", using slow libc codepath.\n");
  135.         }
  136. }
  137.  
  138.  
  139. /*
  140.  * my_clock_gettime() - our "public" interface
  141.  *
  142.  * Notes:
  143.  * - The first call might be slower because the call to
  144.  * |my_clock_gettime_func_init()|
  145.  */
  146. int my_clock_gettime(clockid_t clk_id, struct timespec *tp)
  147. {
  148.         (void)pthread_once(&my_clock_gettime_func_is_initialized,
  149.                 my_clock_gettime_func_init);
  150.  
  151.         if (my_clock_gettime_func) {
  152.                 /* our own "fast" codepath */
  153.                 return (*my_clock_gettime_func)(clk_id, tp);
  154.         }
  155.         else
  156.         {
  157.                 /* libc codepath, whatever they use - might be VDSO, might be syscall */
  158.                 return clock_gettime(clk_id, tp);
  159.         }
  160. }
  161.  
  162. static
  163. void test_my_clock_gettime1(void)
  164. {
  165.         /*
  166.          * dummy call to |my_clock_gettime()| to force initalisation
  167.          * via |my_clock_gettime_func_init()|
  168.          */
  169.         struct timespec dummy;
  170.         (void)my_clock_gettime(CLOCK_REALTIME, &dummy);
  171.        
  172. #define PRINT_CLOCK(clock) \
  173.         { \
  174.                 struct timespec tp1, tp2; \
  175.                 /* \
  176.                  * first libc implementation, then our implementation, \
  177.                  * so that the difference is the call time of our \
  178.                  * codepath. Requires |my_clock_gettime_func_init()| \
  179.                  * to run before this sequence!! \
  180.                  */ \
  181.                 (void)clock_gettime((clock), &tp1); \
  182.                 (void)my_clock_gettime((clock), &tp2); \
  183.                 (void)printf( \
  184.                         "%-20s libc_impl = \t(%-10ld\t%-10ld), " \
  185.                         "our_impl = \t(%-10ld\t%-10ld)\n", \
  186.                         #clock ":", \
  187.                         (long)tp1.tv_sec, (long)tp1.tv_nsec, \
  188.                         (long)tp2.tv_sec, (long)tp2.tv_nsec); \
  189.         }
  190.  
  191.         PRINT_CLOCK(CLOCK_REALTIME);
  192.         PRINT_CLOCK(CLOCK_MONOTONIC);
  193. }
  194.  
  195. int main(int ac, char *av[])
  196. {
  197.         (void)ac;
  198.         (void)av;
  199.        
  200.         test_my_clock_gettime1();
  201.  
  202.         return EXIT_SUCCESS;
  203. }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at