mic*_*ael 3 c++ linux time cpu-registers
我正在实现一些数据结构,其中我需要在一段时间后使某些条目无效,因此对于每个条目,我需要维护其插入时间戳。当我得到一个条目时,我需要再次获取时间戳并计算从插入开始的经过时间(如果它太旧,我无法使用它)。
许多线程高度满足此数据结构,因此我必须以最有效的方式获取此时间戳(oninsert和find)。效率在这里非常重要。
如果重要的话,我正在使用 C++ 开发的 linux 机器上工作。检索时间戳的最有效方法是什么?
顺便说一句,在我正在做的一些旧项目中,我记得我看到了一些直接从 CPU 获取时间戳的汇编命令(不记得命令了)。
我创建了以下基准来测试检索时间戳的几种方法。基准测试是用 GCC 和 -O2 编译的,并在我的 mac 上进行了测试。我已经测量了每种方法获得 100 万个时间戳所需的时间,从结果来看,它看起来rdtsc比其他方法更快。
编辑:修改了基准测试以支持多线程。
基准代码:
#include <iostream>
#include <chrono>
#include <sys/time.h>
#include <unistd.h>
#include <vector>
#include <thread>
#include <atomic>
#define NUM_SAMPLES 1000000
#define NUM_THREADS 4
static inline unsigned long long getticks(void)
{
unsigned int lo, hi;
// RDTSC copies contents of 64-bit TSC into EDX:EAX
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (unsigned long long)hi << 32 | lo;
}
std::atomic<bool> g_start(false);
std::atomic<unsigned int> totalTime(0);
template<typename Method>
void measureFunc(Method method)
{
// warmup
for (unsigned int i = 0; i < NUM_SAMPLES; i++)
{
method();
}
auto start = std::chrono::system_clock::now();
for (unsigned int i = 0; i < NUM_SAMPLES; i++)
{
method();
}
auto end = std::chrono::system_clock::now();
totalTime += std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
template<typename Method>
void measureThread(Method method)
{
while(!g_start.load());
measureFunc(method);
}
template<typename Method>
void measure(const std::string& methodName, Method method)
{
std::vector<std::thread> threads;
totalTime.store(0);
g_start.store(false);
for (unsigned int i = 0; i < NUM_THREADS; i++)
{
threads.push_back(std::thread(measureThread<Method>, method));
}
g_start.store(true);
for (std::thread& th : threads)
{
th.join();
}
double timePerThread = (double)totalTime / (double)NUM_THREADS;
std::cout << methodName << ": " << timePerThread << "ms per thread" << std::endl;
}
int main(int argc, char** argv)
{
measure("gettimeofday", [](){ timeval tv; return gettimeofday(&tv, 0); });
measure("time", [](){ return time(NULL); });
measure("std chrono system_clock", [](){ return std::chrono::system_clock::now(); });
measure("std chrono steady_clock", [](){ return std::chrono::steady_clock::now(); });
measure("clock_gettime monotonic", [](){ timespec tp; return clock_gettime(CLOCK_MONOTONIC, &tp); });
measure("clock_gettime cpu time", [](){ timespec tp; return clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); });
measure("rdtsc", [](){ return getticks(); });
return 0;
}
Run Code Online (Sandbox Code Playgroud)
单个线程的结果(以毫秒为单位):
gettimeofday: 54ms per thread
time: 260ms per thread
std chrono system_clock: 62ms per thread
std chrono steady_clock: 60ms per thread
clock_gettime monotonic: 102ms per thread
clock_gettime cpu time: 493ms per thread
rdtsc: 8ms per thread
Run Code Online (Sandbox Code Playgroud)
有 4 个线程:
gettimeofday: 55.25ms per thread
time: 292.5ms per thread
std chrono system_clock: 69.25ms per thread
std chrono steady_clock: 68.5ms per thread
clock_gettime monotonic: 118.25ms per thread
clock_gettime cpu time: 2975.75ms per thread
rdtsc: 10.25ms per thread
Run Code Online (Sandbox Code Playgroud)
从结果来看,std::chrono从多个线程调用时似乎有一些小开销,该gettimeofday方法随着线程数的增加而保持稳定。
| 归档时间: |
|
| 查看次数: |
3021 次 |
| 最近记录: |