问题:
LINUX 配置文件计时器的分辨率是多少?显然,这是特定于系统的,因此我将在下面提供更多详细信息。
背景:
我正在尝试使用Google GPerfTools套件,我发现无论我多么努力,我都无法获得超过每秒200个样本的CPU时间(不是挂钟时间,甚至更低),即使GPerfTools中允许的最大时间是4000/秒。
请看这个(不受欢迎的)问题:/问题/22799490
在查看 GPerfTools 代码时,我还发现它正在使用ITIMER_PROF
(这并不奇怪),并且正在使用具有正确时间结构值的setitimer(2)
系统调用(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);
}
因此,采样率的限制要么是系统ITIMER_PROF限制,要么是 GPerfTools 如何与我正在分析的程序交互的副产品(也许当我们在 I/O 上被阻止时计时器会关闭?当这种情况发生时...也许这不算样本?:) )
系统细节:
我正在运行运行Ubuntu Linux的标准x86_64盒。这是我的 uname 结果: 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
程序和GPerfTools库以32位模式编译。事实上,GPerfTools 构建中的configure
步骤是在 i386 setarch'd
32 位chroot'd
监狱中完成的。
LINUX 盒子(包括 x86 VM)上重复测试都确认了 250/秒,或实际使用 CPU 时的 4ms 间隔。在这个时代,这真的是正确的吗?测试程序包括以下内容
示例结果:
./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
测试程序
#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 timesn", ncalls);
printf("VIRTUAL timer fired %d timesn", 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-runn");
exit(1);
}
int freq = atoi(argv[1]);
int sleepsex = atoi(argv[2]);
printf("freq = %dn", freq);
printf("timeout = %dn", sleepsex);
printf("When over, you should see %d firingsn",
(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
}