2001-04-21  Ulrich Drepper  <drepper@redhat.com>

	* elf/dl-support.c: Include cpuclock-init.h.  Use CPUCLOCK_VARDEF and
	CPUCLOCK_INIT if defined.
	* sysdeps/generic/dl-sysdep.c: Likewise.
	* sysdeps/generic/cpuclock-init.h: New file.
	* sysdeps/unix/i386/i586/cpuclock-init.h: New file.
	* sysdeps/unix/i386/i586/Versions: New file.
	* sysdeps/unix/i386/i586/clock_settime.c: New file.
	* sysdeps/unix/i386/i586/clock_gettime.c: Handle thread CPU clock
	separately by calling __pthread_clock_gettime if this function is
	available.  Subtract offset from tsc value before computing time value.
This commit is contained in:
Ulrich Drepper 2001-04-21 07:55:01 +00:00
parent b17c0a8e31
commit 5fc48cd78f
18 changed files with 358 additions and 28 deletions

View File

@ -1,3 +1,16 @@
2001-04-21 Ulrich Drepper <drepper@redhat.com>
* elf/dl-support.c: Include cpuclock-init.h. Use CPUCLOCK_VARDEF and
CPUCLOCK_INIT if defined.
* sysdeps/generic/dl-sysdep.c: Likewise.
* sysdeps/generic/cpuclock-init.h: New file.
* sysdeps/unix/i386/i586/cpuclock-init.h: New file.
* sysdeps/unix/i386/i586/Versions: New file.
* sysdeps/unix/i386/i586/clock_settime.c: New file.
* sysdeps/unix/i386/i586/clock_gettime.c: Handle thread CPU clock
separately by calling __pthread_clock_gettime if this function is
available. Subtract offset from tsc value before computing time value.
2001-04-20 Ulrich Drepper <drepper@redhat.com>
* iconv/iconv_prog.c (print_known_names): If printing goes not to

View File

@ -29,6 +29,7 @@
#include <bits/libc-lock.h>
#include <dl-librecon.h>
#include <unsecvars.h>
#include <cpuclock-init.h>
extern char *__progname;
char **_dl_argv = &__progname; /* This is checked for some error messages. */
@ -92,6 +93,11 @@ struct r_scope_elem *_dl_main_searchlist = &_dl_initial_searchlist;
/* Nonzero during startup. */
int _dl_starting_up = 1;
/* Initial value of the CPU clock. */
#ifdef CPUCLOCK_VARDEF
CPUCLOCK_VARDEF (_dl_cpuclock_offset);
#endif
/* During the program run we must not modify the global data of
loaded shared object simultanously in two threads. Therefore we
protect `_dl_open' and `_dl_close' in dl-close.c.
@ -127,6 +133,10 @@ static void non_dynamic_init (void) __attribute__ ((unused));
static void
non_dynamic_init (void)
{
#ifdef CPUCLOCK_INIT
CPUCLOCK_INIT (_dl_cpuclock_offset);
#endif
if (!_dl_pagesize)
_dl_pagesize = __getpagesize ();

View File

@ -1,3 +1,21 @@
2001-04-21 Ulrich Drepper <drepper@redhat.com>
* internals.h: Include <cpuclock-init.h>.
(struct _pthread_descr_struct): Add p_cpuclock_offset field if
CPUCLOCK_VARDEF is defined.
* pthread.c (__pthread_initialize_minimal): Initialize
p_cpuclock_offset field for main thread if CPUCLOCK_INIT is defined.
* manager.c (pthread_start_thread): Set p_cpuclock_offset field
for new thread to current CPU clock value.
* sysdeps/i386/useldt.h: Extend all the macros to handle 8-byte values.
* sysdeps/i386/i586/Makefile: New file.
* sysdeps/i386/i586/Versions: New file.
* sysdeps/i386/i586/ptclock_gettime.c: New file.
* sysdeps/i386/i586/ptclock_settime.c: New file.
* sysdeps/i386/i686/Implies: New file.
2001-04-18 Jakub Jelinek <jakub@redhat.com>
* sysdeps/unix/sysv/linux/sparc/sparc64/Makefile: Put specs into

View File

@ -33,6 +33,7 @@ extern int __compare_and_swap (long int *p, long int oldval, long int newval);
#include "pt-machine.h"
#include "semaphore.h"
#include "../linuxthreads_db/thread_dbP.h"
#include <cpuclock-init.h>
#ifndef THREAD_GETMEM
# define THREAD_GETMEM(descr, member) descr->member
@ -179,6 +180,9 @@ struct _pthread_descr_struct {
struct __res_state *p_resp; /* Pointer to resolver state */
struct __res_state p_res; /* per-thread resolver state */
int p_inheritsched; /* copied from the thread attribute */
#ifdef CPUCLOCK_VARDEF
CPUCLOCK_VARDEF (p_cpuclock_offset); /* Initial CPU clock for thread. */
#endif
/* New elements must be added at the end. */
} __attribute__ ((aligned(32))); /* We need to align the structure so that
doubles are aligned properly. This is 8

View File

@ -225,9 +225,16 @@ static int pthread_start_thread(void *arg)
pthread_descr self = (pthread_descr) arg;
struct pthread_request request;
void * outcome;
#ifdef CPUCLOCK_VARDEF
CPUCLOCK_VARDEF (tmpclock);
#endif
/* Initialize special thread_self processing, if any. */
#ifdef INIT_THREAD_SELF
INIT_THREAD_SELF(self, self->p_nr);
#endif
#ifdef CPUCLOCK_INIT
CPUCLOCK_INIT (tmpclock);
THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);
#endif
/* Make sure our pid field is initialized, just in case we get there
before our father has initialized it. */

View File

@ -225,6 +225,11 @@ static void pthread_handle_sigcancel(int sig);
static void pthread_handle_sigrestart(int sig);
static void pthread_handle_sigdebug(int sig);
/* CPU clock handling. */
#ifdef CPUCLOCK_VARDECL
CPUCLOCK_VARDECL (_dl_cpuclock_offset);
#endif
/* Signal numbers used for the communication.
In these variables we keep track of the used variables. If the
platform does not support any real-time signals we will define the
@ -390,6 +395,9 @@ __pthread_initialize_minimal(void)
#ifdef INIT_THREAD_SELF
INIT_THREAD_SELF(&__pthread_initial_thread, 0);
#endif
#ifdef CPUCLOCK_INIT
__pthread_initial_thread.p_cpuclock_offset = _dl_cpuclock_offset;
#endif
}

View File

@ -0,0 +1,3 @@
ifeq ($(subdir),linuxthreads)
libpthread-sysdep_routines += ptclock_gettime ptclock_settime
endif

View File

@ -0,0 +1,5 @@
libpthread {
GLIBC_2.2.3 {
__pthread_clock_gettime; __pthread_clock_settime;
}
}

View File

@ -0,0 +1,45 @@
/* Copyright (C) 2001 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 Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <time.h>
#include <libc-internal.h>
#include "../../../internals.h"
int
__pthread_clock_gettime (unsigned long long int freq, struct timespec *tp)
{
unsigned long long int tsc;
pthread_descr self = thread_self ();
/* Get the current counter. */
asm volatile ("rdtsc" : "=A" (tsc));
/* Compute the offset since the start time of the process. */
tsc -= THREAD_GETMEM (self, p_cpuclock_offset);
/* Compute the seconds. */
tp->tv_sec = tsc / freq;
/* And the nanoseconds. This computation should be stable until
we get machines with about 16GHz frequency. */
tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq;
return 0;
}

View File

@ -0,0 +1,32 @@
/* Copyright (C) 2001 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 Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <time.h>
#include <libc-internal.h>
#include "../../../internals.h"
void
__pthread_clock_settime (unsigned long long int offset)
{
pthread_descr self = thread_self ();
/* Compute the offset since the start time of the process. */
THREAD_SETMEM (self, p_cpuclock_offset, offset);
}

View File

@ -0,0 +1 @@
i386/i586

View File

@ -1,6 +1,6 @@
/* Special definitions for ix86 machine using segment register based
thread descriptor.
Copyright (C) 1998, 2000 Free Software Foundation, Inc.
Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>.
@ -88,16 +88,24 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
: "0" (0), \
"i" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 4) \
/* There should not be any value with a size other than 1 or 4. */ \
abort (); \
\
else if (sizeof (__value) == 4) \
__asm__ __volatile__ ("movl %%gs:%P1,%0" \
: "=r" (__value) \
: "i" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 8) \
/* There should not be any value with a size other than 1, 4 or 8. */\
abort (); \
\
__asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t" \
"movl %%gs:%P2,%%edx" \
: "=A" (__value) \
: "i" (offsetof (struct _pthread_descr_struct, \
member)), \
"i" (offsetof (struct _pthread_descr_struct, \
member) + 4)); \
} \
__value; \
})
@ -112,16 +120,22 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
: "0" (0), \
"r" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 4) \
/* There should not be any value with a size other than 1 or 4. */ \
abort (); \
\
else if (sizeof (__value) == 4) \
__asm__ __volatile__ ("movl %%gs:(%1),%0" \
: "=r" (__value) \
: "r" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 8) \
/* There should not be any value with a size other than 1, 4 or 8. */\
abort (); \
\
__asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t" \
"movl %%gs:4(%1),%%edx" \
: "=&A" (__value) \
: "r" (offsetof (struct _pthread_descr_struct, \
member))); \
} \
__value; \
})
@ -135,16 +149,24 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
: "q" (__value), \
"i" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 4) \
/* There should not be any value with a size other than 1 or 4. */ \
abort (); \
\
else if (sizeof (__value) == 4) \
__asm__ __volatile__ ("movl %0,%%gs:%P1" : \
: "r" (__value), \
"i" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 8) \
/* There should not be any value with a size other than 1, 4 or 8. */\
abort (); \
\
__asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n" \
"movl %%edx,%%gs:%P2" : \
: "A" (__value), \
"i" (offsetof (struct _pthread_descr_struct, \
member)), \
"i" (offsetof (struct _pthread_descr_struct, \
member) + 4)); \
} \
})
@ -157,16 +179,22 @@ extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t);
: "q" (__value), \
"r" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 4) \
/* There should not be any value with a size other than 1 or 4. */ \
abort (); \
\
else if (sizeof (__value) == 4) \
__asm__ __volatile__ ("movl %0,%%gs:(%1)" : \
: "r" (__value), \
"r" (offsetof (struct _pthread_descr_struct, \
member))); \
else \
{ \
if (sizeof (__value) != 8) \
/* There should not be any value with a size other than 1, 4 or 8. */\
abort (); \
\
__asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t" \
"movl %%edx,%%gs:4(%1)" : \
: "A" (__value), \
"r" (offsetof (struct _pthread_descr_struct, \
member))); \
} \
})

View File

@ -0,0 +1 @@
/* In general there is no CPU clock. */

View File

@ -35,6 +35,7 @@
#include <dl-machine.h>
#include <dl-procinfo.h>
#include <dl-osinfo.h>
#include <cpuclock-init.h>
extern int _dl_argc;
extern char **_dl_argv;
@ -60,7 +61,9 @@ int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
void *__libc_stack_end;
static ElfW(auxv_t) *_dl_auxv;
unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
#ifdef CPUCLOCK_VARDEF
CPUCLOCK_VARDEF (_dl_cpuclock_offset);
#endif
#ifndef DL_FIND_ARG_COMPONENTS
# define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
@ -97,6 +100,10 @@ _dl_sysdep_start (void **start_argptr,
# define set_seen(tag) seen |= M ((tag)->a_type)
#endif
#ifdef CPUCLOCK_INIT
CPUCLOCK_INIT (_dl_cpuclock_offset);
#endif
DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ,
_dl_auxv);

View File

@ -0,0 +1,5 @@
ld {
GLIBC_2.2.3 {
_dl_cpuclock_offset;
}
}

View File

@ -19,6 +19,9 @@
#include <time.h>
#include <libc-internal.h>
#include "cpuclock-init.h"
/* This implementation uses the TSC register in modern (i586 and up) IA-32
processors (most modern clones also provide it). Since we need the
resolution of the clock and since determining this is not cheap, we
@ -33,17 +36,42 @@
static unsigned long long int freq;
/* We add an limitation here: we assume that the machine is not up as
long as it takes to wrap-around the 64-bit timestamp counter. On a
4GHz machine it would take 136 years of uptime to wrap around so
this "limitation" is not severe.
/* We need the starting time for the process. */
CPUCLOCK_VARDECL (_dl_cpuclock_offset);
We use this clock also as the monotonic clock since we don't allow
setting the CPU-time clock. If this should ever change we will have
to separate the two. */
/* This function is defined in the thread library. */
extern int __pthread_clock_gettime (unsigned long long int freq,
struct timespec *tp)
__attribute__ ((__weak__));
/* We add an limitation here: we assume that the process is not
running as long as it takes to wrap-around the 64-bit timestamp
counter. On a 4GHz machine it would take 136 years of uptime to
wrap around so this "limitation" is not severe. */
#define EXTRA_CLOCK_CASES \
case CLOCK_PROCESS_CPUTIME_ID: \
case CLOCK_THREAD_CPUTIME_ID: \
if (__pthread_clock_gettime != NULL) \
{ \
if (__builtin_expect (freq == 0, 0)) \
{ \
/* This can only happen if we haven't initialized the `freq' \
variable yet. Do this now. We don't have to protect this \
code against multiple execution since all of them should \
lead to the same result. */ \
freq = __get_clockfreq (); \
if (__builtin_expect (freq == 0, 0)) \
/* Something went wrong. */ \
break; \
} \
\
retval = __pthread_clock_gettime (freq, tp); \
break; \
} \
/* FALLTHROUGH */ \
\
case CLOCK_PROCESS_CPUTIME_ID: \
{ \
unsigned long long int tsc; \
\
@ -62,6 +90,9 @@ static unsigned long long int freq;
/* Get the current counter. */ \
asm volatile ("rdtsc" : "=A" (tsc)); \
\
/* Compute the offset since the start time of the process. */ \
tsc -= _dl_cpuclock_offset; \
\
/* Compute the seconds. */ \
tp->tv_sec = tsc / freq; \
\

View File

@ -0,0 +1,85 @@
/* Copyright (C) 2001 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 Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <time.h>
#include "cpuclock-init.h"
/* This implementation uses the TSC register in modern (i586 and up) IA-32
processors (most modern clones also provide it). Since we need the
resolution of the clock and since determining this is not cheap, we
cache the value. But this means that systems with processors running
at different speeds or process migration to machines with slower or
faster processors will not work without changes. */
/* Clock frequency of the processor. We make it a 64-bit variable
because some jokers are already playing with processors with more
than 4GHz. */
static unsigned long long int freq;
/* We need the starting time for the process. */
CPUCLOCK_VARDECL (_dl_cpuclock_offset);
/* This function is defined in the thread library. */
extern void __pthread_clock_settime (unsigned long long int offset)
__attribute__ ((__weak__));
/* We add an limitation here: we assume that the process is not
running as long as it takes to wrap-around the 64-bit timestamp
counter. On a 4GHz machine it would take 136 years of uptime to
wrap around so this "limitation" is not severe. */
#define EXTRA_CLOCK_CASES \
case CLOCK_PROCESS_CPUTIME_ID: \
case CLOCK_THREAD_CPUTIME_ID: \
{ \
unsigned long long int tsc; \
unsigned long long int usertime; \
\
/* First thing is to get the current time. */ \
asm volatile ("rdtsc" : "=A" (tsc)); \
\
if (__builtin_expect (freq == 0, 0)) \
{ \
/* This can only happen if we haven't initialized the `freq' \
variable yet. Do this now. We don't have to protect this \
code against multiple execution since all of them should \
lead to the same result. */ \
freq = __get_clockfreq (); \
if (__builtin_expect (freq == 0, 0)) \
/* Something went wrong. */ \
break; \
} \
\
/* Convert the user-provided time into CPU ticks. */ \
usertime = tp->tv_sec * freq + (tp->tv_nsec * freq) / 1000000000ull; \
\
/* Determine the offset and use it as the new base value. */ \
if (clock_id != CLOCK_THREAD_CPUTIME_ID \
|| __pthread_clock_settime == NULL) \
_dl_cpuclock_offset = tsc - usertime; \
else \
__pthread_clock_settime (tsc - usertime); \
} \
break;
#include <sysdeps/unix/clock_settime.c>

View File

@ -0,0 +1,27 @@
/* x86 TSC based CPU clock initialization code.
Copyright (C) 2001 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 Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* The TSC value has 64 bits. */
#define CPUCLOCK_VARDEF(name) unsigned long long int name
/* A declaration. */
#define CPUCLOCK_VARDECL(name) extern unsigned long long int name
/* Reading the TSC value is a simple instruction. */
#define CPUCLOCK_INIT(name) asm volatile ("rdtsc" : "=A" (name))