[cgl_discussion] Re: HR Timer fixes for TLT

george anzinger george at mvista.com
Wed Sep 11 10:16:57 PDT 2002


"Cahill, Ben M" wrote:
> 
> Sounds good . . . thanks!

When I tried to check it in, I found the tree frozen.  Patch
is attached if you need/want to push on.

-g

> 
> -- Ben --
> 
> -----Original Message-----
> From: george anzinger [mailto:george at mvista.com]
> Sent: Tuesday, September 10, 2002 6:30 PM
> To: Cahill, Ben M
> Cc: Corey Minyard
> Subject: Re: HR Timer fixes for TLT
> 
> "Cahill, Ben M" wrote:
> >
> > No, I was going to generate one regarding IPMI driver CPU performance, but
> > now there's controversy about including IPMI in CGLE stuff . . . so no.
> >
> >  . . . do you need a bugzilla, or can you just merge it in with the other
> > stuff you were talking about?
> 
> I will do what ever.  I just wanted to make sure that, it
> there was a bug, that I properly referenced it.
> 
> Status: Done, but failed in testing (so many options).
> Should be able to get it in today.
> 
> -g
> >
> > -- Ben --
> >
> > -----Original Message-----
> > From: george anzinger [mailto:george at mvista.com]
> > Sent: Monday, September 09, 2002 7:30 PM
> > To: Cahill, Ben M
> > Cc: Corey Minyard
> > Subject: Re: HR Timer fixes for TLT
> >
> > "Cahill, Ben M" wrote:
> > >
> > > Hi George,
> > >
> > > Thanks . . . I'm the IPMI guy . . . yes, the OSDL tree is the place.
> > >
> > > Could you let me know when you've got it in place??
> >
> > Sure.  Do you have a Bug to hang it on?
> >
> > -g
> > >
> > > Thanks!
> > >
> > > -- Ben --
> > >
> > > -----Original Message-----
> > > From: george anzinger [mailto:george at mvista.com]
> > > Sent: Monday, September 09, 2002 5:17 PM
> > > To: Corey Minyard
> > > Cc: Cahill, Ben M
> > > Subject: Re: HR Timer fixes for TLT
> > >
> > > Corey Minyard wrote:
> > > >
> > > > George,
> > > >
> > > > I was wondering if you had submitted those HR timer changes to the TLT
> > > > base.  We need them for IPMI, but the IPMI person doesn't feel
> > > > comfortable applying those changes.  Could you put them in?  If you
> need
> > > > a resend, I can do that.
> > > >
> > > > Also, the patch required adding "arch/i386/kernel/time.c" into the
> > > > export-objs in the makefile.  I'm not sure if the patch has that, so
> you
> > > > may want to double-check.
> > > >
> > > First I assume you mean the OSDL tree or what ever they call
> > > it.  The TLT tree is closed.
> > >
> > > I had not realized this work was for this tree.  I would
> > > like to make a bit of a change, but should be able to get it
> > > in today, with luck.  I don't think the change will affect
> > > your code.  What I plan to do is to gather all the export
> > > stuff in a structure and export that.  I will provide macros
> > > to make the external names the same as they are now.
> > >
> > > The real reason I want to do this is these are the key
> > > numbers that need to be tweaked to do the NTP stuff at the
> > > hardware clock level and I want to provide a uniform
> > > interface for this change which I expect to push as a follow
> > > on patch.
> > >
> > > There is also an active bug I need to fix...
> > > --
> > > George Anzinger   george at mvista.com
> > > High-res-timers:
> > > http://sourceforge.net/projects/high-res-timers/
> > > Preemption patch:
> > > http://www.kernel.org/pub/linux/kernel/people/rml
> >
> > --
> > George Anzinger   george at mvista.com
> > High-res-timers:
> > http://sourceforge.net/projects/high-res-timers/
> > Preemption patch:
> > http://www.kernel.org/pub/linux/kernel/people/rml
> 
> --
> George Anzinger   george at mvista.com
> High-res-timers:
> http://sourceforge.net/projects/high-res-timers/
> Preemption patch:
> http://www.kernel.org/pub/linux/kernel/people/rml

-- 
George Anzinger   george at mvista.com
High-res-timers: 
http://sourceforge.net/projects/high-res-timers/
Preemption patch:
http://www.kernel.org/pub/linux/kernel/people/rml
-------------- next part --------------
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/Documentation/high-res-timers/lib/Makefile linux/Documentation/high-res-timers/lib/Makefile
--- src/Documentation/high-res-timers/lib/Makefile	Wed Aug 14 14:22:57 2002
+++ linux/Documentation/high-res-timers/lib/Makefile	Wed Aug 14 17:40:35 2002
@@ -12,11 +12,10 @@
 clean:
 	rm -f *.o *.a *.so *~ core .depend t--* tmp
 
-tf = t--st.c
-.depend: $(SOURCES)
+.depend: $(SOURCES) test_itimerspec
 	$(CC) $(CPPFLAGS)  -M $(SOURCES) | \
 		sed -e '/:/s|^[^ :]*|$(LIBPOSIXTIME)(&)|' > .depend
-	rm -f $(tf)
+	chmod +x test_itimerspec
 	./test_itimerspec $(CC) $(CPPFLAGS) &>/dev/null
 	make
 
Binary files src/Documentation/high-res-timers/lib/libposixtime.so and linux/Documentation/high-res-timers/lib/libposixtime.so differ
Binary files src/Documentation/high-res-timers/tests/2timer_test and linux/Documentation/high-res-timers/tests/2timer_test differ
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/Documentation/high-res-timers/tests/Makefile linux/Documentation/high-res-timers/tests/Makefile
--- src/Documentation/high-res-timers/tests/Makefile	Wed Aug 14 14:22:58 2002
+++ linux/Documentation/high-res-timers/tests/Makefile	Mon Aug 19 11:13:15 2002
@@ -47,9 +47,10 @@
 		clock_gettimetest.c \
 		clock_settimetest.c \
 		clock_gettimetest2.c \
-		clock_gettimetest3.c \
+	        clock_gettimetest3.c \
 		clock_gettimetest4.c \
-		clock_nanosleeptest.c
+		clock_nanosleeptest.c \
+	        performance.c
 
 PROGS = $(SOURCES:.c=) 
 
@@ -67,6 +68,7 @@
 .depend depend: $(SOURCES)
 	$(CC) -M $(CPPFLAGS) $(SOURCES) | \
 		sed -e '/:/s|\(^[^ :]*\)\.o|\1|' > .depend
+	chmod +x do_test
 	make
 
 # This above make insures that we have the .depend when doing the build.
Binary files src/Documentation/high-res-timers/tests/clock_getrestest and linux/Documentation/high-res-timers/tests/clock_getrestest differ
Binary files src/Documentation/high-res-timers/tests/clock_gettimetest and linux/Documentation/high-res-timers/tests/clock_gettimetest differ
Binary files src/Documentation/high-res-timers/tests/clock_gettimetest2 and linux/Documentation/high-res-timers/tests/clock_gettimetest2 differ
Binary files src/Documentation/high-res-timers/tests/clock_gettimetest3 and linux/Documentation/high-res-timers/tests/clock_gettimetest3 differ
Binary files src/Documentation/high-res-timers/tests/clock_gettimetest4 and linux/Documentation/high-res-timers/tests/clock_gettimetest4 differ
Binary files src/Documentation/high-res-timers/tests/clock_nanosleeptest and linux/Documentation/high-res-timers/tests/clock_nanosleeptest differ
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/Documentation/high-res-timers/tests/clock_nanosleeptest.c linux/Documentation/high-res-timers/tests/clock_nanosleeptest.c
--- src/Documentation/high-res-timers/tests/clock_nanosleeptest.c	Wed Aug 14 14:22:58 2002
+++ linux/Documentation/high-res-timers/tests/clock_nanosleeptest.c	Wed Aug 14 17:56:34 2002
@@ -132,8 +132,8 @@
 	for (i = 0; i < 20; i++) {
                 double diff;
 		Try(clock_gettime(clock, &ts));
-		ts.tv_nsec += 150000;
-
+                ts.tv_nsec += 150000;
+                roundtores(&ts,1);  // cheap normalization
 		Try(clock_nanosleep(clock, TIMER_ABSTIME, &ts, NULL));
 
 		Try(clock_gettime(clock, &ns));
Binary files src/Documentation/high-res-timers/tests/clock_settimetest and linux/Documentation/high-res-timers/tests/clock_settimetest differ
Binary files src/Documentation/high-res-timers/tests/jitter_test and linux/Documentation/high-res-timers/tests/jitter_test differ
Binary files src/Documentation/high-res-timers/tests/performance and linux/Documentation/high-res-timers/tests/performance differ
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/Documentation/high-res-timers/tests/performance.c linux/Documentation/high-res-timers/tests/performance.c
--- src/Documentation/high-res-timers/tests/performance.c	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/high-res-timers/tests/performance.c	Tue Aug 27 13:16:14 2002
@@ -0,0 +1,792 @@
+#ifdef comments
+/*
+The performance measurements are:
+
+1.) time to activate a timer with 0 to N timers active in the system
+    (plot time expecting it to have some minor slope) where N is 3000
+    timers.
+
+1a) Do same timer measurement with the timer list set to 512, 1024,
+    2048, and 4192
+
+2.) Measure the preemption operations with timers expiring at random
+    intervals.
+
+3.) Measure the preemption operations with small numbers of timers to
+    large numbers of timers expiring at the same time.
+
+Lets see.  There are two ways of doing this. 
+
+1.) We measure the time to activate timer N as we do each timer from 1
+    to N.  We do this several times take the average, min, max for each
+    N.
+
+2.) For each N we loop for M times activating and deactivating a timer,
+    again measuring the min, max, average.
+
+3.) (I lied about the number of ways :) We do a combo of the above.
+
+The data we gather here is min, max, average for each of N timers. 
+
+So much for test 1.  Test 2 requires some method of measuring the actual
+    preemption times.  Suppose we create a thread that does the
+    measurement.  By using a thread, we can keep track of the number of
+    timers that expire during each period.  The thread could, each time
+    period, get the preemtion info from /proc and put the two together
+    in a data structure/file for subsequent display.
+
+Test 3 is a version of Test 2 with out the random expire times.
+
+An additional test might be to do tests 2 & 3 with both high res and low
+    res clocks.  For that matter, test 1 should do this also.  Should we
+    also consider MONOTONIC as well as REALTIME clocks?
+
+Ok, so, then what are the variables we want to work with and what is the
+    output:
+
+  Test 1,1a
+    Number of timers
+    Number of times to loop thru the N timers
+    Number of times to activate each timer each time thru the loop
+    CLOCK to use
+
+    Produces a file of trupples (min, max, average) for each N.
+
+  Test 2,3
+    Bound of the expire time (i.e. how long will the test run)
+    Number of times to run the above (again keeping min, max, average)
+    Interval over which to measure (e.g. for each 10ms)
+    CLOCK to use
+
+    Produces a file of trupples (min, max, average) for each N expires 
+   
+
+*/
+#endif
+#include <sys/mman.h>
+#include <string.h>
+#include "../lib/posix_time.h"
+
+#include "utils.h"
+#define FALSE 0
+#define TRUE 1
+static char *VERSION = "1.0.0 <20020827.1316.24>";
+static char *program_name = NULL;
+extern void print_usage(FILE*, int);
+static int verbose = FALSE;
+struct timeval start, stop;
+char * ploting;
+#ifdef debug
+#undef debug
+#define debug(a) do {a}while (0)
+#else
+#define debug(a) do {} while (0)
+#endif
+
+/*
+ * A function to caculate the new running average given the old (av),
+ * the new (new) and the new item count (count).
+ * av and new should be "double", while count will usually be int.
+ */
+#define run_av(av, new, count) (((av *(count - 1)) + new)/count)
+
+/*
+ * Ever notice that you can do #foo to get a string but there is 
+ * no way to get a character constant (i.e. 'a') in a macro.  You either
+ * have it or you don't :(
+ *
+ * Ok, here is where we define the run time options.  This one definition
+ * is used three times, the usage print out, the short options init and
+ * the long options init.  The parameters are:
+ * the short options character constant, the same char as is, i.e.
+ * constant, the long version, NIL if no value, PAR if a value should
+ * follow, a user friendly info string for the usage print out.
+ */
+#define OPTIONS \
+OPTION_H('h',h, help,        NIL, Display this usage information (try -vh).\n) \
+OPTION_H('v',v, verbose,     NIL, print verbose data.\n) \
+OPTION_H('n',n, timers,      PAR, Number of timers to work with (3000).\n) \
+OPTION_H('l',l, loop,        PAR, Number of times to loop over all timers (5).\n) \
+OPTION_H('i',i, iterate,     PAR, Number of times to do each timer (5).\n) \
+OPTION_H('r',r, range,       PAR, Range of timer values in milliseconds (no. tmrs *20ms).\n) \
+OPTION_H('m',m, tim-min,     PAR, Minimum timer value to use in milliseconds (10,000).\n) \
+OPTION_H('a',a, abs,         NIL, Use absolute timers.\n) \
+OPTION_H('c',c, clear,       NIL, Timers will be seperately cleared prio to arming.\n) \
+OPTION_H('P',P, priority,    PAR, Use priority X on the test (50).\n) \
+OPTION_H('F',F, fifo,        NIL, Use SCHED_FIFO algorithm.\n) \
+OPTION_H('R',R, rr,          NIL, Use SCHED_RR algorithm (default = SCHED_FIFO).\n) \
+OPTION_H('L',L, low,         NIL, Use low resolution clock (high res).\n) \
+OPTION_H('M',M, mono,        NIL, Use CLOCK_MONOTONIC (CLOCK_REALTIME).\n) \
+OPTION_H('g',g, gnu_plot,    NIL, Produce gnu_plot file on stdout.\n) \
+OPTION_H('t',t, test2,       NIL, Do test 2 (see -vh).\n)  \
+OPTION_H('V',V, version,     NIL, Print version of this program.\n) \
+
+char *verbose_help = 
+   "\n"
+   "Test 1 (use -t to get test 2, for which see comments below)\n\n"
+   "This program collects data on timer arm time against number of active\n"
+   "timers.  It also keeps track of timer completions while it is\n"
+   "measuring the arming times.  It provides its output in a form\n"
+   "compatible with gnuplot.  Several runs through the timers are made with\n"
+   "each run doing several timer arms.  The minimum, maximum and average\n"
+   "times are kept for each timer count.  The data file contains space\n"
+   "delimited data in the following order: count, average, min, max,\n"
+   "completions.  The completions column is the number of timer\n"
+   "completions while measuring the arm times for that timer.  This\n"
+   "column is absent if the count is zero.  All times are in microseconds.\n"
+   "A suggest gnuplot directive is:\n"
+   "'plot <file> w lines, plot <file> using 1:5'.\n"
+   "This will put the timer completions on the plot as points only when\n" 
+   "there are some.  You could also use:\n"
+   "'plot <file> w error, plot <file> using 1:5'.\n"
+   "to plot each value as an error bar.\n"
+   "\n"
+   "Comments on the parameters: Each of the <timers> is armed <iterate>\n"
+   "times on each of <loop> loops, thus there are <iterate> * <loop>\n"
+   "times.  \n"
+   "\n"
+   "The timer must be disarmed between each of the <loop> passes, but\n"
+   "may be left armed for the <iterate> loop.  You can control this with\n"
+   "the <clear> parameter.  \n"
+   "\n"
+   "The time to use for each timer is generated using a random number\n"
+   "generator constrained to give times from <tim-min> to <tim-min> +\n"
+   "<range>.  The default value of <tim-min> precludes timers from\n"
+   "completing during the test, however, this need not be the case.  \n"
+   "\n"
+   "By constraining <range> you can defeat the timer hash, causing all\n"
+   "timers to be inserted in the same hash bucket. (Hash buckets are\n"
+   "1/HZ seconds in size.)  Since the test take well over 1/HZ seconds,\n"
+   "you will need to use the <abs> option to actually force all timers\n"
+   "to the same bucket.  Without the <abs> option you should notice a\n"
+   "sawtooth graph with each 1/HZ (in test time, which is not kept)\n"
+   "representing a tooth, due to the relative alarm times.\n"
+   "\n"
+   "It is recommended that this test be run as a real time task to avoid\n"
+   "its being preempted by other system activity.  See <priority>,\n"
+   "<fifo> and <rr>.  If none of these are given, the task will inherit\n"
+   "its parents scheduling attributes.\n"
+   "\n"
+   "You can also choose the POSIX clock and resolution.  Default is\n"
+   "CLOCK_REALTIME_HR.  <low> change removes the '_HR' and <mono>\n"
+   "changes 'REALTIME' to 'MONOTONIC'.\n\n"
+   "The -g option will cause gnuplot commands to be emitted in front of \n"
+   "the data such that the output can be piped to gnuplot.  Without the \n"
+   "-g these commands will be replaced with comments such that you can \n"
+   "enter your own commands to gnuplot and \"plot\" the output.\n\n"
+   "Test 2 is a generates a plot of preemption time against number of timers\n"
+   "completing on the same tick.  The preemption time is gathered from\n"
+   "the preemption \"stats\" patch.  This test is slow as it needs to wait\n"
+   "for the timers to complete.  For this test N timers are armed in ABSOLUTE\n"
+   "mode for N running from 0 to <-n> timers.  The run will be done <-l> \n"
+   "times and the results averaged to give the same format as the test 1\n"
+   "file except for the completion info.  For this test the \n"
+   "-i, -r, -a, -c, and -m options are meaningless.\n"
+
+;
+
+#define OPTION_U USAGE
+#include "utils.h"
+void print_usage(FILE* stream, int exit_code)
+{
+        fprintf (stream,"%s version %s\n", program_name, VERSION);
+        if(verbose){
+                fprintf(stream,"%s",verbose_help);
+        }
+        fprintf (stream, "Usage:  %s options\n", program_name);
+        fprintf (stream, OPTIONS);
+        exit (exit_code);
+}
+
+
+int clock_index = 0;
+#define MONOTONIC 2
+#define LOW_RES 1
+/* 
+ * We know about the following clocks:
+ */
+clock_t clocks[] = {CLOCK_REALTIME_HR, 
+                    CLOCK_REALTIME, 
+                    CLOCK_MONOTONIC_HR,
+                    CLOCK_MONOTONIC};
+/*
+ * Which have these names:
+ */
+char * clock_names[] = {"CLOCK_REALTIME_HR", 
+                        "CLOCK_REALTIME", 
+                        "CLOCK_MONOTONIC_HR",
+                        "CLOCK_MONOTONIC"};
+int no_timers = 3000;
+int main_loop = 5;
+int iterate_loop = 5;
+int clear_flag = 0;
+int high_bound = 0;
+int mypriority = 0;
+int expirations = 0;
+int line = 90;  // take down by 5 for each line in the graph
+#define new_line() line -= 5
+int test1 = TRUE;
+int expire = 0;
+int gnu_plot = 0;
+int sched_policy = SCHED_OTHER;
+double timer_range = 0.0;
+double min_timer = 10000.0;
+int absf = 0;
+#define SIGNAL1 SIGRTMIN //SIGUNUSED
+struct timespec tm, ts, rs, tb ;
+struct itimerspec tt ;
+struct itimerspec * rtime(struct itimerspec * t)
+{
+        double tim = (((double)random() *  timer_range) /RAND_MAX) + min_timer;
+
+        t->it_value.tv_sec =tim;
+        t->it_value.tv_nsec =  ((tim - t->it_value.tv_sec) * NSEC_PER_SEC);
+        if( absf ) timersum(&t->it_value,&t->it_value,&tb);
+        return t;
+}
+
+#define IF_V(a) do {if( verbose ) { a };}while(0)
+#define start() expirations = 0;Try(clock_gettime(clocke, &ts))
+#define elapsed() ({Try(clock_gettime(clocke, &rs));\
+                     expire = expirations; \
+                     timerdiff(&rs,&ts);\
+                   })
+#define for_each(a) for (t = 0; t < no_timers; t++){a;}
+#define for_main(a) for (o = 0; o < main_loop; o++){ a; }
+#define for_iter(a) for (i = 0; i < iterate_loop; i++){ a; } 
+#define for_all(a)  for_main( for_each (for_iter( a) ))
+
+#define timerx() timer[t].result[o].in_loop[i]
+
+void timer1_handler(int signo, siginfo_t * info, void * ptr)
+{
+        IF_V(printf("In handler\n"););
+	expirations++;
+}
+
+
+void do_test1(void)
+{
+        struct {
+                struct result {
+                        double in_loop[iterate_loop];
+                } result[main_loop];
+        } timer[no_timers];
+        timer_t  timer_id[no_timers];
+        int expires[no_timers];
+        int i,o,t;
+        clock_t clockt = clocks[clock_index];
+        clock_t clocke = CLOCK_MONOTONIC;
+        struct sigevent  sigev;
+        sigset_t new_mask,old_mask;
+        struct sigaction oldact,sigact;
+        struct itimerspec tc = {{0,0},{0,0}};
+        
+        /* 
+         * For this test we don't want any signals, so
+         * just ignor them.
+         */
+        sigact.sa_sigaction = timer1_handler;
+        sigact.sa_flags = SA_SIGINFO;
+        Try(sigemptyset(&sigact.sa_mask));
+
+	sigaddset(&new_mask, SIGNAL1);
+	Try(sigprocmask(SIG_UNBLOCK, &new_mask, &old_mask));
+        /*
+         * Set up a random number generator
+         */
+        start();
+        srandom(ts.tv_sec);
+        Try(clock_gettime(clockt, &tb));
+ 
+        Try(sigaction(SIGNAL1,&sigact,&oldact));
+        sigev.sigev_notify = SIGEV_SIGNAL;
+        sigev.sigev_signo = SIGNAL1;
+        start();
+        for_all( timerx() = 0.0);
+        IF_V(printf(" Result array (%d bytes) cleared in %12.9f sec \n",
+                    main_loop*iterate_loop*no_timers*(sizeof(double)),
+                                                      elapsed()););
+
+        for_each (
+                Try(timer_create(clockt, &sigev, &timer_id[t]));
+                expires[t] = 0;
+                );
+        for_main( 
+                for_each( 
+                        for_iter(
+                                if( clear_flag ){ 
+                                        Try(timer_settime(timer_id[t], 
+                                                          0, &tc, NULL));
+                                }
+                                start();
+                                Try(timer_settime(timer_id[t], 
+                                                  absf, rtime(&tt), NULL));
+                                timerx() = elapsed();
+                                expires[t] = expire;
+                                );
+                        );
+                for_each(
+                        Try(timer_settime(timer_id[t], 0, &tc, NULL));
+                        );
+                );
+     
+        /*
+         * Ok, the test is done, clean up the mess and push out the
+         * data.
+         */
+        for_each (Try(timer_delete(timer_id[t])););
+        /*
+         * don't forget to restore the signal system
+         */
+        Try(sigaction(SIGNAL1,&oldact,NULL));
+        /*
+         * Here is where we write out the data.  All
+         * the numbers are floating point.
+         */
+        printf("%splot \"-\" w lines \n", gnu_plot ? "" : "#");
+
+
+        for_each(
+                double high = 0.0;
+                double low  = 1000;
+                double sum  = 0.0;
+                double scale = 1000000;  // values in micro seconds
+                int ppt = iterate_loop + main_loop;
+                for_main(
+                        for_iter(
+                                double v = timerx();
+                                
+                                sum += v;
+                                if( v > high) high = v;
+                                if( v < low)  low  = v;
+                                );
+                        );
+                if(expires[t]) {
+                        printf( "%d %12.9f %12.9f %12.9f %d\n",
+                                t,
+                                sum * scale/ ppt,
+                                low * scale,
+                                high * scale,
+                                expires[t]);
+                }else{
+                        printf( "%d %12.9f %12.9f %12.9f\n",
+                                t,
+                                sum * scale/ ppt,
+                                low * scale,
+                                high * scale);
+                }
+                );
+
+        return;
+}
+
+/*
+ * Test 2 is to generate data for a graph of preemption time against
+ * timer completions.  We set up N timers to complete at the same
+ * time and then wait for that time.  We then read the preemption
+ * stats in /proc and see how big a hit we took.  For this test we 
+ * will not allow much in the way of control as a timer competion 
+ * is a timer completion.  We will try and fine tune the set up time
+ * to allow us to get all the timers armed prior to the expire time.
+ * This will take longer as N gets larger.  We will test what this
+ * is for N=max and assume it is linear in N (if it is not we will be
+ * erroring on the right side).  We will do the whole test M times
+ * and produce a gnu_plot error file (i.e. N ave min max).
+ */
+#undef timerx
+#undef for_all
+//#define for_each(a) for (t = 0; t < no_timers; t++){a;}
+//#define for_main(a) for (o = 0; o < main_loop; o++){ a; }
+#define for_all(a)  for_main( for_each(  a ))
+#define for_timers(a) for (l = 0; l <= t; l++){a;}
+
+#define timerx() timer[t].result[o]
+#define wait_t() timer[t].wait_time[o]
+
+struct itimerspec * etime(struct itimerspec * t, double tim)
+{
+        t->it_value.tv_sec =tim;
+        t->it_value.tv_nsec =  ((tim - t->it_value.tv_sec) * NSEC_PER_SEC);
+        roundtores(&t->it_value,10000000);
+        timersum(&t->it_value,&t->it_value,&ts);
+        return t;
+}
+#define  wait_for_expire(new_mask) sigwaitinfo(&new_mask, &info);
+
+#define FILEN "/proc/latencytimes"
+#define BUF_SIZE 4048
+
+long get_proc_latency(int count)
+{
+        char buff[BUF_SIZE];
+        int rd;
+        long n, rtn;
+        char * loc, * end;
+        int fd = Try(open(FILEN, O_RDONLY));
+
+        rd = Try(read(fd, &buff[0], BUF_SIZE));
+        if (rd >= BUF_SIZE){
+                printf("%s buffer size too small (%d)\n", FILEN, BUF_SIZE);
+        }
+        n = Try(read(fd, &n, sizeof(n)));
+        if ( n ) {
+                printf("Failed to find expected EOF on %s\n", FILEN);
+        }
+        close(fd);
+        buff[rd] = 0;
+        /*
+         * This is a dirty little bit of code to get the worst case 
+         * latency from the above buffer.  It will be the number just
+         * after the string "end line/file".  There will be a new line
+         * here AND, if SMP there may be more than one of them.  Find
+         * them all and return the biggest.  Units will be microseconds.
+         */
+
+        rtn = 0;
+        end = buff + rd;
+        loc = buff;
+        while (loc < end){
+                char mstring[] = "end line/file";
+                loc = strstr(loc, mstring);
+                if( ! loc )
+                        break;
+                loc += sizeof(mstring);
+                n = strtol(loc, &loc, 10);
+                if ( n > rtn) rtn = n;
+        }
+        if( count > 100 && count > rtn + rtn) {
+                printf("Found %d with count %d from:\n%s", (int)rtn, count, buff);
+        }
+        return rtn;
+        
+}
+
+void do_test2(void)
+{
+        struct result {
+                double result[main_loop];
+                double wait_time[main_loop];
+        } timer[no_timers];
+        timer_t  timer_id[no_timers];
+//       int expires[no_timers];
+        int l,o,t;
+        clock_t clockt = clocks[clock_index];
+        clock_t clocke = CLOCK_MONOTONIC;
+        double max_setup_time, setup_per;
+        struct sigevent  sigev;
+        //sigset_t new_mask,old_mask;
+        struct sigaction oldact,sigact;
+        struct itimerspec tc = {{0,0},{0,0}};
+        struct itimerspec rm;
+        struct timespec tm = {0,20000000}, tz  = {0,0};
+        WAIT_VARS();
+
+        /* 
+         * For this test we will do a sig wait so first block them.
+         */
+        sigact.sa_sigaction = timer1_handler;
+        sigact.sa_flags = SA_SIGINFO;
+
+        Try(clock_gettime(clockt, &tb));
+ 
+        Try(sigaction(SIGNAL1,&sigact,&oldact));
+        wait_setup( SIGNAL1);
+        sigev.sigev_notify = SIGEV_SIGNAL;
+        sigev.sigev_signo = SIGNAL1;
+        start();
+        for_all( timerx() = 0.0);
+        IF_V(printf(" Result array (%d bytes) cleared in %12.9f sec \n",
+                    main_loop*iterate_loop*no_timers*(sizeof(double)),
+                                                      elapsed()););
+
+        for_each (
+                Try(timer_create(clocke, &sigev, &timer_id[t]));
+//               expires[t] = 0;
+                );
+        start();
+        for_each(
+                
+                Try(timer_settime(timer_id[t], TIMER_ABSTIME, etime(&tt,60.0), 
+                                  NULL));
+                );
+        max_setup_time = elapsed();
+        setup_per = max_setup_time / no_timers;
+        IF_V(
+                printf("# Set up time for %d timers %12.9f seconds or \n"
+                       "%12.9f seconds per timer.\n", 
+                       no_timers, max_setup_time, max_setup_time / no_timers););
+        //setup_per *= 2.0; // use double to be safe
+
+        // clear all the timers
+        for_each(
+                Try(timer_settime(timer_id[t], 0, &tc, NULL));
+                ); 
+        start();
+        get_proc_latency(0); // Clear the latency counters
+        IF_V(
+                printf("Get latency takes %12.9f seconds.\n",elapsed());
+                );
+
+        for_main(
+                for_each(
+                        start();
+                        get_proc_latency(0); // Clear the latency counters
+                        etime(&tt, (setup_per * t) + 0.01); 
+                        
+                        for_timers(
+                                Try(timer_settime(
+                                            timer_id[l], TIMER_ABSTIME, 
+                                            &tt, 
+                                            NULL));
+                                );
+                        IF_V( {
+                                struct itimerspec tl;
+                                Try(timer_gettime(timer_id[0],&tl));
+                                if(timerdiff(&tl.it_value,&tc.it_value) == 0.0){
+                                        printf("Timers already expired!"
+                                               "  Consider runing at "
+                                               "higher priority.\n" );
+                                }
+                                printf(".");fflush(stdout);
+                        });
+                        //get_proc_latency(); // Clear the latency counters
+                        wait_sync();  // wait for first signal
+                        clock_nanosleep(clocke, 0, &tm, NULL);
+                        for_timers(      // clear the timers
+                                Try(timer_settime(timer_id[l], TIMER_ABSTIME, 
+                                                  &tc, 
+                                                  &rm));
+                                if (rm.it_value.tv_sec + rm.it_value.tv_nsec){
+                                        printf("Oops!  Time remains on "
+                                               "%d %12.9f secs\n", 
+                                               l, timerdiff(&rm.it_value, &tz));
+                                }
+                                );
+                        timerx() = get_proc_latency(t);
+                        wait_flush();  // flush any left over signals
+                        );
+                );
+        /*
+         * Ok, the test is done, clean up the mess and push out the
+         * data.
+         */
+        for_each (Try(timer_delete(timer_id[t])););
+        /*
+         * Here is where we write out the data.  All
+         * the numbers are floating point.
+         */
+        printf("%splot \"-\" w lines \n", gnu_plot ? "" : "#");
+        for_each(
+                double high = 0.0;
+                double low  = 1000;
+                double sum  = 0.0;
+                double scale = 1.0;
+                double ppt =  main_loop;
+                for_main(
+                        double v = timerx();
+                        sum += v;
+                        if( v > high) high = v;
+                        if( v < low)  low  = v;
+                        /*  wsum += w;
+                        if( w > whigh) whigh = w;
+                        if( w < wlow)  wlow  = w; */
+                        );/*%12.9f %12.9f %12.9f*/
+                printf( "%d %12.9f %12.9f %12.9f  \n",
+                        t,
+                        sum * scale/ ppt,
+                        low * scale,
+                        high * scale
+                        );
+                );
+
+        return;
+                
+ 
+
+}
+
+
+#define OPTION_U LONG
+#include "utils.h"
+int main(int argc, char *argv[])
+{        
+        int next_option;
+        pid_t mypid = getpid();
+        struct sched_param sched_pr;
+        //const char* const short_options = "m:hfvrnpP:b:V";
+        const struct option long_options[] = {
+                OPTIONS
+                { NULL,            0, NULL,  0 }  /* Required at end of array.  */
+        };
+#define OPTION_U SHORT
+#include "utils.h"
+        const char* const short_options = OPTIONS;
+        program_name = argv[0];
+
+        do {
+        	next_option = getopt_long(argc, argv, short_options,
+		     long_options, NULL);
+                switch (next_option) {
+                   case 'h':
+                        print_usage (stdout, 0);
+	   	   case 'v':
+			verbose = TRUE;
+			break;
+                   case 'n': 
+                        no_timers = atol(optarg);
+                        break;
+                   case 'l': 
+                        main_loop = atol(optarg);
+                        break;
+                   case 'i': 
+                        iterate_loop = atol(optarg);
+                        break;
+                    case 'r': 
+                        high_bound = atol(optarg);
+                        break;
+                    case 'm': 
+                        min_timer = atol(optarg);
+                        break;
+	   	   case 'a':
+			absf = TIMER_ABSTIME;
+			break;
+	   	   case 'c':
+			clear_flag = TRUE;
+			break;
+                   case 'P': 
+                        mypriority = atoi(optarg);
+                        break;
+                   case 'F': 
+                        sched_policy = SCHED_FIFO;
+                        break;
+                   case 'R': 
+                        sched_policy = SCHED_RR;
+                        break;
+                   case 'L': 
+                        clock_index |= LOW_RES;
+                        break;
+                   case 'M': 
+                        clock_index |= MONOTONIC;
+                        break;
+                   case 'g': 
+                        gnu_plot = TRUE;
+                        break;
+                   case 't': 
+                        test1 = FALSE;
+                        break;
+                   case 'V': 
+                        printf("%s version %s\n", program_name, VERSION);
+                        exit(0);
+                        
+                   case -1:  /* Done with options.  */
+                        break;
+
+                   default: /* Something else: unexpected.  */
+			print_usage(stderr, 1);
+                        exit(-1);
+                }
+        }
+        while (next_option != -1);
+        /*
+        **  Lock all memory pages associated with this process to prevent
+        **  delays due to process memory being swapped out to disk and back.
+        */
+        mlockall( (MCL_CURRENT | MCL_FUTURE) );
+	/*
+         * Run as SCHED_FIFO (real time) priority 99, since I don't
+	 * trust the user to remember.  Decidely unfriendly.  Changed
+         * to default to inherit.  Reports what is in all cases.
+         */
+        if( sched_policy != SCHED_OTHER) {
+                if (!mypriority) mypriority = 50;
+        }else{
+                if (mypriority)  sched_policy = SCHED_FIFO;
+        }
+	sched_pr.sched_priority = mypriority;
+        if(mypriority){
+                Try (sched_setscheduler(mypid, sched_policy, &sched_pr)); 
+        }
+        Try (sched_getparam(mypid, &sched_pr));
+        sched_policy = Try(sched_getscheduler(0));
+
+	Try (gettimeofday(&start, 0));
+        ploting = gnu_plot ? "set label " : "#",
+
+        printf("%s"
+               "\"Calculations done at priority %d "
+               "using %s scheduleing policy.\" at graph 0.1,0.%d\n",
+               ploting,
+               sched_pr.sched_priority,
+               sched_policy == SCHED_OTHER ? "SCHED_OTHER" : 
+               sched_policy == SCHED_FIFO ? "SCHED_FIFO" : 
+               sched_policy == SCHED_RR ? "SCHED_RR" : "UNKNOWN",
+               line
+                );
+        new_line();
+        printf("%s\"Using %d timers on clock %s\"at graph 0.1,0.%d\n",
+               ploting,
+               no_timers,clock_names[clock_index],
+               line
+               );
+        new_line();
+        printf("%sset ylabel \"Microseconds\"\n",
+               gnu_plot ? "" :"#");
+        printf("%sset xlabel \"Number of timers\"\n",
+               gnu_plot ? "" :"#");
+        if( test1 ){
+                printf("%s\"Time to arm vs. number of armed "
+                       "timers\" at graph 0.5, .975 center\n", ploting);
+                printf("%s\"Outer loop is %d and inner loop %d.\"at "
+                       "graph 0.1,0.%d\n",
+                       ploting,
+                       main_loop,iterate_loop,
+                       line
+                        );
+                new_line();
+                if ( high_bound ){
+                        timer_range = (double)high_bound / 1000;
+                }else{
+                        timer_range = .02 * no_timers;
+                }
+                tm.tv_sec = timer_range;
+                tm.tv_nsec =  (timer_range - tm.tv_sec) * NSEC_PER_SEC;
+                min_timer /= 1000;
+                printf("%s\"Maximum timer range is from %12.9f "
+                       "to %12.9f seconds.\" at graph 0.1,0.%d\n",
+                       ploting,
+                       min_timer, 
+                       min_timer + timer_range,
+                       line
+                      );
+                new_line();
+       }else{
+               printf("%s\"Schedule latency vs. number of "
+                      "completing timers\" at graph 0.5, .975 center\n", 
+                      ploting);
+                printf("%s\"Average of %d completions.\"at "
+                       "graph 0.1,0.%d\n",
+                       ploting,
+                       main_loop,
+                       line
+                        );
+                new_line();
+       }
+        /*
+         * Ok, we have all the info from the user and are now ready to
+         * start the tests.  We put the tests in a function so that the 
+         * data array can be dynamicaly allocated.  Since we have it
+         * locked, it is possible to fail here with a SIGSEGV.
+
+         */
+        if ( test1 ){
+                do_test1();
+        } else{
+
+                do_test2();
+        }
+
+
+        exit(0);
+        return 0;
+}
Binary files src/Documentation/high-res-timers/tests/timer_test and linux/Documentation/high-res-timers/tests/timer_test differ
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/Documentation/high-res-timers/tests/utils.h linux/Documentation/high-res-timers/tests/utils.h
--- src/Documentation/high-res-timers/tests/utils.h	Wed Aug 14 14:22:58 2002
+++ linux/Documentation/high-res-timers/tests/utils.h	Fri Aug 23 17:06:06 2002
@@ -1,3 +1,35 @@
+#ifdef OPTION_U
+#if OPTION_U == USAGE
+#undef OPTION_H
+#undef PAR
+#undef NIL
+#define OPTION_H(shortc,short,long,par,desc) "  -"#short" --"#long par"\t"#desc
+#define PAR "\tX"
+#define NIL "\t"
+#undef OPTION_U 
+#elif OPTION_U == LONG
+#undef OPTION_H
+#undef PAR
+#undef NIL
+#undef OPTION_U 
+#define OPTION_H(shortc,short,long,parm,desc)  { #long,parm,NULL,shortc},
+#define PAR 1
+#define NIL 0
+#elif  OPTION_U == SHORT
+#undef OPTION_H
+#undef PAR
+#undef NIL
+#define OPTION_H(shortc,short,long,parm,desc)  #short parm
+#define PAR ":"
+#define NIL
+#undef OPTION_U 
+#else
+#error "OPTION_U error"
+#undef OPTION_U 
+#endif
+#endif // OPTION_U
+#ifndef _UTILS_H
+#define _UTILS_H
 #include <sys/time.h>
 #include <unistd.h>
 #include <signal.h>
@@ -9,8 +41,11 @@
 #include <fcntl.h>
 #include <sched.h>
 #include <assert.h>
-
-#define usleep(time) do{ struct timespec ts = {0 ,time*1000};clock_nanosleep(CLOCK_REALTIME,0,&ts, NULL);}while(0)
+#define _GNU_SOURCE
+#include <getopt.h>
+#define SHORT 1
+#define LONG 2
+#define USAGE 0
 
 /*
  * The "wait" set of macros are designed to allow parent and child to wait on
@@ -191,8 +226,12 @@
  * Since it exits via myperror, above, it will report where the exit
  * came from (source and line number).  Error text will be the expression.
  */
-#define Try(f) ((f) != -1 ? : myperror( #f ))
-#define try(e,f) ((f) != -1 ? no_error(e,#f): my_c_perror( e,#f ))
+#define Try(f) ({int foobas = (f); \
+                if( foobas == -1) \
+                myperror( #f );   \
+                foobas;})
+#define try(e,f) ({int foobas = (f); if( foobas == -1){  my_c_perror( e,#f );\
+                                     } else{  no_error(e,#f);} foobas;})
 /* These two printf() calls take a string with "%d.%03d" somewhere in it
  * and an integer.  They print the interger as a decimal with 3 digits
  * to the right of the decimal point.  Use to print microsecond values
@@ -225,3 +264,4 @@
 #define NO_BITS 10000
 #define NO_WDS ((NO_BITS/32)+1)
 
+#endif
Binary files src/Kerntypes and linux/Kerntypes differ
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- src/arch/i386/kernel/Makefile	Tue May 21 15:09:49 2002
+++ linux/arch/i386/kernel/Makefile	Mon Sep  9 16:46:21 2002
@@ -14,7 +14,7 @@
 
 O_TARGET := kernel.o
 
-export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o traps.o dr_alloc.o
+export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o traps.o dr_alloc.o time.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/include/asm-i386/hrtime-M386.h linux/include/asm-i386/hrtime-M386.h
--- src/include/asm-i386/hrtime-M386.h	Wed Aug 14 14:23:01 2002
+++ linux/include/asm-i386/hrtime-M386.h	Tue Sep 10 16:16:42 2002
@@ -64,14 +64,14 @@
 #define HR_SCALE_NSEC_ARCH 32
 #define HR_SCALE_USEC_ARCH 29
 
-#define arch_to_usec (SC_n(HR_SCALE_ARCH_USEC,1000000)/ \
+#define cf_arch_to_usec (SC_n(HR_SCALE_ARCH_USEC,1000000)/ \
                            (long long)CLOCK_TICK_RATE)
 
 extern inline int arch_cycles_to_usec(long update)
 {
 	return (mpy_sc_n(HR_SCALE_ARCH_USEC, update ,arch_to_usec));
 }
-#define arch_to_nsec (SC_n(HR_SCALE_ARCH_NSEC,1000000000)/ \
+#define cf_arch_to_nsec (SC_n(HR_SCALE_ARCH_NSEC,1000000000)/ \
                            (long long)CLOCK_TICK_RATE)
 
 extern inline int arch_cycles_to_nsec(long update)
@@ -81,19 +81,25 @@
 /* 
  * And the other way...
  */
-#define usec_to_arch (SC_n( HR_SCALE_USEC_ARCH,CLOCK_TICK_RATE)/ \
+#define cf_usec_to_arch (SC_n( HR_SCALE_USEC_ARCH,CLOCK_TICK_RATE)/ \
                                             (long long)1000000)
 extern inline int usec_to_arch_cycles(unsigned long usec)
 {
         return mpy_sc_n(HR_SCALE_USEC_ARCH,usec,usec_to_arch);
 }
-#define nsec_to_arch (SC_n( HR_SCALE_NSEC_ARCH,CLOCK_TICK_RATE)/ \
+#define cf_nsec_to_arch (SC_n( HR_SCALE_NSEC_ARCH,CLOCK_TICK_RATE)/ \
                                             (long long)1000000000)
 extern inline int nsec_to_arch_cycles(long nsec)
 {
         return (mpy_ex32(nsec,nsec_to_arch));
 }
 /*
+ * If this is defined otherwise to allow NTP adjusting, it should
+ * be scaled by about 16 bits (or so) to allow small percentage
+ * changes
+ */
+#define arch_cycles_to_latch(x) x
+/*
  * This function updates base_c0
  * This function is always called under the write_lock_irq(&xtime_lock)
  * It returns the number of "clocks" since the last call to it.
@@ -158,7 +164,14 @@
 #ifdef _INCLUDED_FROM_TIME_C
 int base_c0 = 0;
 int base_c0_offset = 0;
-long cycles_per_jiffies = LATCH;
+struct timer_conversion_bits timer_conversion_bits = {
+        _cycles_per_jiffies: (LATCH),
+        _nsec_to_arch:       cf_nsec_to_arch,
+        _usec_to_arch:       cf_usec_to_arch,
+        _arch_to_nsec:       cf_arch_to_nsec,
+        _arch_to_usec:       cf_arch_to_usec,
+        _arch_to_latch:      1
+};
 int _timer_latch_reset;
 
 #define set_last_timer_cc() (void)(1)
@@ -189,6 +202,7 @@
 	READ_CNT1(c1);
 	base_c0 -= delta;
 
+	new_latch_value = arch_cycles_to_latch( new_latch_value );
         if (new_latch_value < TIMER_DELTA){
                 new_latch_value = TIMER_DELTA;
         }
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/include/asm-i386/hrtime-M586.h linux/include/asm-i386/hrtime-M586.h
--- src/include/asm-i386/hrtime-M586.h	Wed Aug 14 14:23:01 2002
+++ linux/include/asm-i386/hrtime-M586.h	Tue Sep 10 17:28:06 2002
@@ -36,21 +36,11 @@
 
 #ifdef _INCLUDED_FROM_TIME_C
 /*
- * The following four values are not used for machines 
- * without a TSC.  For machines with a TSC they
- * are caculated at boot time. They are used to 
- * calculate "cycles" to jiffies or usec.  Don't get
- * confused into thinking they are simple multiples or
- * divisors, however.  
- */
-unsigned long arch_to_usec; 
-unsigned long arch_to_nsec;
-unsigned long usec_to_arch; 
-unsigned long nsec_to_arch;
-/*
  * This gets redefined when we calibrate the TSC
  */
-long cycles_per_jiffies = LATCH;
+struct timer_conversion_bits timer_conversion_bits = {
+        _cycles_per_jiffies: LATCH
+};
 #endif
 
 /*
@@ -88,11 +78,6 @@
 
 extern unsigned long long base_cpuctr;
 extern unsigned long base_jiffies;
-extern unsigned long usec_to_arch;
-extern unsigned long nsec_to_arch;
-extern unsigned long arch_to_usec;
-extern unsigned long arch_to_nsec;
-extern int arch_to_latch;
 /* 
  * We use various scaling.  The ex32 scales by 2**32, sc_n by the first parm.
  * When working with constants, choose a scale such that x/n->(32-scale)< 1/2.
@@ -138,7 +123,6 @@
 
 #include <asm/io.h>
 
-int arch_to_latch;
 
 #ifndef USEC_PER_SEC
 #define USEC_PER_SEC 1000000
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/include/asm-i386/hrtime-Macpi.h linux/include/asm-i386/hrtime-Macpi.h
--- src/include/asm-i386/hrtime-Macpi.h	Wed Aug 14 14:23:01 2002
+++ linux/include/asm-i386/hrtime-Macpi.h	Tue Sep 10 17:08:06 2002
@@ -62,25 +62,28 @@
 #define HR_SCALE_USEC_ARCH 29
 
 #ifndef  PM_TIMER_FREQUENCY 
-#define PM_TIMER_FREQUENCY  3579545  /* counts per second */
+#define PM_TIMER_FREQUENCY  3579545/*45   counts per second */
 #endif
+#define PM_TIMER_FREQUENCY_x_100  357954545  /* counts per second * 100*/
+
+#define cf_arch_to_usec (SC_32(100000000)/(long long)PM_TIMER_FREQUENCY_x_100)
 extern inline int arch_cycles_to_usec(unsigned long update) 
 {
-	return (mpy_ex32(update ,(SC_32(1000000)/(long long)PM_TIMER_FREQUENCY)));
+	return (mpy_ex32(update ,arch_to_usec));
 }
 /*
  * We need to take 1/3 of the presented value (or more exactly)
- * CLOCK_TICK_RATE /PM_TIMER_FREQUENCY (which is not exactly 1/3)
- * Also we NEVER want to do a div.
+ * CLOCK_TICK_RATE /PM_TIMER_FREQUENCY.  Note that these two timers
+ * are on the same cyrstal so will be EXACTLY 1/3.
  */
-#define clock_over_pm_ex32 SC_32(CLOCK_TICK_RATE)/(long long)PM_TIMER_FREQUENCY
+#define cf_arch_to_latch SC_32(CLOCK_TICK_RATE)/(long long)(CLOCK_TICK_RATE * 3)
 extern inline int arch_cycles_to_latch(unsigned long update)
 {
-        return (mpy_ex32(update ,clock_over_pm_ex32));
+        return (mpy_ex32(update ,arch_to_latch));
 }
 
-#define arch_to_nsec (SC_n(HR_SCALE_ARCH_NSEC,1000000000)/ \
-                           (long long)PM_TIMER_FREQUENCY)
+#define cf_arch_to_nsec (SC_n(HR_SCALE_ARCH_NSEC,100000000000LL)/ \
+                           (long long)PM_TIMER_FREQUENCY_x_100)
 
 extern inline int arch_cycles_to_nsec(long update)
 {
@@ -89,13 +92,13 @@
 /* 
  * And the other way...
  */
-#define usec_to_arch (SC_n( HR_SCALE_USEC_ARCH,PM_TIMER_FREQUENCY)/ \
-                                            (long long)1000000)
+#define cf_usec_to_arch (SC_n( HR_SCALE_USEC_ARCH,PM_TIMER_FREQUENCY_x_100)/ \
+                                            (long long)100000000)
 extern inline int usec_to_arch_cycles(unsigned long usec)
 {
         return mpy_sc_n(HR_SCALE_USEC_ARCH,usec,usec_to_arch);
 }
-#define nsec_to_arch (SC_n( HR_SCALE_NSEC_ARCH,PM_TIMER_FREQUENCY)/ \
+#define cf_nsec_to_arch (SC_n( HR_SCALE_NSEC_ARCH,PM_TIMER_FREQUENCY)/ \
                                             (long long)1000000000)
 extern inline int nsec_to_arch_cycles(unsigned long nsec)
 {
@@ -107,7 +110,14 @@
 #ifdef _INCLUDED_FROM_TIME_C
 
 #include <asm/io.h>
-long cycles_per_jiffies =  ((PM_TIMER_FREQUENCY + HZ/2) / HZ);
+struct timer_conversion_bits timer_conversion_bits = {
+        _cycles_per_jiffies: ((PM_TIMER_FREQUENCY + HZ/2) / HZ),
+        _nsec_to_arch:       cf_nsec_to_arch,
+        _usec_to_arch:       cf_usec_to_arch,
+        _arch_to_nsec:       cf_arch_to_nsec,
+        _arch_to_usec:       cf_arch_to_usec,
+        _arch_to_latch:      cf_arch_to_latch
+};
 int acpi_pm_tmr_address;
 
 
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/include/asm-i386/hrtime.h linux/include/asm-i386/hrtime.h
--- src/include/asm-i386/hrtime.h	Wed Aug 14 14:23:01 2002
+++ linux/include/asm-i386/hrtime.h	Tue Sep 10 17:28:43 2002
@@ -165,7 +165,6 @@
 
 extern int _schedule_next_int(unsigned long jiffie_f,long sub_jiffie_in, int always);
 
-extern long cycles_per_jiffies;
 extern unsigned int volatile latch_reload;
 
 EXTERN int jiffies_intr;
@@ -376,8 +375,7 @@
          * We must be called with irq disabled.
 	 */
 
-	new_latch_value = arch_cycles_to_latch( new_latch_value /*- 
-                                                pit_pgm_correction*/);
+	new_latch_value = arch_cycles_to_latch( new_latch_value );
         if (new_latch_value < TIMER_DELTA){
                 new_latch_value = TIMER_DELTA;
         }
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/include/linux/hrtime.h linux/include/linux/hrtime.h
--- src/include/linux/hrtime.h	Wed Aug 14 14:23:01 2002
+++ linux/include/linux/hrtime.h	Tue Sep 10 17:28:43 2002
@@ -34,6 +34,36 @@
                           struct itimerspec *cur_setting);
 };
 
+/*
+ * This gets filled in at init time, either static or dynamic.
+ * Someday this will be what NTP fiddles with.
+ * Do we need the scale here?  I don't think so, as long as we
+ * do percentage offsets for NTP.
+ */
+struct timer_conversion_bits {
+        unsigned long _arch_to_usec; 
+        unsigned long _arch_to_nsec;
+        unsigned long _usec_to_arch; 
+        unsigned long _nsec_to_arch;
+        long _cycles_per_jiffies;
+        unsigned long _arch_to_latch;
+};
+extern struct timer_conversion_bits timer_conversion_bits;
+/*
+ * The following four values are not used for machines 
+ * without a TSC.  For machines with a TSC they
+ * are caculated at boot time. They are used to 
+ * calculate "cycles" to jiffies or usec.  Don't get
+ * confused into thinking they are simple multiples or
+ * divisors, however.  
+ */
+#define arch_to_usec timer_conversion_bits._arch_to_usec 
+#define arch_to_nsec timer_conversion_bits._arch_to_nsec
+#define usec_to_arch timer_conversion_bits._usec_to_arch 
+#define nsec_to_arch timer_conversion_bits._nsec_to_arch
+#define cycles_per_jiffies timer_conversion_bits._cycles_per_jiffies
+#define arch_to_latch timer_conversion_bits._arch_to_latch 
+
 extern void clock_was_set(void);  // Function to call when ever the clock is set
 #include <linux/config.h>
 #ifdef CONFIG_HIGH_RES_TIMERS
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/kernel/itimer.c linux/kernel/itimer.c
--- src/kernel/itimer.c	Wed Aug 14 14:23:01 2002
+++ linux/kernel/itimer.c	Mon Sep  9 15:49:35 2002
@@ -235,7 +235,7 @@
 #if CONFIGURE_MIN_INTERVAL == 0
 IF_HIGH_RES(static  __init void figure_time_rep(void);)
 #endif
-static int high_res_guard = 0;
+IF_HIGH_RES(static int high_res_guard = 0;)
 /* 
  * Build the free list
  */
@@ -260,9 +260,9 @@
                     register_posix_clock(CLOCK_MONOTONIC_HR,&clock_monotonic);
                     high_res_guard = nsec_to_arch_cycles(CONFIGURE_MIN_INTERVAL);
                 );
-        IF_ALL_PERIODIC(
-                final_clock_init();      // defined by arch header file
-                )
+#ifdef  final_clock_init
+        final_clock_init();      // defined by arch header file if needed
+#endif
 #if CONFIGURE_MIN_INTERVAL == 0
         figure_time_rep();
 #endif
@@ -1250,23 +1250,25 @@
  */
 static int do_posix_gettime(struct k_clock *clock, struct timespec *tp)
 {
-      unsigned long flags;
 
         if (clock->clock_get){
                 return clock->clock_get(tp);
         }
 
 #ifdef CONFIG_HIGH_RES_TIMERS
-        write_lock_irqsave(&xtime_lock, flags);
-        update_jiffies_sub();
-        update_real_wall_time();  
-        tp->tv_sec = xtime.tv_sec;
-        tp->tv_nsec = xtime.tv_usec * NSEC_PER_USEC;
-        tp->tv_nsec += arch_cycles_to_nsec(sub_jiffie());
-        write_unlock_irqrestore(&xtime_lock, flags);
-        if ( tp->tv_nsec >  NSEC_PER_SEC ){
-                tp->tv_nsec -= NSEC_PER_SEC ;
-                tp->tv_sec++;
+        {
+                unsigned long flags;
+                write_lock_irqsave(&xtime_lock, flags);
+                update_jiffies_sub();
+                update_real_wall_time();  
+                tp->tv_sec = xtime.tv_sec;
+                tp->tv_nsec = xtime.tv_usec * NSEC_PER_USEC;
+                tp->tv_nsec += arch_cycles_to_nsec(sub_jiffie());
+                write_unlock_irqrestore(&xtime_lock, flags);
+                if ( tp->tv_nsec >  NSEC_PER_SEC ){
+                        tp->tv_nsec -= NSEC_PER_SEC ;
+                        tp->tv_sec++;
+                }
         }
 #else
         do_gettimeofday((struct timeval*)tp);
@@ -1328,10 +1330,12 @@
          * Remember that quick_update_jiffies_sub() can return more
          * than a jiffies worth of cycles...
          */
-        while ( unlikely(sub_jiff_offset > cycles_per_jiffies)){
-                sub_jiff_offset -= cycles_per_jiffies;
-                jiffies_64_f++;
-        }
+        IF_HIGH_RES(
+                while ( unlikely(sub_jiff_offset > cycles_per_jiffies)){
+                        sub_jiff_offset -= cycles_per_jiffies;
+                        jiffies_64_f++;
+                }
+                )
         tp->tv_sec = div_long_long_rem(jiffies_64_f,HZ,&sub_sec);
 
 	tp->tv_nsec = sub_sec * (NSEC_PER_SEC / HZ);
diff -urP -I \$Id:.*Exp \$ -X /usr/src/patch.exclude src/kernel/ksyms.c linux/kernel/ksyms.c
--- src/kernel/ksyms.c	Fri Sep  6 17:43:29 2002
+++ linux/kernel/ksyms.c	Mon Sep  9 16:41:38 2002
@@ -52,6 +52,7 @@
 #include <linux/completion.h>
 #include <linux/seq_file.h>
 #include <asm/checksum.h>
+#include <linux/hrtime.h>
 
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
@@ -489,6 +490,7 @@
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
 EXPORT_SYMBOL(do_settimeofday);
+EXPORT_SYMBOL(timer_conversion_bits);
 
 #if !defined(__ia64__)
 EXPORT_SYMBOL(loops_per_jiffy);


More information about the cgl_discussion mailing list