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