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]

[PATCH] linux, x86: Add 32 bit vDSO time function support


This patch add support for 32 bit vDSO time functions provided by the linux
kernel 3.15, which 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 results in a performance increase between 4 and 13 for this
functions, depending on the CPU and the function.

The patch is not very intrusive, since it only make changes in the
sysdeps/unix/sysv/linux/i386 path.

The code is copied and based from the file in the
sysdeps/unix/sysv/linux/i386/x86_64 path.

The patch is against commit c54e5cf7db32709b4f04a117f44f69dc5684cbf2

I habe signed a ASSIGNMENT - GLIBC form which is already confirmed.

ChangeLog:

2014-04-19  Stefani Seibold  <stefani@seibold.net>

        * sysdeps/unix/sysv/linux/i386/clock_gettime.c: Add header
        * sysdeps/unix/sysv/linux/i386/timespec_get.c: Add header

2014-03-04  Stefani Seibold  <stefani@seibold.net>

        * sysdeps/unix/sysv/linux/i386/Makefile: New file
        * sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h: New file
        * sysdeps/unix/sysv/linux/i386/clock_gettime.c: New file
        * sysdeps/unix/sysv/linux/i386/gettimeofday.c: New file
        * sysdeps/unix/sysv/linux/i386/init-first.c: New file
        * sysdeps/unix/sysv/linux/i386/time.c: New file
        * sysdeps/unix/sysv/linux/i386/timespec_get.c: New file

Signed-off-by: Stefani Seibold <stefani@seibold.net>
---
 sysdeps/unix/sysv/linux/i386/Makefile         |  4 ++
 sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h | 31 +++++++++++++
 sysdeps/unix/sysv/linux/i386/clock_gettime.c  | 37 +++++++++++++++
 sysdeps/unix/sysv/linux/i386/gettimeofday.c   | 65 ++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/i386/init-first.c     | 52 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/i386/time.c           | 67 +++++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/i386/timespec_get.c   | 27 +++++++++++
 7 files changed, 283 insertions(+)
 create mode 100644 sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h
 create mode 100644 sysdeps/unix/sysv/linux/i386/clock_gettime.c
 create mode 100644 sysdeps/unix/sysv/linux/i386/gettimeofday.c
 create mode 100644 sysdeps/unix/sysv/linux/i386/init-first.c
 create mode 100644 sysdeps/unix/sysv/linux/i386/time.c
 create mode 100644 sysdeps/unix/sysv/linux/i386/timespec_get.c

diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile
index acc3021..3222f46 100644
--- a/sysdeps/unix/sysv/linux/i386/Makefile
+++ b/sysdeps/unix/sysv/linux/i386/Makefile
@@ -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 --git a/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h b/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h
new file mode 100644
index 0000000..f291924
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/bits/libc-vdso.h
@@ -0,0 +1,31 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 2005-2014 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 --git a/sysdeps/unix/sysv/linux/i386/clock_gettime.c b/sysdeps/unix/sysv/linux/i386/clock_gettime.c
new file mode 100644
index 0000000..049bc93
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/clock_gettime.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 2002-2014 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 "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 --git a/sysdeps/unix/sysv/linux/i386/gettimeofday.c b/sysdeps/unix/sysv/linux/i386/gettimeofday.c
new file mode 100644
index 0000000..f2be8fb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/gettimeofday.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2014 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 (linux26, "LINUX_2.6", 61765110);
+
+  /* If the vDSO is not available we fall back on the old syscall.  */
+  return (_dl_vdso_vsym ("__vdso_gettimeofday", &linux26)
+	  ?: (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 --git a/sysdeps/unix/sysv/linux/i386/init-first.c b/sysdeps/unix/sysv/linux/i386/init-first.c
new file mode 100644
index 0000000..e8e96d0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/init-first.c
@@ -0,0 +1,52 @@
+/* Initialization code run first thing by the ELF startup code.  Linux/i386.
+   Copyright (C) 2007-2014 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 (linux26, "LINUX_2.6", 61765110);
+
+  void *p = _dl_vdso_vsym ("__vdso_clock_gettime", &linux26);
+  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 --git a/sysdeps/unix/sysv/linux/i386/time.c b/sysdeps/unix/sysv/linux/i386/time.c
new file mode 100644
index 0000000..f1a4c66
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/time.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2001-2014 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 (linux26, "LINUX_2.6", 61765110);
+
+  /* If the vDSO is not available we fall back on the old syscall.  */
+  return _dl_vdso_vsym ("__vdso_time", &linux26) ?: (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 --git a/sysdeps/unix/sysv/linux/i386/timespec_get.c b/sysdeps/unix/sysv/linux/i386/timespec_get.c
new file mode 100644
index 0000000..6eb83c1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/i386/timespec_get.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2002-2014 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 "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"
-- 
1.9.2



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