This is the mail archive of the libc-alpha@sources.redhat.com 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]

Revised: IA64 HP_TIMING fixes for SMP systems with unsynchronizedITC


Modifications:
- Move Linux specific code into sysdeps/unix/sysv/linux/ia64.
- Scale the usecs obtained from gettimeofday properly to simulate ITC.

Summary of the issue:

The current code in sysdeps/ia64/hp-timing.h expects the ITC to deliver an
monotonic increasing clock value. That is assured only on UP systems and
on SMP systems with synchronized ITC clocks.

Some systems (like the SGI Altix) do not have synchronized ITC clocks. If
a process is moved to another processor and ITC is used to determine time
then time may seem to be running backwards or leaping because ITC values
from different CPUs are compared.

IA64 kernels provide a proc file /proc/sal/itc_drift that contains "1" if
the platform has an unsynchronized ITC.

The following patch checks for drifty ITC clocks based on that file. If
ITC is drifty then it generates timestamps based on the gettimeofday
system call.

This also contains a small fix for elf/rtld-Rules

Index: glibc-2.3.2-200309260658/elf/rtld-Rules
===================================================================
--- glibc-2.3.2-200309260658.orig/elf/rtld-Rules	2003-07-24 20:31:13.000000000 -0700
+++ glibc-2.3.2-200309260658/elf/rtld-Rules	2004-06-03 18:46:55.000000000 -0700
@@ -31,7 +31,7 @@
 ifeq ($(subdir),elf)

 ifndef rtld-subdirs
-error This makefile is a subroutine of elf/Makefile not to be used directly
+$(error This makefile is a subroutine of elf/Makefile not to be used directly)
 endif

 include ../Makeconfig
Index: glibc-2.3.2-200309260658/sysdeps/ia64/Makefile
===================================================================
--- glibc-2.3.2-200309260658.orig/sysdeps/ia64/Makefile	2004-06-03 18:44:10.000000000 -0700
+++ glibc-2.3.2-200309260658/sysdeps/ia64/Makefile	2004-06-03 18:46:55.000000000 -0700
@@ -12,7 +12,7 @@

 ifeq (yes,$(build-shared))
 # Compatibility
-sysdep_routines += libgcc-compat
+sysdep_routines += libgcc-compat
 shared-only-routines += libgcc-compat
 endif
 endif
@@ -21,4 +21,15 @@
 sysdep-dl-routines += dl-symaddr dl-fptr
 sysdep_routines += $(sysdep-dl-routines)
 sysdep-rtld-routines += $(sysdep-dl-routines)
+sysdep-dl-routines += hp-timing
 endif
+
+ifeq ($(subdir),posix)
+sysdep_routines += hp-timing
+endif
+
+ifeq ($(subdir),malloc)
+libmemusage-sysdep_routines += hp-timing
+endif
+
+
Index: glibc-2.3.2-200309260658/sysdeps/ia64/hp-timing.c
===================================================================
--- glibc-2.3.2-200309260658.orig/sysdeps/ia64/hp-timing.c	2002-01-31 23:48:41.000000000 -0800
+++ glibc-2.3.2-200309260658/sysdeps/ia64/hp-timing.c	2004-06-04 08:29:06.000000000 -0700
@@ -18,7 +18,61 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */

+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
 #include <hp-timing.h>

 /* We have to define the variable for the overhead.  */
 hp_timing_t _dl_hp_timing_overhead;
+
+static int freq;
+extern hp_timing_t __get_clockfreq (void);
+
+/* Values
+   itc_drifting ==-1 using ITC
+   itc_drifting == 1 using CLOCK_REALTIME
+   itc_drifting == 0 ITC drift status undetermined
+*/
+int itc_drifting=0;
+
+unsigned long int hp_gettimestamp(void)
+{
+	if (itc_drifting>0)
+get_realtimestamp:
+	{
+		struct timeval t;
+		unsigned long usecs;
+
+		/* Make sure that CPU clock frequency has already been determined */
+		if (freq==0)
+		{
+			freq=__get_clockfreq()/1000000UL;
+			if (freq==0) freq=10;
+		}
+		/* clock_gettime is not working in the elf loader... use gettimeofday */
+		__gettimeofday(&t,NULL);
+		usecs=t.tv_usec+t.tv_sec*1000000UL;
+		/* properly scale the microseconds according to the CPU clock rate */
+		return usecs*freq;
+	}
+	else
+	{
+		unsigned long x;
+
+		if (itc_is_drifting())
+		{
+			itc_drifting=1;
+			goto get_realtimestamp;
+		}
+		itc_drifting=-1;
+		HP_TIMING_NOW(x);
+		return x;
+	}
+}
+
Index: glibc-2.3.2-200309260658/sysdeps/ia64/hp-timing.h
===================================================================
--- glibc-2.3.2-200309260658.orig/sysdeps/ia64/hp-timing.h	2003-07-20 14:51:49.000000000 -0700
+++ glibc-2.3.2-200309260658/sysdeps/ia64/hp-timing.h	2004-06-03 18:46:55.000000000 -0700
@@ -72,11 +72,13 @@
 /* We always assume having the timestamp register.  */
 #define HP_TIMING_AVAIL		(1)

-/* We indeed have inlined functions.  */
-#define HP_TIMING_INLINE	(1)
+/* We indeed have inlined functions but sometimes we need to make a call.  */
+#define HP_TIMING_INLINE	(0)

 /* We use 64bit values for the times.  */
 typedef unsigned long int hp_timing_t;
+int itc_drifting;
+unsigned long hp_gettimestamp(void);

 /* Set timestamp value to zero.  */
 #define HP_TIMING_ZERO(Var)	(Var) = (0)
@@ -91,10 +93,13 @@
 /* That's quite simple.  Use the `ar.itc' instruction.  */
 #define HP_TIMING_NOW(Var) \
   ({ unsigned long int __itc;						      \
+    if (itc_drifting>=0) Var=hp_gettimestamp();				\
+    else {								\
      do									      \
        asm volatile ("mov %0=ar.itc" : "=r" (__itc) : : "memory");	      \
-     while (REPEAT_READ (__itc));					      \
-     Var = __itc; })
+      while (REPEAT_READ (__itc));					      \
+      Var = __itc; }							\
+   })

 /* Use two 'ar.itc' instructions in a row to find out how long it takes.  */
 #define HP_TIMING_DIFF_INIT() \
Index: glibc-2.3.2-200309260658/sysdeps/unix/sysv/linux/ia64/Makefile
===================================================================
--- glibc-2.3.2-200309260658.orig/sysdeps/unix/sysv/linux/ia64/Makefile	2003-06-02 12:56:22.000000000 -0700
+++ glibc-2.3.2-200309260658/sysdeps/unix/sysv/linux/ia64/Makefile	2004-06-03 18:46:55.000000000 -0700
@@ -7,6 +7,11 @@
 gen-as-const-headers += sigcontext-offsets.sym
 endif

+ifeq ($(subdir), csu)
+sysdep_routines += get_clockfreq
+static-only-routines += get_clockfreq
+endif
+
 ifeq ($(subdir),misc)
 sysdep_headers += sys/io.h
 sysdep_routines += ioperm clone2
@@ -16,6 +21,15 @@
 sysdep-dl-routines += dl-static
 sysdep_routines += $(sysdep-dl-routines)
 sysdep-rtld-routines += $(sysdep-dl-routines)
+sysdep-dl-routines += get_clockfreq
+endif
+
+ifeq ($(subdir),malloc)
+libmemusage-sysdep_routines += get_clockfreq
+endif
+
+ifeq ($(subdir),posix)
+sysdep_routines += get_clockfreq
 endif

 # This is a crude attempt to silence the compiler which complains about
Index: glibc-2.3.2-200309260658/sysdeps/unix/sysv/linux/ia64/hp-timing.c
===================================================================
--- glibc-2.3.2-200309260658.orig/sysdeps/unix/sysv/linux/ia64/hp-timing.c	1969-12-31 16:00:00.000000000 -0800
+++ glibc-2.3.2-200309260658/sysdeps/unix/sysv/linux/ia64/hp-timing.c	2004-06-03 18:46:55.000000000 -0700
@@ -0,0 +1,49 @@
+/* Support for high precision, low overhead timing functions.  IA-64 version.
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2001.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+int itc_is_drifting(void)
+{
+	int itc_drifting=0;
+
+	int fd = open ("/proc/sal/itc_drift", O_RDONLY);
+
+	if (__builtin_expect (fd != -1, 1))
+	{
+		char buf[16];
+		/* We expect the file to contain a single digit followed by
+		   a newline.  If the format changes we better not rely on
+		   the file content.  */
+		if (read (fd, buf, sizeof buf) != 2 || buf[0] != '0' || buf[1] != '\n')
+			itc_drifting=1;
+		close (fd);
+	}
+	return itc_drifting;
+}
+
+#include <sysdeps/ia64/hp-timing.c>
+


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