This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

x86: Add 32 bit vDSO time function support


Hi,

in the near future the linux will support vDSO time functions for the
x86 32 bit kernels. This will be also supported the ia32 emulation mode.

The VDSO time functions __vdso_time(), __vdso_gettimeofday() and
__vdso_clock_getttime() are fast and a reliable way to get the exact
time without the overhead of a kernel system call.

This result in a  performance increase between 4 and 13 for this
functions, depending on the CPU and the function.

I will attach the patch against glibc-2.19, which is not very intrusive,
since it only make changes in the  sysdeps/unix/sysv/linux/i386 path.

How is the procedure to get this patch into the glibc mainline?

- Stefani

diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h glibc-2.18/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h	1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h	2014-03-03 11:29:26.799650036 +0100
@@ -0,0 +1,31 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 2005-2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBC_VDSO_H
+#define _LIBC_VDSO_H
+
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef SHARED
+
+extern long int (*__vdso_clock_gettime) (clockid_t, struct timespec *);
+
+#endif
+
+#endif /* _LIBC_VDSO_H */
diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/clock_gettime.c glibc-2.18/sysdeps/unix/sysv/linux/i386/clock_gettime.c
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/clock_gettime.c	1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/clock_gettime.c	2014-03-03 11:44:54.873047522 +0100
@@ -0,0 +1,20 @@
+#include "bits/libc-vdso.h"
+
+#ifdef SHARED
+# define SYSCALL_GETTIME(id, tp) \
+  ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \
+  long int v_ret;							  \
+  PTR_DEMANGLE (f);							  \
+  v_ret = f (id, tp);							  \
+  if (INTERNAL_SYSCALL_ERROR_P (v_ret, )) {				  \
+    __set_errno (INTERNAL_SYSCALL_ERRNO (v_ret, ));			  \
+    v_ret = -1;								  \
+  }									  \
+  v_ret; })
+# define INTERNAL_GETTIME(id, tp) \
+  ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \
+  PTR_DEMANGLE (f);							  \
+  f (id, tp); })
+#endif
+
+#include "../clock_gettime.c"
diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/gettimeofday.c glibc-2.18/sysdeps/unix/sysv/linux/i386/gettimeofday.c
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/gettimeofday.c	1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/gettimeofday.c	2014-03-03 17:08:02.021699309 +0100
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sys/time.h>
+
+#ifdef SHARED
+
+# include <dl-vdso.h>
+# include <sysdep.h>
+# include <errno.h>
+
+static int
+fallback_gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
+}
+
+void *gettimeofday_ifunc (void) __asm__ ("__gettimeofday");
+
+void *
+gettimeofday_ifunc (void)
+{
+  PREPARE_VERSION (linux25, "LINUX_2.5", 61765109);
+
+  /* If the vDSO is not available we fall back on the old syscall.  */
+  return (_dl_vdso_vsym ("__vdso_gettimeofday", &linux25)
+	  ?: (void *) fallback_gettimeofday);
+}
+asm (".type __gettimeofday, %gnu_indirect_function");
+
+/* This is doing "libc_hidden_def (__gettimeofday)" but the compiler won't
+   let us do it in C because it doesn't know we're defining __gettimeofday
+   here in this file.  */
+asm (".globl __GI___gettimeofday\n"
+     "__GI___gettimeofday = __gettimeofday");
+
+#else
+
+# include <sysdep.h>
+# include <errno.h>
+
+int
+__gettimeofday (struct timeval *tv, struct timezone *tz)
+{
+  return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
+}
+libc_hidden_def (__gettimeofday)
+
+#endif
+weak_alias (__gettimeofday, gettimeofday)
+libc_hidden_weak (gettimeofday)
diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/init-first.c glibc-2.18/sysdeps/unix/sysv/linux/i386/init-first.c
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/init-first.c	1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/init-first.c	2014-03-03 16:16:37.766257808 +0100
@@ -0,0 +1,52 @@
+/* Initialization code run first thing by the ELF startup code.  Linux/i386.
+   Copyright (C) 2007-2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+# include <time.h>
+# include <sysdep.h>
+# include <dl-vdso.h>
+# include <bits/libc-vdso.h>
+
+long int (*__vdso_clock_gettime) (clockid_t, struct timespec *)
+  __attribute__ ((nocommon));
+strong_alias (__vdso_clock_gettime, __GI___vdso_clock_gettime attribute_hidden)
+
+
+long int fallback_clock_gettime(clockid_t id, struct timespec *tp)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  return INTERNAL_SYSCALL (clock_gettime, err, 2, id, tp);
+}
+
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  PREPARE_VERSION (linux25, "LINUX_2.5", 61765109);
+
+  void *p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux25);
+  if (p == NULL)
+    p = fallback_clock_gettime;
+  PTR_MANGLE (p);
+  __GI___vdso_clock_gettime = p;
+}
+
+# define VDSO_SETUP _libc_vdso_platform_setup
+#endif
+
+#include <csu/init-first.c>
diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/Makefile glibc-2.18/sysdeps/unix/sysv/linux/i386/Makefile
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/Makefile	2013-08-11 00:52:55.000000000 +0200
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/Makefile	2014-03-03 11:34:21.922960487 +0100
@@ -21,3 +21,7 @@ endif
 ifeq ($(subdir),stdlib)
 gen-as-const-headers += ucontext_i.sym
 endif
+
+ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso
+endif
diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/time.c glibc-2.18/sysdeps/unix/sysv/linux/i386/time.c
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/time.c	1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/time.c	2014-03-03 16:19:09.428361771 +0100
@@ -0,0 +1,67 @@
+/* Copyright (C) 2001-2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifdef SHARED
+/* Redefine time so that the compiler won't complain about the type
+   mismatch with the IFUNC selector in strong_alias, below.  */
+#undef time
+#define time __redirect_time
+#include <time.h>
+#include <sysdep.h>
+
+static time_t
+fallback_time (time_t *t)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  return INTERNAL_SYSCALL (time, err, 1, t);
+}
+
+
+#include <dl-vdso.h>
+
+/* Avoid DWARF definition DIE on ifunc symbol so that GDB can handle
+   ifunc symbol properly.  */
+extern __typeof (__redirect_time) __libc_time;
+void *time_ifunc (void) __asm__ ("__libc_time");
+
+void *
+time_ifunc (void)
+{
+  PREPARE_VERSION (linux25, "LINUX_2.5", 61765109);
+
+  /* If the vDSO is not available we fall back on the old syscall.  */
+  return _dl_vdso_vsym ("__vdso_time", &linux25) ?: (void *) fallback_time;
+}
+__asm (".type __libc_time, %gnu_indirect_function");
+
+#undef time
+strong_alias (__libc_time, time)
+libc_hidden_ver (__libc_time, time)
+
+#else
+
+# include <time.h>
+# include <sysdep.h>
+
+time_t
+time (time_t *t)
+{
+  INTERNAL_SYSCALL_DECL (err);
+  return INTERNAL_SYSCALL (time, err, 1, t);
+}
+
+#endif
diff -u -N -r -p glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/timespec_get.c glibc-2.18/sysdeps/unix/sysv/linux/i386/timespec_get.c
--- glibc-2.18.orig/sysdeps/unix/sysv/linux/i386/timespec_get.c	1970-01-01 01:00:00.000000000 +0100
+++ glibc-2.18/sysdeps/unix/sysv/linux/i386/timespec_get.c	2014-03-03 11:22:34.829800368 +0100
@@ -0,0 +1,10 @@
+#include "bits/libc-vdso.h"
+
+#ifdef SHARED
+# define INTERNAL_GETTIME(id, tp) \
+  ({ long int (*f) (clockid_t, struct timespec *) = __vdso_clock_gettime; \
+  PTR_DEMANGLE (f);							  \
+  f (id, tp); })
+#endif
+
+#include "../timespec_get.c"



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]