On Fri, May 28, 2021 at 08:15:20AM +0200, Mark Kettenis wrote:
> > Date: Thu, 27 May 2021 18:29:04 -0500
> > From: Scott Cheloha <scottchel...@gmail.com>
> 
> Sorry, but does is one of those areas where I'm not very aware how the
> interfaces are used by applications.  So my default position is:
> "don't change it".  Especially since these are "legacy" interfaces.
> 
> > On Wed, May 19, 2021 at 10:32:55AM -0500, Scott Cheloha wrote:
> > > On Wed, May 12, 2021 at 01:15:05PM -0500, Scott Cheloha wrote:
> > > > 
> > > > [...]
> > > > 
> > > > Paul de Weerd mentioned off-list that the initial expiration for an
> > > > ITIMER_REAL timer is always at least one tick.  I looked into it and
> > > > yes, this is the case, because the kernel rounds it_value up to one
> > > > tick if it is non-zero.
> > > > 
> > > > After thinking about it a bit I don't think we should do this
> > > > rounding.  At least, not for the initial expiration.
> 
> The manual page explicity says:
> 
>   "Time values smaller than the resolution of the system clock are
>    rounded up to this reolution (typically 10 milliseconds)".
> 
> which has been there from revision 1.
> 
> Note that POSIX defines timer_gettime() and timer_settime(), which we
> don't implement.  We don't implement these, but the POSIX standard
> says in the rationale:
> 
>   "Practical clocks tick at a finite rate, with rates of 100 hertz and
>    1000 hertz being common.  The inverse of this tick rate is the
>    clock resolution, also called the clock granularity, which in
>    either case is expressed as a time duration, being 10 milliseconds
>    and 1 millisecond respectively for these common rates. The
>    granularity of practical clocks implies that if one reads a given
>    clock twice in rapid succession, one may get the same time value
>    twice; and that timers must wait for the next clock tick after the
>    theoretical expiration time, to ensure that a timer never returns
>    too soon.  Note also that the granularity of the clock may be
>    significantly coarser than the resolution of the data format used
>    to set and get time and interval values. Also note that some
>    implementations may choose to adjust time and/or interval values to
>    exactly match the ticks of the underlying clock."
> 
> which seems to imply that rounding up is what is desired here as well,
> although I presume here the actual resolution of the clock is supposed
> to be used.  But for timers associated with the
> CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID that would be
> realstathz, which is still tick-like...
> 
> In other words, I'm not convinced...
> 

I adjusted Paul de Weerds timer.c code to work with all three setitimer
clocks. The result is this:

Before:

ITIMER_REAL
timeout  800000us min/avg/max/std-dev: 800208/808854.500/811085/3043.725 us
timeout  400000us min/avg/max/std-dev: 400210/409098.031/410645/2786.929 us
timeout  200000us min/avg/max/std-dev: 200035/209098.641/212912/2759.900 us
timeout  100000us min/avg/max/std-dev: 100025/108900.367/110360/3057.488 us
timeout   50000us min/avg/max/std-dev: 50025/59198.781/61234/2680.975 us
timeout   25000us min/avg/max/std-dev: 28997/29999.529/31023/200.045 us
timeout   12500us min/avg/max/std-dev: 17508/20103.311/27802/896.630 us
timeout    6250us min/avg/max/std-dev: 10026/18596.189/23655/3354.573 us
timeout    3125us min/avg/max/std-dev: 10087/18304.020/21226/3679.233 us
timeout    1562us min/avg/max/std-dev: 10059/19395.580/20615/2335.428 us
timeout     781us min/avg/max/std-dev: 10038/19299.439/28400/2792.181 us
timeout     390us min/avg/max/std-dev: 10193/19502.061/21132/2122.942 us
timeout     195us min/avg/max/std-dev: 10068/19297.430/21386/2517.788 us
timeout      97us min/avg/max/std-dev: 10214/19799.789/20804/1372.321 us
timeout      48us min/avg/max/std-dev: 10032/19399.801/28896/2668.078 us
timeout      24us min/avg/max/std-dev: 10106/19599.900/20936/1930.546 us
timeout      12us min/avg/max/std-dev: 10203/19799.570/20952/1379.133 us
timeout       6us min/avg/max/std-dev: 10047/19799.711/21452/1406.507 us
timeout       3us min/avg/max/std-dev: 10035/18699.750/20984/3237.439 us
timeout       1us min/avg/max/std-dev: 10036/19499.779/20631/2148.104 us
ITIMER_VIRTUAL
timeout  800000us min/avg/max/std-dev: 766035/802268.312/860000/15187.871 us
timeout  400000us min/avg/max/std-dev: 372155/400825.844/497840/14646.898 us
timeout  200000us min/avg/max/std-dev: 182798/200070.953/217841/6382.939 us
timeout  100000us min/avg/max/std-dev: 85393/100599.352/118195/5079.172 us
timeout   50000us min/avg/max/std-dev: 32158/49660.000/62153/3548.212 us
timeout   25000us min/avg/max/std-dev: 22158/30199.730/39995/2776.258 us
timeout   12500us min/avg/max/std-dev: 13231/20539.410/33248/3425.671 us
timeout    6250us min/avg/max/std-dev: 2534/9999.680/20004/2506.703 us
timeout    3125us min/avg/max/std-dev: 3959/10081.800/20003/1933.720 us
timeout    1562us min/avg/max/std-dev: 2160/9845.760/14616/1819.296 us
timeout     781us min/avg/max/std-dev: 1798/9971.950/20004/2190.388 us
timeout     390us min/avg/max/std-dev: 2184/10481.690/20012/3139.951 us
timeout     195us min/avg/max/std-dev: 3234/10045.700/17847/2251.113 us
timeout      97us min/avg/max/std-dev: 3201/10353.440/20004/2578.286 us
timeout      48us min/avg/max/std-dev: 3214/10099.440/20006/2476.438 us
timeout      24us min/avg/max/std-dev: 3235/10145.650/21359/2371.112 us
timeout      12us min/avg/max/std-dev: 3258/9971.990/20004/1779.954 us
timeout       6us min/avg/max/std-dev: 3240/10081.800/20004/2195.738 us
timeout       3us min/avg/max/std-dev: 3255/10017.840/22161/1872.433 us
timeout       1us min/avg/max/std-dev: 6043/10427.980/26771/2577.006 us
ITIMER_PROF
timeout  800000us min/avg/max/std-dev: 773957/825628.500/1291795/65319.603 us
timeout  400000us min/avg/max/std-dev: 359999/413765.438/555388/34798.846 us
timeout  200000us min/avg/max/std-dev: 163174/203752.922/316906/19732.160 us
timeout  100000us min/avg/max/std-dev: 69984/108577.547/309999/31115.503 us
timeout   50000us min/avg/max/std-dev: 25432/54867.051/122835/16381.745 us
timeout   25000us min/avg/max/std-dev: 17057/31432.080/108412/9305.043 us
timeout   12500us min/avg/max/std-dev: 7191/20267.301/33960/4862.938 us
timeout    6250us min/avg/max/std-dev: 1730/11271.320/41803/6833.725 us
timeout    3125us min/avg/max/std-dev: 3118/10427.890/20008/2959.521 us
timeout    1562us min/avg/max/std-dev: 2800/9932.020/22164/3489.845 us
timeout     781us min/avg/max/std-dev: 3093/10399.650/23224/3625.505 us
timeout     390us min/avg/max/std-dev: 2162/10199.760/30007/3434.499 us
timeout     195us min/avg/max/std-dev: 3237/10267.140/20006/2908.820 us
timeout      97us min/avg/max/std-dev: 2149/10753.720/69994/6621.012 us
timeout      48us min/avg/max/std-dev: 2033/10299.800/20004/2885.025 us
timeout      24us min/avg/max/std-dev: 485/10178.170/21315/3291.616 us
timeout      12us min/avg/max/std-dev: 3164/9999.390/16836/2610.197 us
timeout       6us min/avg/max/std-dev: 2158/9721.350/20005/2925.856 us
timeout       3us min/avg/max/std-dev: 3147/10717.670/20005/3186.014 us
timeout       1us min/avg/max/std-dev: 1774/10181.730/26038/3625.016 us

After:
ITIMER_REAL
timeout  800000us min/avg/max/std-dev: 803100/803985.938/804058/205.714 us
timeout  400000us min/avg/max/std-dev: 400952/402097.844/407683/719.658 us
timeout  200000us min/avg/max/std-dev: 200209/201099.375/209316/854.072 us
timeout  100000us min/avg/max/std-dev: 100197/100499.148/100800/69.824 us
timeout   50000us min/avg/max/std-dev: 50024/50350.051/59947/965.817 us
timeout   25000us min/avg/max/std-dev: 29356/30149.439/30922/130.371 us
timeout   12500us min/avg/max/std-dev: 20045/20099.689/20155/13.412 us
timeout    6250us min/avg/max/std-dev: 8271/10150.280/16362/769.947 us
timeout    3125us min/avg/max/std-dev: 9608/10049.960/10491/119.870 us
timeout    1562us min/avg/max/std-dev: 8076/10049.690/12737/412.012 us
timeout     781us min/avg/max/std-dev: 9541/10050.100/10559/137.557 us
timeout     390us min/avg/max/std-dev: 9663/10049.610/10448/115.429 us
timeout     195us min/avg/max/std-dev: 9729/10049.820/10373/46.558 us
timeout      97us min/avg/max/std-dev: 9732/10049.860/10368/45.814 us
timeout      48us min/avg/max/std-dev: 9738/10049.810/10362/46.385 us
timeout      24us min/avg/max/std-dev: 9615/10049.620/10485/117.845 us
timeout      12us min/avg/max/std-dev: 9739/10049.780/10359/44.860 us
timeout       6us min/avg/max/std-dev: 9730/10050.020/10368/46.513 us
timeout       3us min/avg/max/std-dev: 9730/10049.850/10371/46.334 us
timeout       1us min/avg/max/std-dev: 9729/10049.920/10369/46.450 us
ITIMER_VIRTUAL
timeout  800000us min/avg/max/std-dev: 789569/804457.438/830156/5440.643 us
timeout  400000us min/avg/max/std-dev: 391946/402120.188/410366/3031.344 us
timeout  200000us min/avg/max/std-dev: 194356/200088.641/204765/1108.089 us
timeout  100000us min/avg/max/std-dev: 91674/99899.289/104355/1100.726 us
timeout   50000us min/avg/max/std-dev: 45647/50121.762/60004/1267.733 us
timeout   25000us min/avg/max/std-dev: 27787/29999.711/32218/313.228 us
timeout   12500us min/avg/max/std-dev: 8337/19799.750/26567/1590.757 us
timeout    6250us min/avg/max/std-dev: 3424/10012.570/18332/1096.381 us
timeout    3125us min/avg/max/std-dev: 9999/10010.560/10046/19.419 us
timeout    1562us min/avg/max/std-dev: 9997/9999.860/10000/0.974 us
timeout     781us min/avg/max/std-dev: 9998/9999.890/10000/2.649 us
timeout     390us min/avg/max/std-dev: 8241/10022.020/13976/434.222 us
timeout     195us min/avg/max/std-dev: 9995/9999.840/10000/3.332 us
timeout      97us min/avg/max/std-dev: 3436/9934.190/10001/653.082 us
timeout      48us min/avg/max/std-dev: 9994/9999.820/10000/-nan us
timeout      24us min/avg/max/std-dev: 9997/10043.440/14358/433.618 us
timeout      12us min/avg/max/std-dev: 9996/9999.850/10000/2.791 us
timeout       6us min/avg/max/std-dev: 9999/9999.900/10001/-nan us
timeout       3us min/avg/max/std-dev: 9997/10039.640/12218/280.492 us
timeout       1us min/avg/max/std-dev: 9700/9999.790/10300/43.534 us
ITIMER_PROF
timeout  800000us min/avg/max/std-dev: 791669/800155.375/809999/2688.569 us
timeout  400000us min/avg/max/std-dev: 391674/400119.594/408324/2849.512 us
timeout  200000us min/avg/max/std-dev: 187787/199916.219/206569/1862.663 us
timeout  100000us min/avg/max/std-dev: 91676/99899.297/108328/1663.900 us
timeout   50000us min/avg/max/std-dev: 41678/49916.352/58332/1439.452 us
timeout   25000us min/avg/max/std-dev: 28327/29999.699/31678/240.663 us
timeout   12500us min/avg/max/std-dev: 11666/20199.760/29999/1845.135 us
timeout    6250us min/avg/max/std-dev: 9994/9999.850/10000/2.791 us
timeout    3125us min/avg/max/std-dev: 9997/9999.860/10001/0.974 us
timeout    1562us min/avg/max/std-dev: 9995/9999.880/10007/1.526 us
timeout     781us min/avg/max/std-dev: 9700/10083.090/18330/829.971 us
timeout     390us min/avg/max/std-dev: 3435/9916.600/10298/676.252 us
timeout     195us min/avg/max/std-dev: 9996/9999.880/10001/1.526 us
timeout      97us min/avg/max/std-dev: 9984/10043.390/14372/435.059 us
timeout      48us min/avg/max/std-dev: 9994/9999.860/10000/0.974 us
timeout      24us min/avg/max/std-dev: 2240/9856.300/10000/1006.313 us
timeout      12us min/avg/max/std-dev: 1628/9999.790/18330/1181.026 us
timeout       6us min/avg/max/std-dev: 1642/9999.750/18329/1179.956 us
timeout       3us min/avg/max/std-dev: 9986/9999.860/10013/0.974 us
timeout       1us min/avg/max/std-dev: 9998/10065.560/16573/654.033 us

Looking at the numbers I think the result is actually what we want. Once
the timeout is below 1/HZs the avg time slept is pretty much 1 tick.
The profiling and virtual timers seem to be fairly close to before on avg
but the std-dec seems to be better but this could be just my luck.

Below the timer.c code I used.
-- 
:wq Claudio


#include <err.h>
#include <errno.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>

#define LOOPCOUNT 100

volatile sig_atomic_t trigger;

void
sighdlr(int signum) {
        trigger = signum;
}

static void
test(int which)
{
        struct itimerval        new_timer = { 0 };
        struct timeval          str, end;
        long long               count, d, sum, min, max, tsumsq;
        long                    timeout;
        double                  avg, dev, dummy;

        for (timeout = 800000; timeout != 0; timeout /= 2) {
                new_timer.it_value.tv_usec = timeout;
                min = 1000000000;
                max = 0;
                sum = 0;
                tsumsq = 0;
                for (count = 0; count != LOOPCOUNT; count++) {
                        trigger = 0;
                        gettimeofday(&str, NULL);
                        setitimer(which, &new_timer, NULL);
                        dummy = 1.0;
                        while (trigger == 0) {
                                dummy += sqrt(dummy);
                        }
                        gettimeofday(&end, NULL);
                        d = (end.tv_sec - str.tv_sec) * 1000000 +
                            end.tv_usec - str.tv_usec;
                        sum += d;
                        tsumsq += d * d;
                        if (d < min)
                                min = d;
                        if (d > max)
                                max = d;
                }
                avg = (float) sum / count;
                dev = sqrt((float) tsumsq / count - avg * avg);
                printf("timeout %7ldus min/avg/max/std-dev: %lld/%.3f/"
                    "%lld/%.3f us\n", timeout, min, avg, max, dev);
        }
}

int
main(int argc, char ** argv)
{
        signal(SIGALRM, sighdlr);
        signal(SIGVTALRM, sighdlr);
        signal(SIGPROF, sighdlr);

        printf("Running for %d loops\n\n", LOOPCOUNT);

        printf("ITIMER_REAL\n");
        test(ITIMER_REAL);
        printf("ITIMER_VIRTUAL\n");
        test(ITIMER_VIRTUAL);
        printf("ITIMER_PROF\n");
        test(ITIMER_PROF);
}

Reply via email to