Fix test issue on NetBSD: Walk-around getrusage(2) implementation nits
authorKamil Rytarowski <n54@gmx.com>
Sun, 21 Feb 2016 04:36:03 +0000 (05:36 +0100)
committerKamil Rytarowski <n54@gmx.com>
Sun, 21 Feb 2016 04:44:50 +0000 (05:44 +0100)
The following code:

int main(int argc, char **argv)
{
    int i, j, k, total;
    struct rusage resUsage1, resUsage2;

    if (getrusage (RUSAGE_SELF, &resUsage1) == -1)
        errx(1, "getrusage");

    /* simulate some activity */
    for( i=0; i<1000; i++ )
    {
        for( j=0; j<1000; j++ )
        {
            total = j * i;
            for( k=0; k<1000; k++ )
            {
                total += k + i;
            }
        }
    }

    if (getrusage (RUSAGE_SELF, &resUsage2) == -1)
        errx(1, "getrusage");

    printf("kernel1 %ld.%06ld\n", resUsage1.ru_stime.tv_sec, resUsage1.ru_stime.tv_usec);
    printf("kernel2 %ld.%06ld\n", resUsage2.ru_stime.tv_sec, resUsage2.ru_stime.tv_usec);

    printf("user1 %ld.%06ld\n", resUsage1.ru_utime.tv_sec, resUsage1.ru_utime.tv_usec);
    printf("user2 %ld.%06ld\n", resUsage2.ru_utime.tv_sec, resUsage2.ru_utime.tv_usec);

    return 0;
}

Returns the following values:

$ ./test
kernel1 0.000262
kernel2 0.000000
user1 0.000262
user2 2.279965

The reason for it is as follows:

    The reason is that the scheduler keeps a precise total cpu time of
    a process but the systime/usertime is only sampled by a much slower
    clock. The ratio systime/usertime is then used to return an approximation
    so that systime and usertime sum up to the total time(*).

    As a result it is possible that usertime or systime go backwards.

    FreeBSD has implemented a workaround by remembering reported
    usertime/systime values for a process and clamping getrusage()
    against these values. As a result the usertime/systime value
    is usually too high but it is monotonic.

    Another approach would be to round down the usertime/systime values,
    by not approximating 'measurments' that do not exist. The result
    would be that usertime/systime values that are too low and don't
    sum up to the total CPU time but are again monotonic.

    The approximation is done in kern_resource/calc().
    (*) The sampled interrupt time is also included.

-- by Michael van Elst
-- http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=30115

Walkaround it by doing kernel-work with subsequent malloc(3) and free(3) calls.
Note that doing these calls for smaller chunks (it looks like a compiler/libc
can optimize it without going to the host kernel) or just 1000 times is not
sufficient.

Commit migrated from https://github.com/dotnet/coreclr/commit/4c389ad3e373cf4bb6ae643e8a91b7104eb6c39a

src/coreclr/src/pal/tests/palsuite/threading/GetProcessTimes/test2/test2.c

index e2e7411..687facc 100644 (file)
@@ -25,7 +25,7 @@ int __cdecl main( int argc, char **argv )
 
 {
     int i, j, k;
-    int total = 0;
+    int *total;
     
     HANDLE hProcess;    
     FILETIME createTime;
@@ -76,11 +76,16 @@ int __cdecl main( int argc, char **argv )
     {
         for( j=0; j<1000; j++ )
         {
-            total = j * i;
+            /* do kernel work to increase system usage counters */
+            total = malloc(1024 * 1024);
+
+            *total = j * i;
             for( k=0; k<1000; k++ )
             {
-                total += k + i;
+                *total += k + i;
             }
+
+            free(total);
         }
     }