* [patch 0/3] cyclictest: Various fixes and a new option
@ 2015-05-26 19:06 anna-maria
2015-05-26 19:07 ` [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past anna-maria
` (2 more replies)
0 siblings, 3 replies; 17+ messages in thread
From: anna-maria @ 2015-05-26 19:06 UTC (permalink / raw)
To: linux-rt-users; +Cc: Clark Williams
This patch series addresses two shortcomings of the cyclictest code:
- Calculation of the next wakeup time does not take latencies
longer than the interval time into account, so the next
scheduled event is already in the past.
- The offset value of the --aligned option should be counted in
microseconds, but the code lacks a conversion to nanoseconds
Aside of this, add a new option which allows to align the measurement
threads to the next full second with an optional offset.
Anna-Maria
^ permalink raw reply [flat|nested] 17+ messages in thread* [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past 2015-05-26 19:06 [patch 0/3] cyclictest: Various fixes and a new option anna-maria @ 2015-05-26 19:07 ` anna-maria 2015-06-02 13:06 ` John Kacur 2015-05-26 19:07 ` [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds anna-maria 2015-05-26 19:07 ` [patch 3/3] cyclictest: Align measurement threads to the next full second anna-maria 2 siblings, 1 reply; 17+ messages in thread From: anna-maria @ 2015-05-26 19:07 UTC (permalink / raw) To: linux-rt-users; +Cc: Clark Williams [-- Attachment #1: calc-next-wakeup.patch --] [-- Type: text/plain, Size: 1225 bytes --] The calculated next wakeup time is already in the past, if the latency is longer than the interval. Thereby latency is detected that does not correspond to latency caused by the system but by cyclictest itself. Force forward the next wakeup time past now. Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -369,6 +369,12 @@ static inline void tsnorm(struct timespe } } +static inline int tsgreater(struct timespec *a, struct timespec *b) +{ + return ((a->tv_sec > b->tv_sec) || + (a->tv_sec == b->tv_sec && a->tv_nsec > b->tv_nsec)); +} + static inline int64_t calcdiff(struct timespec t1, struct timespec t2) { int64_t diff; @@ -949,6 +955,12 @@ void *timerthread(void *param) } tsnorm(&next); + while (tsgreater(&now, &next)) { + next.tv_sec += interval.tv_sec; + next.tv_nsec += interval.tv_nsec; + tsnorm(&next); + } + if (par->max_cycles && par->max_cycles == stat->cycles) break; } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past 2015-05-26 19:07 ` [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past anna-maria @ 2015-06-02 13:06 ` John Kacur 0 siblings, 0 replies; 17+ messages in thread From: John Kacur @ 2015-06-02 13:06 UTC (permalink / raw) To: anna-maria; +Cc: linux-rt-users, Clark Williams On Tue, 26 May 2015, anna-maria@glx-um.de wrote: > The calculated next wakeup time is already in the past, if the latency > is longer than the interval. Thereby latency is detected that does not > correspond to latency caused by the system but by cyclictest itself. > > Force forward the next wakeup time past now. > > Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> > --- > src/cyclictest/cyclictest.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > Index: rt-tests/src/cyclictest/cyclictest.c > =================================================================== > --- rt-tests.orig/src/cyclictest/cyclictest.c > +++ rt-tests/src/cyclictest/cyclictest.c > @@ -369,6 +369,12 @@ static inline void tsnorm(struct timespe > } > } > > +static inline int tsgreater(struct timespec *a, struct timespec *b) > +{ > + return ((a->tv_sec > b->tv_sec) || > + (a->tv_sec == b->tv_sec && a->tv_nsec > b->tv_nsec)); > +} > + > static inline int64_t calcdiff(struct timespec t1, struct timespec t2) > { > int64_t diff; > @@ -949,6 +955,12 @@ void *timerthread(void *param) > } > tsnorm(&next); > > + while (tsgreater(&now, &next)) { > + next.tv_sec += interval.tv_sec; > + next.tv_nsec += interval.tv_nsec; > + tsnorm(&next); > + } > + > if (par->max_cycles && par->max_cycles == stat->cycles) > break; > } > > > -- Applied, this one will be in the next build Thanks! John Kacur ^ permalink raw reply [flat|nested] 17+ messages in thread
* [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-05-26 19:06 [patch 0/3] cyclictest: Various fixes and a new option anna-maria 2015-05-26 19:07 ` [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past anna-maria @ 2015-05-26 19:07 ` anna-maria 2015-05-27 21:32 ` John Kacur 2015-05-26 19:07 ` [patch 3/3] cyclictest: Align measurement threads to the next full second anna-maria 2 siblings, 1 reply; 17+ messages in thread From: anna-maria @ 2015-05-26 19:07 UTC (permalink / raw) To: linux-rt-users; +Cc: Clark Williams [-- Attachment #1: align-use-microseconds.patch --] [-- Type: text/plain, Size: 812 bytes --] The offset is specified in microseconds according to the documentation, but, the microseconds to nanoseconds conversion is missing so the effective offset has the unit of nanoseconds. Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -1289,7 +1289,7 @@ static void process_options (int argc, c case OPT_ALIGNED: aligned=1; if (optarg != NULL) - offset = atoi(optarg); + offset = atoi(optarg) * 1000; else if (optind<argc && atoi(argv[optind])) offset = atoi(argv[optind]); else ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-05-26 19:07 ` [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds anna-maria @ 2015-05-27 21:32 ` John Kacur 2015-05-30 11:01 ` Anna-Maria Gleixner 0 siblings, 1 reply; 17+ messages in thread From: John Kacur @ 2015-05-27 21:32 UTC (permalink / raw) To: anna-maria; +Cc: linux-rt-users, Clark Williams On Tue, 26 May 2015, anna-maria@glx-um.de wrote: > The offset is specified in microseconds according to the > documentation, but, the microseconds to nanoseconds conversion is > missing so the effective offset has the unit of nanoseconds. > > Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> > --- > src/cyclictest/cyclictest.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > Index: rt-tests/src/cyclictest/cyclictest.c > =================================================================== > --- rt-tests.orig/src/cyclictest/cyclictest.c > +++ rt-tests/src/cyclictest/cyclictest.c > @@ -1289,7 +1289,7 @@ static void process_options (int argc, c > case OPT_ALIGNED: > aligned=1; > if (optarg != NULL) > - offset = atoi(optarg); > + offset = atoi(optarg) * 1000; > else if (optind<argc && atoi(argv[optind]) Don't we need the conversion here too then? > offset = atoi(argv[optind]); > else > > > -- Thanks John ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-05-27 21:32 ` John Kacur @ 2015-05-30 11:01 ` Anna-Maria Gleixner 2015-06-02 13:00 ` John Kacur 0 siblings, 1 reply; 17+ messages in thread From: Anna-Maria Gleixner @ 2015-05-30 11:01 UTC (permalink / raw) To: John Kacur; +Cc: linux-rt-users, Clark Williams On 2015-05-27 23:32, John Kacur wrote: > On Tue, 26 May 2015, anna-maria@glx-um.de wrote: > Don't we need the conversion here too then? >> offset = atoi(argv[optind]); Jap, this is right. I forgot it. I changed the patch. I forgot the same in the third patch of this series. I'll fix it and send the patch back to you. Anna-Maria The offset is specified in microseconds according to the documentation, but, the microseconds to nanoseconds conversion is missing so the effective offset has the unit of nanoseconds. Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -1289,9 +1289,9 @@ static void process_options (int argc, c case OPT_ALIGNED: aligned=1; if (optarg != NULL) - offset = atoi(optarg); + offset = atoi(optarg) * 1000; else if (optind<argc && atoi(argv[optind])) - offset = atoi(argv[optind]); + offset = atoi(argv[optind]) * 1000; else offset = 0; break; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-05-30 11:01 ` Anna-Maria Gleixner @ 2015-06-02 13:00 ` John Kacur 2015-06-02 21:01 ` Thomas Gleixner 0 siblings, 1 reply; 17+ messages in thread From: John Kacur @ 2015-06-02 13:00 UTC (permalink / raw) To: Anna-Maria Gleixner; +Cc: John Kacur, linux-rt-users, Clark Williams On Sat, 30 May 2015, Anna-Maria Gleixner wrote: > On 2015-05-27 23:32, John Kacur wrote: > > On Tue, 26 May 2015, anna-maria@glx-um.de wrote: > > Don't we need the conversion here too then? > > > offset = atoi(argv[optind]); > > Jap, this is right. I forgot it. I changed the patch. > I forgot the same in the third patch of this series. I'll fix it and send the > patch back to you. > > Anna-Maria > > > The offset is specified in microseconds according to the > documentation, but, the microseconds to nanoseconds conversion is > missing so the effective offset has the unit of nanoseconds. > > Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> > --- > src/cyclictest/cyclictest.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > Index: rt-tests/src/cyclictest/cyclictest.c > =================================================================== > --- rt-tests.orig/src/cyclictest/cyclictest.c > +++ rt-tests/src/cyclictest/cyclictest.c > @@ -1289,9 +1289,9 @@ static void process_options (int argc, c I fixed your patch manually, but you are doing something wrong generating it, see how the function header get's cut off above there? > case OPT_ALIGNED: > aligned=1; > if (optarg != NULL) > - offset = atoi(optarg); > + offset = atoi(optarg) * 1000; > else if (optind<argc && atoi(argv[optind])) > - offset = atoi(argv[optind]); > + offset = atoi(argv[optind]) * 1000; > else > offset = 0; > break; > -- > To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-06-02 13:00 ` John Kacur @ 2015-06-02 21:01 ` Thomas Gleixner 2015-06-02 21:17 ` John Kacur 0 siblings, 1 reply; 17+ messages in thread From: Thomas Gleixner @ 2015-06-02 21:01 UTC (permalink / raw) To: John Kacur; +Cc: Anna-Maria Gleixner, linux-rt-users, Clark Williams On Tue, 2 Jun 2015, John Kacur wrote: > > =================================================================== > > --- rt-tests.orig/src/cyclictest/cyclictest.c > > +++ rt-tests/src/cyclictest/cyclictest.c > > @@ -1289,9 +1289,9 @@ static void process_options (int argc, c > > > I fixed your patch manually, but you are doing something wrong generating > it, see how the function header get's cut off above there? No. This is entirely correct. diff cuts off the function declaration at some random column and it's completely irrelevant to the correctness of the patch. That line is merily an extra for navigation purpose and not at all relevant to the patch itself. @@ -1289,9 +1289,9 @@ would be a completly sufficient header for the hunk. The reason why this patch did not apply is, that it is a complete replacement of the original patch and not a delta patch. Anna-Maria should have sent a new series(PATCH V2) instead of patches which can be mistaken as delta fixes. Thanks, tglx ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-06-02 21:01 ` Thomas Gleixner @ 2015-06-02 21:17 ` John Kacur 2015-06-02 21:33 ` Thomas Gleixner 0 siblings, 1 reply; 17+ messages in thread From: John Kacur @ 2015-06-02 21:17 UTC (permalink / raw) To: Thomas Gleixner Cc: John Kacur, Anna-Maria Gleixner, linux-rt-users, Clark Williams On Tue, 2 Jun 2015, Thomas Gleixner wrote: > On Tue, 2 Jun 2015, John Kacur wrote: > > > =================================================================== > > > --- rt-tests.orig/src/cyclictest/cyclictest.c > > > +++ rt-tests/src/cyclictest/cyclictest.c > > > @@ -1289,9 +1289,9 @@ static void process_options (int argc, c > > > > > > I fixed your patch manually, but you are doing something wrong generating > > it, see how the function header get's cut off above there? > > No. This is entirely correct. diff cuts off the function declaration > at some random column and it's completely irrelevant to the > correctness of the patch. That line is merily an extra for navigation > purpose and not at all relevant to the patch itself. > > @@ -1289,9 +1289,9 @@ > > would be a completly sufficient header for the hunk. > > The reason why this patch did not apply is, that it is a complete > replacement of the original patch and not a delta patch. > > Anna-Maria should have sent a new series(PATCH V2) instead of patches > which can be mistaken as delta fixes. > > > Thanks, > > tglx Yeah, my guess as to why her patches are failing was wrong, but they are failing. Maybe it's a wordwrap problem. When I try with patch -p1 < annas-patch, I get this. patch -p1 < ~/patches/anna/align_measurement_threads.patch patching file src/cyclictest/cyclictest.c Hunk #1 FAILED at 185. patch: **** malformed patch at line 64: par->prio); Thanks John ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-06-02 21:17 ` John Kacur @ 2015-06-02 21:33 ` Thomas Gleixner 2015-06-08 13:18 ` Anna-Maria Gleixner 0 siblings, 1 reply; 17+ messages in thread From: Thomas Gleixner @ 2015-06-02 21:33 UTC (permalink / raw) To: John Kacur; +Cc: Anna-Maria Gleixner, linux-rt-users, Clark Williams On Tue, 2 Jun 2015, John Kacur wrote: > Yeah, my guess as to why her patches are failing was wrong, but they are > failing. Maybe it's a wordwrap problem. When I try with patch -p1 < > annas-patch, I get this. > > patch -p1 < ~/patches/anna/align_measurement_threads.patch > patching file src/cyclictest/cyclictest.c > Hunk #1 FAILED at 185. > patch: **** malformed patch at line 64: par->prio); Fair enough. Let her resend then. Thanks, tglx ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-06-02 21:33 ` Thomas Gleixner @ 2015-06-08 13:18 ` Anna-Maria Gleixner 2015-06-08 17:31 ` John Kacur 0 siblings, 1 reply; 17+ messages in thread From: Anna-Maria Gleixner @ 2015-06-08 13:18 UTC (permalink / raw) To: Thomas Gleixner; +Cc: John Kacur, linux-rt-users, Clark Williams On Tue, 2 Jun 2015, Thomas Gleixner wrote: > Fair enough. Let her resend then. I'm sorry. Now it applies. Anna-Maria cyclictest: Convert the offset of the alignment option to microseconds The offset is specified in microseconds according to the documentation, but, the microseconds to nanoseconds conversion is missing so the effective offset has the unit of nanoseconds. Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -1289,9 +1289,9 @@ static void process_options (int argc, c case OPT_ALIGNED: aligned=1; if (optarg != NULL) - offset = atoi(optarg); + offset = atoi(optarg) * 1000; else if (optind<argc && atoi(argv[optind])) - offset = atoi(argv[optind]); + offset = atoi(argv[optind]) * 1000; else offset = 0; break; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds 2015-06-08 13:18 ` Anna-Maria Gleixner @ 2015-06-08 17:31 ` John Kacur 0 siblings, 0 replies; 17+ messages in thread From: John Kacur @ 2015-06-08 17:31 UTC (permalink / raw) To: Anna-Maria Gleixner Cc: Thomas Gleixner, John Kacur, linux-rt-users, Clark Williams On Mon, 8 Jun 2015, Anna-Maria Gleixner wrote: > On Tue, 2 Jun 2015, Thomas Gleixner wrote: > > Fair enough. Let her resend then. > > I'm sorry. Now it applies. > Anna-Maria > > > cyclictest: Convert the offset of the alignment option to microseconds > > The offset is specified in microseconds according to the > documentation, but, the microseconds to nanoseconds conversion is > missing so the effective offset has the unit of nanoseconds. > > Signed-off-by: Anna-Maria Gleixner <anna-maria@glx-um.de> > --- > src/cyclictest/cyclictest.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > Index: rt-tests/src/cyclictest/cyclictest.c > =================================================================== > --- rt-tests.orig/src/cyclictest/cyclictest.c > +++ rt-tests/src/cyclictest/cyclictest.c > @@ -1289,9 +1289,9 @@ static void process_options (int argc, c > case OPT_ALIGNED: > aligned=1; > if (optarg != NULL) > - offset = atoi(optarg); > + offset = atoi(optarg) * 1000; > else if (optind<argc && atoi(argv[optind])) > - offset = atoi(argv[optind]); > + offset = atoi(argv[optind]) * 1000; > else > offset = 0; > break; > -- Thanks, applied, this will be in the next release John ^ permalink raw reply [flat|nested] 17+ messages in thread
* [patch 3/3] cyclictest: Align measurement threads to the next full second 2015-05-26 19:06 [patch 0/3] cyclictest: Various fixes and a new option anna-maria 2015-05-26 19:07 ` [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past anna-maria 2015-05-26 19:07 ` [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds anna-maria @ 2015-05-26 19:07 ` anna-maria 2015-05-30 11:02 ` Anna-Maria Gleixner 2 siblings, 1 reply; 17+ messages in thread From: anna-maria @ 2015-05-26 19:07 UTC (permalink / raw) To: linux-rt-users; +Cc: Clark Williams [-- Attachment #1: align-sec.patch --] [-- Type: text/plain, Size: 4639 bytes --] cyclictest starts the test threads at a random point in time. For fully reproducible tests it is required to schedule the threads with a specified offset from the timer tick. The influence of the tick can be measured by running the test with offset = 0 and offset = tickinterval/2. To achieve this we rely on the fact, that the kernel starts the tick at CLOCK_MONOTONIC time 0. So it's guaranteed that the tick timer expires always every second (if the interval between the ticks defined by CONFIG_HZ is a whole-number divider of a second). Setting the global start time of the test threads to a full second (plus offset) and the interval to the interval between the ticks, the threads are scheduled with the specified offset to the tick. Add a new option --secaligned which select this mode and modify the --aligned option code to support this. The --secaligned and --aligned options are mutually exclusive. Signed-off-by Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -185,6 +185,7 @@ static int ct_debug; static int use_fifo = 0; static pthread_t fifo_threadid; static int aligned = 0; +static int secaligned = 0; static int offset = 0; static int laptop = 0; @@ -798,14 +799,27 @@ void *timerthread(void *param) fatal("timerthread%d: failed to set priority to %d\n", par->cpu, par->prio); /* Get current time */ - if(aligned){ + if (aligned || secaligned) { pthread_barrier_wait(&globalt_barr); - if(par->tnum==0) + if (par->tnum == 0) { clock_gettime(par->clock, &globalt); + if (secaligned) { + /* Ensure that the thread start timestamp is not + in the past */ + if (globalt.tv_nsec > 900000000) + globalt.tv_sec += 2; + else + globalt.tv_sec++; + globalt.tv_nsec = 0; + } + } pthread_barrier_wait(&align_barr); now = globalt; if(offset) { - now.tv_nsec += offset * par->tnum; + if (aligned) + now.tv_nsec += offset * par->tnum; + else + now.tv_nsec += offset; tsnorm(&now); } } @@ -1056,6 +1070,8 @@ static void display_help(int error) "-R --resolution check clock resolution, calling clock_gettime() many\n" " times. list of clock_gettime() values will be\n" " reported with -X\n" + " --secaligned [USEC] align thread wakeups to the next full second,\n" + " and apply the optional offset\n" "-s --system use sys_nanosleep and sys_setitimer\n" "-S --smp Standard SMP testing: options -a -t -n and\n" " same priority of all threads\n" @@ -1204,7 +1220,7 @@ enum option_values { OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION, OPT_SYSTEM, OPT_SMP, OPT_THREADS, OPT_TRACER, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE, OPT_WAKEUP, OPT_WAKEUPRT, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS, - OPT_ALIGNED, OPT_LAPTOP, + OPT_ALIGNED, OPT_LAPTOP, OPT_SECALIGNED, }; /* Process commandline options */ @@ -1251,6 +1267,7 @@ static void process_options (int argc, c {"priospread", no_argument, NULL, OPT_PRIOSPREAD }, {"relative", no_argument, NULL, OPT_RELATIVE }, {"resolution", no_argument, NULL, OPT_RESOLUTION }, + {"secaligned", optional_argument, NULL, OPT_SECALIGNED }, {"system", no_argument, NULL, OPT_SYSTEM }, {"smp", no_argument, NULL, OPT_SMP }, {"threads", optional_argument, NULL, OPT_THREADS }, @@ -1391,6 +1408,15 @@ static void process_options (int argc, c case OPT_RESOLUTION: check_clock_resolution = 1; break; case 's': + case OPT_SECALIGNED: + secaligned = 1; + if (optarg != NULL) + offset = atoi(optarg) * 1000; + else if (optind < argc && atoi(argv[optind])) + offset = atoi(argv[optind]); + else + offset = 0; + break; case OPT_SYSTEM: use_system = MODE_SYS_OFFSET; break; case 'S': @@ -1528,7 +1554,10 @@ static void process_options (int argc, c if (num_threads < 1) error = 1; - if (aligned) { + if (aligned && secaligned) + error = 1; + + if (aligned || secaligned) { pthread_barrier_init(&globalt_barr, NULL, num_threads); pthread_barrier_init(&align_barr, NULL, num_threads); } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 3/3] cyclictest: Align measurement threads to the next full second 2015-05-26 19:07 ` [patch 3/3] cyclictest: Align measurement threads to the next full second anna-maria @ 2015-05-30 11:02 ` Anna-Maria Gleixner 2015-06-02 13:05 ` John Kacur 0 siblings, 1 reply; 17+ messages in thread From: Anna-Maria Gleixner @ 2015-05-30 11:02 UTC (permalink / raw) To: John Kacur; +Cc: linux-rt-users, Clark Williams On 2015-05-26 21:07, anna-maria@glx-um.de wrote: > + case OPT_SECALIGNED: > + secaligned = 1; > + if (optarg != NULL) > + offset = atoi(optarg) * 1000; > + else if (optind < argc && atoi(argv[optind])) The conversion to microseconds is missing as well. > + offset = atoi(argv[optind]); > + else The patch is fixed. Anna-Maria cyclictest starts the test threads at a random point in time. For fully reproducible tests it is required to schedule the threads with a specified offset from the timer tick. The influence of the tick can be measured by running the test with offset = 0 and offset = tickinterval/2. To achieve this we rely on the fact, that the kernel starts the tick at CLOCK_MONOTONIC time 0. So it's guaranteed that the tick timer expires always every second (if the interval between the ticks defined by CONFIG_HZ is a whole-number divider of a second). Setting the global start time of the test threads to a full second (plus offset) and the interval to the interval between the ticks, the threads are scheduled with the specified offset to the tick. Add a new option --secaligned which select this mode and modify the --aligned option code to support this. The --secaligned and --aligned options are mutually exclusive. Signed-off-by Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -185,6 +185,7 @@ static int ct_debug; static int use_fifo = 0; static pthread_t fifo_threadid; static int aligned = 0; +static int secaligned = 0; static int offset = 0; static int laptop = 0; @@ -798,14 +799,27 @@ void *timerthread(void *param) fatal("timerthread%d: failed to set priority to %d\n", par->cpu, par->prio); /* Get current time */ - if(aligned){ + if (aligned || secaligned) { pthread_barrier_wait(&globalt_barr); - if(par->tnum==0) + if (par->tnum == 0) { clock_gettime(par->clock, &globalt); + if (secaligned) { + /* Ensure that the thread start timestamp is not + in the past */ + if (globalt.tv_nsec > 900000000) + globalt.tv_sec += 2; + else + globalt.tv_sec++; + globalt.tv_nsec = 0; + } + } pthread_barrier_wait(&align_barr); now = globalt; if(offset) { - now.tv_nsec += offset * par->tnum; + if (aligned) + now.tv_nsec += offset * par->tnum; + else + now.tv_nsec += offset; tsnorm(&now); } } @@ -1056,6 +1070,8 @@ static void display_help(int error) "-R --resolution check clock resolution, calling clock_gettime() many\n" " times. list of clock_gettime() values will be\n" " reported with -X\n" + " --secaligned [USEC] align thread wakeups to the next full second,\n" + " and apply the optional offset\n" "-s --system use sys_nanosleep and sys_setitimer\n" "-S --smp Standard SMP testing: options -a -t -n and\n" " same priority of all threads\n" @@ -1204,7 +1220,7 @@ enum option_values { OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION, OPT_SYSTEM, OPT_SMP, OPT_THREADS, OPT_TRACER, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE, OPT_WAKEUP, OPT_WAKEUPRT, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS, - OPT_ALIGNED, OPT_LAPTOP, + OPT_ALIGNED, OPT_LAPTOP, OPT_SECALIGNED, }; /* Process commandline options */ @@ -1251,6 +1267,7 @@ static void process_options (int argc, c {"priospread", no_argument, NULL, OPT_PRIOSPREAD }, {"relative", no_argument, NULL, OPT_RELATIVE }, {"resolution", no_argument, NULL, OPT_RESOLUTION }, + {"secaligned", optional_argument, NULL, OPT_SECALIGNED }, {"system", no_argument, NULL, OPT_SYSTEM }, {"smp", no_argument, NULL, OPT_SMP }, {"threads", optional_argument, NULL, OPT_THREADS }, @@ -1391,6 +1408,15 @@ static void process_options (int argc, c case OPT_RESOLUTION: check_clock_resolution = 1; break; case 's': + case OPT_SECALIGNED: + secaligned = 1; + if (optarg != NULL) + offset = atoi(optarg) * 1000; + else if (optind < argc && atoi(argv[optind])) + offset = atoi(argv[optind]) * 1000; + else + offset = 0; + break; case OPT_SYSTEM: use_system = MODE_SYS_OFFSET; break; case 'S': @@ -1528,7 +1554,10 @@ static void process_options (int argc, c if (num_threads < 1) error = 1; - if (aligned) { + if (aligned && secaligned) + error = 1; + + if (aligned || secaligned) { pthread_barrier_init(&globalt_barr, NULL, num_threads); pthread_barrier_init(&align_barr, NULL, num_threads); } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 3/3] cyclictest: Align measurement threads to the next full second 2015-05-30 11:02 ` Anna-Maria Gleixner @ 2015-06-02 13:05 ` John Kacur 2015-06-08 13:21 ` Anna-Maria Gleixner 0 siblings, 1 reply; 17+ messages in thread From: John Kacur @ 2015-06-02 13:05 UTC (permalink / raw) To: Anna-Maria Gleixner; +Cc: John Kacur, linux-rt-users, Clark Williams On Sat, 30 May 2015, Anna-Maria Gleixner wrote: > On 2015-05-26 21:07, anna-maria@glx-um.de wrote: > > > + case OPT_SECALIGNED: > > + secaligned = 1; > > + if (optarg != NULL) > > + offset = atoi(optarg) * 1000; > > + else if (optind < argc && atoi(argv[optind])) > > The conversion to microseconds is missing as well. > > > + offset = atoi(argv[optind]); > > + else > > The patch is fixed. > > Anna-Maria > > > cyclictest starts the test threads at a random point in time. For > fully reproducible tests it is required to schedule the threads with a > specified offset from the timer tick. The influence of the tick can be > measured by running the test with offset = 0 and offset = > tickinterval/2. > > To achieve this we rely on the fact, that the kernel starts the tick > at CLOCK_MONOTONIC time 0. So it's guaranteed that the tick timer > expires always every second (if the interval between the ticks defined > by CONFIG_HZ is a whole-number divider of a second). Setting the > global start time of the test threads to a full second (plus offset) > and the interval to the interval between the ticks, the threads are > scheduled with the specified offset to the tick. > > Add a new option --secaligned which select this mode and modify the > --aligned option code to support this. The --secaligned and --aligned > options are mutually exclusive. > > Signed-off-by Anna-Maria Gleixner <anna-maria@glx-um.de> > --- > src/cyclictest/cyclictest.c | 39 ++++++++++++++++++++++++++++++++++----- > 1 file changed, 34 insertions(+), 5 deletions(-) > > Index: rt-tests/src/cyclictest/cyclictest.c > =================================================================== > --- rt-tests.orig/src/cyclictest/cyclictest.c > +++ rt-tests/src/cyclictest/cyclictest.c > @@ -185,6 +185,7 @@ static int ct_debug; > static int use_fifo = 0; > static pthread_t fifo_threadid; > static int aligned = 0; > +static int secaligned = 0; > static int offset = 0; > static int laptop = 0; > > @@ -798,14 +799,27 @@ void *timerthread(void *param) > fatal("timerthread%d: failed to set priority to %d\n", > par->cpu, par->prio); > > /* Get current time */ > - if(aligned){ > + if (aligned || secaligned) { > pthread_barrier_wait(&globalt_barr); > - if(par->tnum==0) > + if (par->tnum == 0) { > clock_gettime(par->clock, &globalt); > + if (secaligned) { > + /* Ensure that the thread start timestamp is > not > + in the past */ > + if (globalt.tv_nsec > 900000000) > + globalt.tv_sec += 2; > + else > + globalt.tv_sec++; > + globalt.tv_nsec = 0; > + } > + } > pthread_barrier_wait(&align_barr); > now = globalt; > if(offset) { > - now.tv_nsec += offset * par->tnum; > + if (aligned) > + now.tv_nsec += offset * par->tnum; > + else > + now.tv_nsec += offset; > tsnorm(&now); > } > } > @@ -1056,6 +1070,8 @@ static void display_help(int error) > "-R --resolution check clock resolution, calling > clock_gettime() many\n" > " times. list of clock_gettime() > values will be\n" > " reported with -X\n" > + " --secaligned [USEC] align thread wakeups to the next > full second,\n" > + " and apply the optional offset\n" > "-s --system use sys_nanosleep and > sys_setitimer\n" > "-S --smp Standard SMP testing: options -a -t > -n and\n" > " same priority of all threads\n" > @@ -1204,7 +1220,7 @@ enum option_values { > OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION, OPT_SYSTEM, > OPT_SMP, OPT_THREADS, OPT_TRACER, OPT_UNBUFFERED, OPT_NUMA, > OPT_VERBOSE, > OPT_WAKEUP, OPT_WAKEUPRT, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, > OPT_NUMOPTS, > - OPT_ALIGNED, OPT_LAPTOP, > + OPT_ALIGNED, OPT_LAPTOP, OPT_SECALIGNED, > }; > > /* Process commandline options */ > @@ -1251,6 +1267,7 @@ static void process_options (int argc, c > {"priospread", no_argument, NULL, > OPT_PRIOSPREAD }, > {"relative", no_argument, NULL, > OPT_RELATIVE }, > {"resolution", no_argument, NULL, > OPT_RESOLUTION }, > + {"secaligned", optional_argument, NULL, > OPT_SECALIGNED }, > {"system", no_argument, NULL, > OPT_SYSTEM }, > {"smp", no_argument, NULL, OPT_SMP > }, > {"threads", optional_argument, NULL, > OPT_THREADS }, > @@ -1391,6 +1408,15 @@ static void process_options (int argc, c > case OPT_RESOLUTION: > check_clock_resolution = 1; break; > case 's': > + case OPT_SECALIGNED: > + secaligned = 1; > + if (optarg != NULL) > + offset = atoi(optarg) * 1000; > + else if (optind < argc && atoi(argv[optind])) > + offset = atoi(argv[optind]) * 1000; > + else > + offset = 0; > + break; > case OPT_SYSTEM: > use_system = MODE_SYS_OFFSET; break; > case 'S': > @@ -1528,7 +1554,10 @@ static void process_options (int argc, c > if (num_threads < 1) > error = 1; > > - if (aligned) { > + if (aligned && secaligned) > + error = 1; > + > + if (aligned || secaligned) { > pthread_barrier_init(&globalt_barr, NULL, num_threads); > pthread_barrier_init(&align_barr, NULL, num_threads); > } > -- Sorry, this one isn't applying either, perhaps your emailer is doing automatic word wrap? Can you fix this up, and resend please? Thank you John Kacur ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 3/3] cyclictest: Align measurement threads to the next full second 2015-06-02 13:05 ` John Kacur @ 2015-06-08 13:21 ` Anna-Maria Gleixner 2015-06-08 17:32 ` John Kacur 0 siblings, 1 reply; 17+ messages in thread From: Anna-Maria Gleixner @ 2015-06-08 13:21 UTC (permalink / raw) To: John Kacur; +Cc: linux-rt-users, Clark Williams On Tue, 2 Jun 2015, John Kacur wrote: > Can you fix this up, and resend please? Now it should work. Anna-Maria cyclictest: Align measurement threads to the next full second cyclictest starts the test threads at a random point in time. For fully reproducible tests it is required to schedule the threads with a specified offset from the timer tick. The influence of the tick can be measured by running the test with offset = 0 and offset = tickinterval/2. To achieve this we rely on the fact, that the kernel starts the tick at CLOCK_MONOTONIC time 0. So it's guaranteed that the tick timer expires always every second (if the interval between the ticks defined by CONFIG_HZ is a whole-number divider of a second). Setting the global start time of the test threads to a full second (plus offset) and the interval to the interval between the ticks, the threads are scheduled with the specified offset to the tick. Add a new option --secaligned which select this mode and modify the --aligned option code to support this. The --secaligned and --aligned options are mutually exclusive. Signed-off-by Anna-Maria Gleixner <anna-maria@glx-um.de> --- src/cyclictest/cyclictest.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) Index: rt-tests/src/cyclictest/cyclictest.c =================================================================== --- rt-tests.orig/src/cyclictest/cyclictest.c +++ rt-tests/src/cyclictest/cyclictest.c @@ -185,6 +185,7 @@ static int ct_debug; static int use_fifo = 0; static pthread_t fifo_threadid; static int aligned = 0; +static int secaligned = 0; static int offset = 0; static int laptop = 0; @@ -798,14 +799,27 @@ void *timerthread(void *param) fatal("timerthread%d: failed to set priority to %d\n", par->cpu, par->prio); /* Get current time */ - if(aligned){ + if (aligned || secaligned) { pthread_barrier_wait(&globalt_barr); - if(par->tnum==0) + if (par->tnum == 0) { clock_gettime(par->clock, &globalt); + if (secaligned) { + /* Ensure that the thread start timestamp is not + in the past */ + if (globalt.tv_nsec > 900000000) + globalt.tv_sec += 2; + else + globalt.tv_sec++; + globalt.tv_nsec = 0; + } + } pthread_barrier_wait(&align_barr); now = globalt; if(offset) { - now.tv_nsec += offset * par->tnum; + if (aligned) + now.tv_nsec += offset * par->tnum; + else + now.tv_nsec += offset; tsnorm(&now); } } @@ -1056,6 +1070,8 @@ static void display_help(int error) "-R --resolution check clock resolution, calling clock_gettime() many\n" " times. list of clock_gettime() values will be\n" " reported with -X\n" + " --secaligned [USEC] align thread wakeups to the next full second,\n" + " and apply the optional offset\n" "-s --system use sys_nanosleep and sys_setitimer\n" "-S --smp Standard SMP testing: options -a -t -n and\n" " same priority of all threads\n" @@ -1204,7 +1220,7 @@ enum option_values { OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION, OPT_SYSTEM, OPT_SMP, OPT_THREADS, OPT_TRACER, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE, OPT_WAKEUP, OPT_WAKEUPRT, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS, - OPT_ALIGNED, OPT_LAPTOP, + OPT_ALIGNED, OPT_LAPTOP, OPT_SECALIGNED, }; /* Process commandline options */ @@ -1251,6 +1267,7 @@ static void process_options (int argc, c {"priospread", no_argument, NULL, OPT_PRIOSPREAD }, {"relative", no_argument, NULL, OPT_RELATIVE }, {"resolution", no_argument, NULL, OPT_RESOLUTION }, + {"secaligned", optional_argument, NULL, OPT_SECALIGNED }, {"system", no_argument, NULL, OPT_SYSTEM }, {"smp", no_argument, NULL, OPT_SMP }, {"threads", optional_argument, NULL, OPT_THREADS }, @@ -1391,6 +1408,15 @@ static void process_options (int argc, c case OPT_RESOLUTION: check_clock_resolution = 1; break; case 's': + case OPT_SECALIGNED: + secaligned = 1; + if (optarg != NULL) + offset = atoi(optarg) * 1000; + else if (optind < argc && atoi(argv[optind])) + offset = atoi(argv[optind]) * 1000; + else + offset = 0; + break; case OPT_SYSTEM: use_system = MODE_SYS_OFFSET; break; case 'S': @@ -1528,7 +1554,10 @@ static void process_options (int argc, c if (num_threads < 1) error = 1; - if (aligned) { + if (aligned && secaligned) + error = 1; + + if (aligned || secaligned) { pthread_barrier_init(&globalt_barr, NULL, num_threads); pthread_barrier_init(&align_barr, NULL, num_threads); } ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [patch 3/3] cyclictest: Align measurement threads to the next full second 2015-06-08 13:21 ` Anna-Maria Gleixner @ 2015-06-08 17:32 ` John Kacur 0 siblings, 0 replies; 17+ messages in thread From: John Kacur @ 2015-06-08 17:32 UTC (permalink / raw) To: Anna-Maria Gleixner; +Cc: John Kacur, linux-rt-users, Clark Williams On Mon, 8 Jun 2015, Anna-Maria Gleixner wrote: > > On Tue, 2 Jun 2015, John Kacur wrote: > > Can you fix this up, and resend please? > > Now it should work. > Anna-Maria > > > cyclictest: Align measurement threads to the next full second > > cyclictest starts the test threads at a random point in time. For > fully reproducible tests it is required to schedule the threads with a > specified offset from the timer tick. The influence of the tick can be > measured by running the test with offset = 0 and offset = > tickinterval/2. > > To achieve this we rely on the fact, that the kernel starts the tick > at CLOCK_MONOTONIC time 0. So it's guaranteed that the tick timer > expires always every second (if the interval between the ticks defined > by CONFIG_HZ is a whole-number divider of a second). Setting the > global start time of the test threads to a full second (plus offset) > and the interval to the interval between the ticks, the threads are > scheduled with the specified offset to the tick. > > Add a new option --secaligned which select this mode and modify the > --aligned option code to support this. The --secaligned and --aligned > options are mutually exclusive. > > Signed-off-by Anna-Maria Gleixner <anna-maria@glx-um.de> > --- > src/cyclictest/cyclictest.c | 39 ++++++++++++++++++++++++++++++++++----- > 1 file changed, 34 insertions(+), 5 deletions(-) > > Index: rt-tests/src/cyclictest/cyclictest.c > =================================================================== > --- rt-tests.orig/src/cyclictest/cyclictest.c > +++ rt-tests/src/cyclictest/cyclictest.c > @@ -185,6 +185,7 @@ static int ct_debug; > static int use_fifo = 0; > static pthread_t fifo_threadid; > static int aligned = 0; > +static int secaligned = 0; > static int offset = 0; > static int laptop = 0; > > @@ -798,14 +799,27 @@ void *timerthread(void *param) > fatal("timerthread%d: failed to set priority to %d\n", par->cpu, par->prio); > > /* Get current time */ > - if(aligned){ > + if (aligned || secaligned) { > pthread_barrier_wait(&globalt_barr); > - if(par->tnum==0) > + if (par->tnum == 0) { > clock_gettime(par->clock, &globalt); > + if (secaligned) { > + /* Ensure that the thread start timestamp is not > + in the past */ > + if (globalt.tv_nsec > 900000000) > + globalt.tv_sec += 2; > + else > + globalt.tv_sec++; > + globalt.tv_nsec = 0; > + } > + } > pthread_barrier_wait(&align_barr); > now = globalt; > if(offset) { > - now.tv_nsec += offset * par->tnum; > + if (aligned) > + now.tv_nsec += offset * par->tnum; > + else > + now.tv_nsec += offset; > tsnorm(&now); > } > } > @@ -1056,6 +1070,8 @@ static void display_help(int error) > "-R --resolution check clock resolution, calling clock_gettime() many\n" > " times. list of clock_gettime() values will be\n" > " reported with -X\n" > + " --secaligned [USEC] align thread wakeups to the next full second,\n" > + " and apply the optional offset\n" > "-s --system use sys_nanosleep and sys_setitimer\n" > "-S --smp Standard SMP testing: options -a -t -n and\n" > " same priority of all threads\n" > @@ -1204,7 +1220,7 @@ enum option_values { > OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION, OPT_SYSTEM, > OPT_SMP, OPT_THREADS, OPT_TRACER, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE, > OPT_WAKEUP, OPT_WAKEUPRT, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, OPT_NUMOPTS, > - OPT_ALIGNED, OPT_LAPTOP, > + OPT_ALIGNED, OPT_LAPTOP, OPT_SECALIGNED, > }; > > /* Process commandline options */ > @@ -1251,6 +1267,7 @@ static void process_options (int argc, c > {"priospread", no_argument, NULL, OPT_PRIOSPREAD }, > {"relative", no_argument, NULL, OPT_RELATIVE }, > {"resolution", no_argument, NULL, OPT_RESOLUTION }, > + {"secaligned", optional_argument, NULL, OPT_SECALIGNED }, > {"system", no_argument, NULL, OPT_SYSTEM }, > {"smp", no_argument, NULL, OPT_SMP }, > {"threads", optional_argument, NULL, OPT_THREADS }, > @@ -1391,6 +1408,15 @@ static void process_options (int argc, c > case OPT_RESOLUTION: > check_clock_resolution = 1; break; > case 's': > + case OPT_SECALIGNED: > + secaligned = 1; > + if (optarg != NULL) > + offset = atoi(optarg) * 1000; > + else if (optind < argc && atoi(argv[optind])) > + offset = atoi(argv[optind]) * 1000; > + else > + offset = 0; > + break; > case OPT_SYSTEM: > use_system = MODE_SYS_OFFSET; break; > case 'S': > @@ -1528,7 +1554,10 @@ static void process_options (int argc, c > if (num_threads < 1) > error = 1; > > - if (aligned) { > + if (aligned && secaligned) > + error = 1; > + > + if (aligned || secaligned) { > pthread_barrier_init(&globalt_barr, NULL, num_threads); > pthread_barrier_init(&align_barr, NULL, num_threads); > } > -- Thanks, applied, this will appear in the next release John ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2015-06-08 17:32 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-05-26 19:06 [patch 0/3] cyclictest: Various fixes and a new option anna-maria 2015-05-26 19:07 ` [patch 1/3] cyclictest: Ensure that next wakeup time is never in the past anna-maria 2015-06-02 13:06 ` John Kacur 2015-05-26 19:07 ` [patch 2/3] cyclictest: Convert the offset of the alignment option to microseconds anna-maria 2015-05-27 21:32 ` John Kacur 2015-05-30 11:01 ` Anna-Maria Gleixner 2015-06-02 13:00 ` John Kacur 2015-06-02 21:01 ` Thomas Gleixner 2015-06-02 21:17 ` John Kacur 2015-06-02 21:33 ` Thomas Gleixner 2015-06-08 13:18 ` Anna-Maria Gleixner 2015-06-08 17:31 ` John Kacur 2015-05-26 19:07 ` [patch 3/3] cyclictest: Align measurement threads to the next full second anna-maria 2015-05-30 11:02 ` Anna-Maria Gleixner 2015-06-02 13:05 ` John Kacur 2015-06-08 13:21 ` Anna-Maria Gleixner 2015-06-08 17:32 ` John Kacur
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).