1

Question:

What is the resolution of the LINUX profile timer? Clearly, this is system specific, so I will provide more details below.

Background:

I am trying to use the Google GPerfTools suite, and I am finding that no matter how hard I try, I cannot get more than about 200 samples/second of CPU time (NOT wallclock time, that's even LOWER), even though the allowable max in the GPerfTools is 4000/second.

Please see this (unloved) question: /questions/22799490

In looking thru the GPerfTools code, I also found that it is using an ITIMER_PROF (no surprise there), and is using the setitimer(2) system call with the correct timestruct values (duh!):

void ProfileHandler::StartTimer() {
  if (!allowed_) {
    return;
  }
  struct itimerval timer;
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = 1000000 / frequency_;
  timer.it_value = timer.it_interval;
  setitimer(timer_type_, &timer, 0);
}

Thus, the limitation on sampling rate is either in a system ITIMER_PROF limitation, or a byproduct of how GPerfTools is interacting with the program I am profiling (perhaps the timer is going off when we're blocked on I/O? When that happens...maybe that doesn't count as a sample? :) )

System Specifics:

I am running on a standard x86_64 box running Ubuntu Linux. Here is my uname result: Linux <hostname> 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 17:37:58 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Program and the GPerfTools library were compiled in 32-bit mode. In fact, the configure step in the GPerfTools build was done in a 32-bit chroot'd jail setarch'd to i386.

Community
  • 1
  • 1
Mark Gerolimatos
  • 2,424
  • 1
  • 23
  • 33

1 Answers1

0

Repeated tests on different Ubuntu x86 LINUX boxes (including x86 VMs) all confirm 250/second, or a 4ms interval when actually using the CPU. Can this actually be correct in this day and age? Test program included below

Example results:

./itimer 200 3
freq = 200
timeout = 3
When over, you should see 599 firings
PERF timer fired 599 times
VIRTUAL timer fired 599 times

./itimer 500 3
freq = 500
timeout = 3
When over, you should see 1499 firings
PERF timer fired 749 times
VIRTUAL timer fired 749 times

Test Program

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>

struct itimerval mrVal;
struct itimerval timeout;

int ncalls = 0;
int nvcalls = 0;
void killer(int signum)
{
    // Off by a few because we don't stop the timers,
    // but good enough for testing purposes
    printf("PERF timer fired %d times\n", ncalls);
    printf("VIRTUAL timer fired %d times\n", nvcalls);
    exit(0);
}

void interval_handler(int signum)
{
    ncalls += 1;
}

void virtual_handler(int signum)
{
    nvcalls += 1;
}

static double keeper = 12.345;

int main(int argc, char **argv)
{
    if (argc < 3) {
        printf("Usage: itimer freq seconds-to-run\n");
        exit(1);
    }
    int freq = atoi(argv[1]);
    int sleepsex = atoi(argv[2]);
    printf("freq = %d\n", freq);
    printf("timeout = %d\n", sleepsex);
    printf("When over, you should see %d firings\n",
                    (freq * sleepsex) - 1);

    timeout.it_interval.tv_sec = sleepsex;
    timeout.it_interval.tv_usec = 0;
    timeout.it_value = timeout.it_interval;

    mrVal.it_interval.tv_sec = 0;
    mrVal.it_interval.tv_usec = 1000000 / freq;
    mrVal.it_value = mrVal.it_interval;
    if(signal(SIGPROF, interval_handler) == SIG_ERR) {
        printf("HOSER!\n");
    }
    if(signal(SIGVTALRM, virtual_handler) == SIG_ERR) {
        printf("HOSER!\n");
    }
    if(signal(SIGALRM, killer) == SIG_ERR) {
        printf("HOSER!\n");
    }
    if(signal(SIGINT, killer) == SIG_ERR) {
        printf("HOSER!\n");
    }
    setitimer(ITIMER_PROF, &mrVal, 0);
    setitimer(ITIMER_VIRTUAL, &mrVal, 0);
#if 1
    // Use CPU. Otherwise, the PERF timer doesn't go off
    // Trivial floating point stuff that counts good enough
    // as work
    setitimer(ITIMER_REAL, &timeout, 0);
    while(1) {
        double d = keeper;
        d/=1.3773;
        d*=1.3777;
        keeper = d;
    }
#else
    sleep(sleepsex);
    killer(0);
#endif
}
Mark Gerolimatos
  • 2,424
  • 1
  • 23
  • 33
  • Is it the same value as `CONFIG_HZ` of linux kernel configuration? Usual values of HZ are: 100, 1000, 250 – osgx Oct 18 '15 at 01:57