[v2,05/10] Use clock_gettime to implement time.

Message ID 20190828153236.18229-6-zackw@panix.com
State Superseded
Headers

Commit Message

Zack Weinberg Aug. 28, 2019, 3:32 p.m. UTC
  Most ports were using gettimeofday to implement time, or they were
making a direct (v)syscall.  Unconditionally switch to using
clock_gettime instead.  All sysdeps implementations of time are
removed.

	* time/time.c (time): No longer a stub implementation.
	Call __clock_gettime.

	* sysdeps/unix/sysv/linux/powerpc/Versions (GLIBC_PRIVATE):
	Remove __vdso_time.
	* sysdeps/unix/sysv/linux/powerpc/init-first.c (__vdso_time): Delete.
	(_libc_vdso_platform_setup): Don't initialize __vdso_time.
	* sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list: Remove entry
	for time.

	* sysdeps/posix/time.c
	* sysdeps/unix/sysv/linux/time.c
	* sysdeps/unix/sysv/linux/i386/time.c
	* sysdeps/unix/sysv/linux/powerpc/time.c
	* sysdeps/unix/sysv/linux/sparc/sparc64/time.c
	* sysdeps/unix/sysv/linux/x86/time.c:
	Delete file.
---
 sysdeps/posix/time.c                          | 40 ---------
 sysdeps/unix/sysv/linux/i386/time.c           | 34 --------
 sysdeps/unix/sysv/linux/powerpc/Versions      |  1 -
 sysdeps/unix/sysv/linux/powerpc/init-first.c  |  5 --
 sysdeps/unix/sysv/linux/powerpc/time.c        | 84 -------------------
 sysdeps/unix/sysv/linux/sparc/sparc64/time.c  |  1 -
 sysdeps/unix/sysv/linux/time.c                | 41 ---------
 sysdeps/unix/sysv/linux/x86/time.c            | 59 -------------
 .../unix/sysv/linux/x86_64/x32/syscalls.list  |  1 -
 time/time.c                                   | 12 ++-
 10 files changed, 5 insertions(+), 273 deletions(-)
 delete mode 100644 sysdeps/posix/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/i386/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/powerpc/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/sparc/sparc64/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/time.c
 delete mode 100644 sysdeps/unix/sysv/linux/x86/time.c
  

Comments

Florian Weimer Aug. 28, 2019, 6:16 p.m. UTC | #1
* Zack Weinberg:

> Most ports were using gettimeofday to implement time, or they were
> making a direct (v)syscall.  Unconditionally switch to using
> clock_gettime instead.  All sysdeps implementations of time are
> removed.

I'm sorry, but this is clearly not advisable because clock_gettime is
almost an order of magnitude slower than time.

A synthetic benchmark with back-to-back time calls takes 2.3 ns on a
Xeon Gold 6126 CPU, but 17.9 ns on your branch.

Given that time has no stringent accuracy requirements, this shouldn't
come as a surprise.

Thanks,
Florian
  
Zack Weinberg Aug. 28, 2019, 6:36 p.m. UTC | #2
On Wed, Aug 28, 2019 at 2:16 PM Florian Weimer <fweimer@redhat.com> wrote:
>
> * Zack Weinberg:
>
> > Most ports were using gettimeofday to implement time, or they were
> > making a direct (v)syscall.  Unconditionally switch to using
> > clock_gettime instead.  All sysdeps implementations of time are
> > removed.
>
> I'm sorry, but this is clearly not advisable because clock_gettime is
> almost an order of magnitude slower than time.

Hmm.  How do we reconcile this with the (Linux) kernel maintainers'
stated intentions to provide only clock_gettime in the future?  We
could use CLOCK_REALTIME_COARSE when available, I suppose; can you see
whether that recovers the lost performance, or else send me your
benchmark code so I can try it?

zw
  
Florian Weimer Aug. 28, 2019, 6:49 p.m. UTC | #3
* Zack Weinberg:

> On Wed, Aug 28, 2019 at 2:16 PM Florian Weimer <fweimer@redhat.com> wrote:
>>
>> * Zack Weinberg:
>>
>> > Most ports were using gettimeofday to implement time, or they were
>> > making a direct (v)syscall.  Unconditionally switch to using
>> > clock_gettime instead.  All sysdeps implementations of time are
>> > removed.
>>
>> I'm sorry, but this is clearly not advisable because clock_gettime is
>> almost an order of magnitude slower than time.
>
> Hmm.  How do we reconcile this with the (Linux) kernel maintainers'
> stated intentions to provide only clock_gettime in the future?  We
> could use CLOCK_REALTIME_COARSE when available, I suppose; can you see
> whether that recovers the lost performance, or else send me your
> benchmark code so I can try it?

I see 4.9 ns with CLOCK_REALTIME_COARSE, compared to 2.2 ns for time.
It still looks significantly slower to me.

We also have to be careful not to use clocks that don't stay in the vDSO
on all supported kernel/hypervisor combinations.

Benchmark code is below.

Thanks,
Florian

#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

int
main (int argc, char **argv)
{
  int count;
  if (argc != 3 || (count = atoi (argv[2])) <= 0)
    err (1, "usage: %s METHOD ITERATIONS", argv[0]);

  if (strcmp (argv[1], "time") == 0)
    for (int i = 0; i < count; ++i)
      time (NULL);
  else if (strcmp (argv[1], "gettimeofday") == 0)
    for (int i = 0; i < count; ++i)
      {
        struct timeval tv;
        gettimeofday (&tv, NULL);
      }
  else if (strcmp (argv[1], "realtime") == 0)
    for (int i = 0; i < count; ++i)
      {
        struct timespec tv;
        clock_gettime (CLOCK_REALTIME, &tv);
      }
  else if (strcmp (argv[1], "realtime_coarse") == 0)
    for (int i = 0; i < count; ++i)
      {
        struct timespec tv;
        clock_gettime (CLOCK_REALTIME_COARSE, &tv);
      }
  else if (strcmp (argv[1], "monotonic") == 0)
    for (int i = 0; i < count; ++i)
      {
        struct timespec tv;
        clock_gettime (CLOCK_MONOTONIC, &tv);
      }
  else if (strcmp (argv[1], "monotonic_coarse") == 0)
    for (int i = 0; i < count; ++i)
      {
        struct timespec tv;
        clock_gettime (CLOCK_MONOTONIC_COARSE, &tv);
      }
  else if (strcmp (argv[1], "monotonic_raw") == 0)
    for (int i = 0; i < count; ++i)
      {
        struct timespec tv;
        clock_gettime (CLOCK_MONOTONIC_RAW, &tv);
      }
  else
    errx (1, "invalid clock: %s", argv[1]);

  return 0;
}
  
Paul Eggert Aug. 28, 2019, 8:01 p.m. UTC | #4
Florian Weimer wrote:
> Given that time has no stringent accuracy requirements, this shouldn't
> come as a surprise.

In what sense does 'time' have less-stringent accuracy requirements than 
clock_gettime (CLOCK_REALTIME) does? Can 'time' return a value that disagrees 
with the time_t part of what clock_gettime (CLOCK_REALTIME) returns? Any such 
disagreement would cause application bugs that could well be unlikely and hard 
to track down; also, if there is disagreement, replacing calls to 'time' with 
calls to clock_gettime might not be advisable even aside from performance issues.
  
Florian Weimer Aug. 28, 2019, 8:21 p.m. UTC | #5
* Paul Eggert:

> Florian Weimer wrote:
>> Given that time has no stringent accuracy requirements, this shouldn't
>> come as a surprise.
>
> In what sense does 'time' have less-stringent accuracy requirements
> than clock_gettime (CLOCK_REALTIME) does? Can 'time' return a value
> that disagrees with the time_t part of what clock_gettime
> (CLOCK_REALTIME) returns? Any such disagreement would cause
> application bugs that could well be unlikely and hard to track down;
> also, if there is disagreement, replacing calls to 'time' with calls
> to clock_gettime might not be advisable even aside from performance
> issues.

Maybe accuracy is the wrong word.  But time can definitely return the
value of a variable that is incremented periodically from the timer
interrupt.  That's not possible for gettimeofday or clock_gettime with
CLOCK_REALTIME (from a quality-of-implementation perspective).

Thanks,
Florian
  
Paul Eggert Aug. 28, 2019, 9:12 p.m. UTC | #6
Florian Weimer wrote:
> time can definitely return the
> value of a variable that is incremented periodically from the timer
> interrupt.

Is that variable the one that CLOCK_REALTIME_COARSE uses? If so, and if we're 
going to replace calls to 'time' with calls to 'clock_realtime', we can do 
either of the following:

* Use CLOCK_REALTIME_COARSE. This takes less CPU time and its behavior better 
matches what the current glibc does.

* Use CLOCK_REALTIME. This will lessen bugs due to naive code (quite possibly 
some code within glibc!) which assumes that 'time (0)' and clock_gettime 
(CLOCK_REALTIME, ...)' use the same clock.

It sounds you're leaning towards (1) and I'm inclined to agree. However, 
shouldn't the manual say that 'time' does not necessarily agree with 
CLOCK_REALTIME? The current behavior is a trap for the unwary.


To illustrate the problems with naive code, see the attached program. On my 
Fedora 30 x86-64 desktop, './a.out' outputs this:

clock_gettime (CLOCK_REALTIME, ...) yielded a seconds count of 1567026298;
then time (0) yielded a seconds count of 1567026297, which was 1 s earlier.
Time warp!

In contrast, './a.out 1' (which uses CLOCK_REALTIME_COARSE) finds no 
discrepancies in 2**32 attempts.
  
Florian Weimer Aug. 28, 2019, 9:39 p.m. UTC | #7
* Paul Eggert:

> Florian Weimer wrote:
>> time can definitely return the
>> value of a variable that is incremented periodically from the timer
>> interrupt.
>
> Is that variable the one that CLOCK_REALTIME_COARSE uses? If so, and
> if we're going to replace calls to 'time' with calls to
> 'clock_realtime', we can do either of the following:
>
> * Use CLOCK_REALTIME_COARSE. This takes less CPU time and its behavior
> better matches what the current glibc does.
>
> * Use CLOCK_REALTIME. This will lessen bugs due to naive code (quite
> possibly some code within glibc!) which assumes that 'time (0)' and
> clock_gettime (CLOCK_REALTIME, ...)' use the same clock.

I think we should keep using the time entry in the vDSO.  This
consolidation is just not possible to do for performance reasons.

> It sounds you're leaning towards (1) and I'm inclined to
> agree. However, shouldn't the manual say that 'time' does not
> necessarily agree with CLOCK_REALTIME? The current behavior is a trap
> for the unwary.

Yes, clarifying the manual would make sense.  I do not know where the
discrepancy comes from.  It could just be that CLOCK_REALTIME performs
rounding, while time performs truncation.

Thanks,
Florian
  
Zack Weinberg Aug. 29, 2019, 5:49 p.m. UTC | #8
On Wed, Aug 28, 2019 at 5:39 PM Florian Weimer <fweimer@redhat.com> wrote:
> I think we should keep using the time entry in the vDSO.  This
> consolidation is just not possible to do for performance reasons.

To be crystal clear about where I'm coming from, I think this
consolidation is *necessary* to clear the way for the y2038 patches.
And I was under the impression that the kernel people wanted to
withdraw support for the time and gettimeofday entry points (at least
for new architectures going forward).

So I'm only looking for ways to mitigate the performance impact at
this point.  Before I back off on "henceforth we only call the
kernel's clock_gettime" I would need to hear *both* a really
compelling argument for why we need to keep calling the time or
gettimeofday entry points -- a few ns more expense on a call that only
reports the time to the nearest second isn't going to cut it -- *and*
an explanation of why it won't interfere with the y2038 work and/or
why we won't have to stop using them in the future anyway.

zw
  
Florian Weimer Sept. 2, 2019, 1:32 p.m. UTC | #9
* Zack Weinberg:

> On Wed, Aug 28, 2019 at 5:39 PM Florian Weimer <fweimer@redhat.com> wrote:
>> I think we should keep using the time entry in the vDSO.  This
>> consolidation is just not possible to do for performance reasons.
>
> To be crystal clear about where I'm coming from, I think this
> consolidation is *necessary* to clear the way for the y2038 patches.

But it's not an absolute technical requirement, right?

I mean, if we wanted, we could still add a file like
sysdeps/unix/sysv/linux/x86_64/time.c and do things differently there?
(Although we'd also have to change the vDSO setup code for an efficient
implementation.)

> And I was under the impression that the kernel people wanted to
> withdraw support for the time and gettimeofday entry points (at least
> for new architectures going forward).

Yes, but that doesn't mean they want performance regressions on x86-64.
I think.

> So I'm only looking for ways to mitigate the performance impact at
> this point.  Before I back off on "henceforth we only call the
> kernel's clock_gettime" I would need to hear *both* a really
> compelling argument for why we need to keep calling the time or
> gettimeofday entry points -- a few ns more expense on a call that only
> reports the time to the nearest second isn't going to cut it -- *and*
> an explanation of why it won't interfere with the y2038 work and/or
> why we won't have to stop using them in the future anyway.

I expect that people have time calls in (binary) logging code where this
is visible.  I think EXPLAIN ANALYZE in PostgreSQL also rather sensitive
to timing performance, but fortunately it already uses
clock_gettimeofday.

I'm not too concerned here (assuming that we *can* still optimize the
time function on select architectures if that proves necessary in a
couple of years).  It's just that I really dislike the idea of
performance regressions on 64-bit architectures as a side effect of
Y2038 support on 32-bit architectures.

Thanks,
Florian
  
Adhemerval Zanella Netto Sept. 2, 2019, 6:35 p.m. UTC | #10
On 02/09/2019 10:32, Florian Weimer wrote:
> * Zack Weinberg:
> 
>> On Wed, Aug 28, 2019 at 5:39 PM Florian Weimer <fweimer@redhat.com> wrote:
>>> I think we should keep using the time entry in the vDSO.  This
>>> consolidation is just not possible to do for performance reasons.
>>
>> To be crystal clear about where I'm coming from, I think this
>> consolidation is *necessary* to clear the way for the y2038 patches.
> 
> But it's not an absolute technical requirement, right?
> 
> I mean, if we wanted, we could still add a file like
> sysdeps/unix/sysv/linux/x86_64/time.c and do things differently there?
> (Although we'd also have to change the vDSO setup code for an efficient
> implementation.)
> 
>> And I was under the impression that the kernel people wanted to
>> withdraw support for the time and gettimeofday entry points (at least
>> for new architectures going forward).
> 
> Yes, but that doesn't mean they want performance regressions on x86-64.
> I think.
> 
>> So I'm only looking for ways to mitigate the performance impact at
>> this point.  Before I back off on "henceforth we only call the
>> kernel's clock_gettime" I would need to hear *both* a really
>> compelling argument for why we need to keep calling the time or
>> gettimeofday entry points -- a few ns more expense on a call that only
>> reports the time to the nearest second isn't going to cut it -- *and*
>> an explanation of why it won't interfere with the y2038 work and/or
>> why we won't have to stop using them in the future anyway.
> 
> I expect that people have time calls in (binary) logging code where this
> is visible.  I think EXPLAIN ANALYZE in PostgreSQL also rather sensitive
> to timing performance, but fortunately it already uses
> clock_gettimeofday.
> 
> I'm not too concerned here (assuming that we *can* still optimize the
> time function on select architectures if that proves necessary in a
> couple of years).  It's just that I really dislike the idea of
> performance regressions on 64-bit architectures as a side effect of
> Y2038 support on 32-bit architectures.

I think the *default* implementation for time should indeed be done through
clock_gettime, as this patch intends, however I also think it is possible to
keep arch-specific code in place so the optimized vDSO implementation are
used. It will also allow each arch maintainer to do the switch if the
consensus would to use the default one.

My view is we can use my proposed patch to refactor time [1], and change
the fallback syscall path to call clock_gettime instead.  I can work
towards the modification.

[1] https://sourceware.org/ml/libc-alpha/2019-07/msg00157.html
  

Patch

diff --git a/sysdeps/posix/time.c b/sysdeps/posix/time.c
deleted file mode 100644
index e1b3bc8d4c..0000000000
--- a/sysdeps/posix/time.c
+++ /dev/null
@@ -1,40 +0,0 @@ 
-/* Copyright (C) 1991-2019 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 <stddef.h>		/* For NULL.  */
-#include <time.h>
-#include <sys/time.h>
-
-
-/* Return the current time as a `time_t' and also put it in *T if T is
-   not NULL.  Time is represented as seconds from Jan 1 00:00:00 1970.  */
-time_t
-time (time_t *t)
-{
-  struct timeval tv;
-  time_t result;
-
-  if (__gettimeofday (&tv, (struct timezone *) NULL))
-    result = (time_t) -1;
-  else
-    result = (time_t) tv.tv_sec;
-
-  if (t != NULL)
-    *t = result;
-  return result;
-}
-libc_hidden_def (time)
diff --git a/sysdeps/unix/sysv/linux/i386/time.c b/sysdeps/unix/sysv/linux/i386/time.c
deleted file mode 100644
index 440e3e6ab4..0000000000
--- a/sysdeps/unix/sysv/linux/i386/time.c
+++ /dev/null
@@ -1,34 +0,0 @@ 
-/* time -- Get number of seconds since Epoch.  Linux/i386 version.
-   Copyright (C) 2015-2019 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
-# define time __redirect_time
-#endif
-
-#include <time.h>
-
-#ifdef SHARED
-# undef time
-# define time_type __redirect_time
-
-# undef libc_hidden_def
-# define libc_hidden_def(name)  \
-  __hidden_ver1 (__time_syscall, __GI_time, __time_syscall);
-#endif
-
-#include <sysdeps/unix/sysv/linux/x86/time.c>
diff --git a/sysdeps/unix/sysv/linux/powerpc/Versions b/sysdeps/unix/sysv/linux/powerpc/Versions
index 8ebeea15a1..859e0d7daf 100644
--- a/sysdeps/unix/sysv/linux/powerpc/Versions
+++ b/sysdeps/unix/sysv/linux/powerpc/Versions
@@ -10,7 +10,6 @@  libc {
     __vdso_clock_gettime;
     __vdso_clock_getres;
     __vdso_getcpu;
-    __vdso_time;
   }
 }
 libm {
diff --git a/sysdeps/unix/sysv/linux/powerpc/init-first.c b/sysdeps/unix/sysv/linux/powerpc/init-first.c
index 831f910788..4f12b59e76 100644
--- a/sysdeps/unix/sysv/linux/powerpc/init-first.c
+++ b/sysdeps/unix/sysv/linux/powerpc/init-first.c
@@ -25,7 +25,6 @@  int (*VDSO_SYMBOL(clock_gettime)) (clockid_t, struct timespec *);
 int (*VDSO_SYMBOL(clock_getres)) (clockid_t, struct timespec *);
 unsigned long long (*VDSO_SYMBOL(get_tbfreq)) (void);
 int (*VDSO_SYMBOL(getcpu)) (unsigned *, unsigned *);
-time_t (*VDSO_SYMBOL(time)) (time_t *);
 
 #if defined(__PPC64__) || defined(__powerpc64__)
 void *VDSO_SYMBOL(sigtramp_rt64);
@@ -59,10 +58,6 @@  _libc_vdso_platform_setup (void)
   PTR_MANGLE (p);
   VDSO_SYMBOL (getcpu) = p;
 
-  p = _dl_vdso_vsym ("__kernel_time", &linux2615);
-  PTR_MANGLE (p);
-  VDSO_SYMBOL (time) = p;
-
   /* PPC64 uses only one signal trampoline symbol, while PPC32 will use
      two depending if SA_SIGINFO is used (__kernel_sigtramp_rt32) or not
      (__kernel_sigtramp32).
diff --git a/sysdeps/unix/sysv/linux/powerpc/time.c b/sysdeps/unix/sysv/linux/powerpc/time.c
deleted file mode 100644
index cb3e8b9a73..0000000000
--- a/sysdeps/unix/sysv/linux/powerpc/time.c
+++ /dev/null
@@ -1,84 +0,0 @@ 
-/* time system call for Linux/PowerPC.
-   Copyright (C) 2013-2019 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
-# ifndef __powerpc64__
-#  define time __redirect_time
-# else
-#  define __redirect_time time
-# endif
-
-# include <time.h>
-# include <sysdep.h>
-# include <dl-vdso.h>
-# include <libc-vdso.h>
-# include <dl-machine.h>
-
-# ifndef __powerpc64__
-#  undef time
-
-time_t
-__time_vsyscall (time_t *t)
-{
-  return INLINE_VSYSCALL (time, 1, t);
-}
-
-/* __GI_time is defined as hidden and for ppc32 it enables the
-   compiler make a local call (symbol@local) for internal GLIBC usage. It
-   means the PLT won't be used and the ifunc resolver will be called directly.
-   For ppc64 a call to a function in another translation unit might use a
-   different toc pointer thus disallowing direct branchess and making internal
-   ifuncs calls safe.  */
-#  undef libc_hidden_def
-#  define libc_hidden_def(name)					\
-  __hidden_ver1 (__time_vsyscall, __GI_time, __time_vsyscall);
-
-# endif /* !__powerpc64__  */
-
-static time_t
-time_syscall (time_t *t)
-{
-  struct timeval tv;
-  time_t result;
-
-  if (INLINE_VSYSCALL (gettimeofday, 2, &tv, NULL) < 0)
-    result = (time_t) -1;
-  else
-    result = (time_t) tv.tv_sec;
-
-  if (t != NULL)
-    *t = result;
-  return result;
-}
-
-# define INIT_ARCH()						\
-  PREPARE_VERSION_KNOWN (linux2615, LINUX_2_6_15);		\
-  void *vdso_time = _dl_vdso_vsym ("__kernel_time", &linux2615);
-
-/* If the vDSO is not available we fall back to the syscall.  */
-libc_ifunc_hidden (__redirect_time, time,
-		   vdso_time
-		   ? VDSO_IFUNC_RET (vdso_time)
-		   : (void *) time_syscall);
-libc_hidden_def (time)
-
-#else
-
-#include <sysdeps/posix/time.c>
-
-#endif /* !SHARED */
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/time.c b/sysdeps/unix/sysv/linux/sparc/sparc64/time.c
deleted file mode 100644
index 509b580c55..0000000000
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/time.c
+++ /dev/null
@@ -1 +0,0 @@ 
-#include <sysdeps/posix/time.c>
diff --git a/sysdeps/unix/sysv/linux/time.c b/sysdeps/unix/sysv/linux/time.c
deleted file mode 100644
index 1978f6d817..0000000000
--- a/sysdeps/unix/sysv/linux/time.c
+++ /dev/null
@@ -1,41 +0,0 @@ 
-/* Copyright (C) 2005-2019 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 <stddef.h>
-#include <time.h>
-
-#include <sysdep.h>
-
-#ifdef __NR_time
-
-time_t
-time (time_t *t)
-{
-  INTERNAL_SYSCALL_DECL (err);
-  time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
-  /* There cannot be any error.  */
-  if (t != NULL)
-    *t = res;
-  return res;
-}
-libc_hidden_def (time)
-
-#else
-
-# include <sysdeps/posix/time.c>
-
-#endif
diff --git a/sysdeps/unix/sysv/linux/x86/time.c b/sysdeps/unix/sysv/linux/x86/time.c
deleted file mode 100644
index 3d72488500..0000000000
--- a/sysdeps/unix/sysv/linux/x86/time.c
+++ /dev/null
@@ -1,59 +0,0 @@ 
-/* time -- Get number of seconds since Epoch.  Linux/x86 version.
-   Copyright (C) 2015-2019 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 <time.h>
-
-#ifdef SHARED
-
-#include <dl-vdso.h>
-#include <errno.h>
-
-static time_t
-__time_syscall (time_t *t)
-{
-  INTERNAL_SYSCALL_DECL (err);
-  return INTERNAL_SYSCALL (time, err, 1, t);
-}
-
-# ifndef time_type
-/* The i386 time.c includes this file with a defined time_type macro.
-   For x86_64 we have to define it to time as the internal symbol is the
-   ifunc'ed one.  */
-#  define time_type time
-# endif
-
-#undef INIT_ARCH
-#define INIT_ARCH() PREPARE_VERSION_KNOWN (linux26, LINUX_2_6);
-/* If the vDSO is not available we fall back on the syscall.  */
-libc_ifunc_hidden (time_type, time,
-		   (_dl_vdso_vsym ("__vdso_time", &linux26)
-		    ?:  &__time_syscall))
-libc_hidden_def (time)
-
-#else
-
-# 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/x86_64/x32/syscalls.list b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
index b44f6f99e9..c0cfa7b0da 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/syscalls.list
@@ -3,4 +3,3 @@ 
 gettimeofday	-	gettimeofday:__vdso_gettimeofday@LINUX_2.6	i:pP	__gettimeofday	gettimeofday
 personality	EXTRA	personality	Ei:i	__personality	personality
 posix_fadvise64	-	fadvise64	Vi:iiii	posix_fadvise	posix_fadvise64
-time		-	time:__vdso_time@LINUX_2.6			Ei:P	time
diff --git a/time/time.c b/time/time.c
index 88612d6c76..bae0fd14dd 100644
--- a/time/time.c
+++ b/time/time.c
@@ -15,19 +15,17 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <errno.h>
 #include <time.h>
 
 /* Return the time now, and store it in *TIMER if not NULL.  */
 time_t
 time (time_t *timer)
 {
-  __set_errno (ENOSYS);
+  struct timespec ts;
+  __clock_gettime (CLOCK_REALTIME, &ts);
 
-  if (timer != NULL)
-    *timer = (time_t) -1;
-  return (time_t) -1;
+  if (timer)
+    *timer = ts.tv_sec;
+  return ts.tv_sec;
 }
 libc_hidden_def (time)
-
-stub_warning (time)