[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