系统调用成本
System call cost
我目前正在处理操作系统操作开销。
我实际上正在研究进行系统调用的成本,并且我开发了一个简单的 C++ 程序来观察它。
#include <iostream>
#include <unistd.h>
#include <sys/time.h>
uint64_t
rdtscp(void) {
uint32_t eax, edx;
__asm__ __volatile__("rdtscp" //! rdtscp instruction
: "+a" (eax), "=d" (edx) //! output
: //! input
: "%ecx"); //! registers
return (((uint64_t)edx << 32) | eax);
}
int main(void) {
uint64_t before;
uint64_t after;
struct timeval t;
for (unsigned int i = 0; i < 10; ++i) {
before = rdtscp();
gettimeofday(&t, NULL);
after = rdtscp();
std::cout << after - before << std::endl;
std::cout << t.tv_usec << std::endl;
}
return 0;
}
这个程序非常简单。
- rdtscp 函数只是调用 RTDSCP 指令(将 64 位周期计数加载到两个 32 位寄存器的处理器指令)的包装器。这个函数是用来取时的。
- 我迭代了10次。在每次迭代中,我调用 gettimeofday 并确定执行它所花费的时间(作为 CPU 个周期)。
结果出乎意料:
8984
64008
376
64049
164
64053
160
64056
160
64060
160
64063
164
64067
160
64070
160
64073
160
64077
输出中的奇数行是执行系统调用所需的周期数。偶数行是t.tv_usec中包含的值(由我正在研究的系统调用gettimeofday设置)。
我真的不明白这怎么可能:循环次数急剧减少,从近 10,000 到 150 左右!但是 timeval 结构仍然在每次调用时更新!
我试过不同的操作系统(debian 和 macos),结果是相似的。
就算用了缓存,我也看不出怎么可能。进行系统调用应该导致上下文切换以从用户模式切换到内核模式,我们仍然需要读取时钟以更新时间。
有人有想法吗?
答案是?尝试另一个系统调用。 linux 上有 vsyscalls,它们可以加速某些系统调用:
What are vdso and vsyscall?
简短版本:不执行系统调用,而是内核映射一个内存区域,进程可以在其中访问时间信息。成本 ?不多(没有上下文切换)。
我目前正在处理操作系统操作开销。
我实际上正在研究进行系统调用的成本,并且我开发了一个简单的 C++ 程序来观察它。
#include <iostream>
#include <unistd.h>
#include <sys/time.h>
uint64_t
rdtscp(void) {
uint32_t eax, edx;
__asm__ __volatile__("rdtscp" //! rdtscp instruction
: "+a" (eax), "=d" (edx) //! output
: //! input
: "%ecx"); //! registers
return (((uint64_t)edx << 32) | eax);
}
int main(void) {
uint64_t before;
uint64_t after;
struct timeval t;
for (unsigned int i = 0; i < 10; ++i) {
before = rdtscp();
gettimeofday(&t, NULL);
after = rdtscp();
std::cout << after - before << std::endl;
std::cout << t.tv_usec << std::endl;
}
return 0;
}
这个程序非常简单。
- rdtscp 函数只是调用 RTDSCP 指令(将 64 位周期计数加载到两个 32 位寄存器的处理器指令)的包装器。这个函数是用来取时的。
- 我迭代了10次。在每次迭代中,我调用 gettimeofday 并确定执行它所花费的时间(作为 CPU 个周期)。
结果出乎意料:
8984
64008
376
64049
164
64053
160
64056
160
64060
160
64063
164
64067
160
64070
160
64073
160
64077
输出中的奇数行是执行系统调用所需的周期数。偶数行是t.tv_usec中包含的值(由我正在研究的系统调用gettimeofday设置)。
我真的不明白这怎么可能:循环次数急剧减少,从近 10,000 到 150 左右!但是 timeval 结构仍然在每次调用时更新!
我试过不同的操作系统(debian 和 macos),结果是相似的。
就算用了缓存,我也看不出怎么可能。进行系统调用应该导致上下文切换以从用户模式切换到内核模式,我们仍然需要读取时钟以更新时间。
有人有想法吗?
答案是?尝试另一个系统调用。 linux 上有 vsyscalls,它们可以加速某些系统调用: What are vdso and vsyscall?
简短版本:不执行系统调用,而是内核映射一个内存区域,进程可以在其中访问时间信息。成本 ?不多(没有上下文切换)。