如何在 Linux 中创建高分辨率计时器来测量程序性能?

2024-10-11 08:36:00
admin
原创
71
摘要:问题描述:我正在尝试比较 GPU 与 CPU 的性能。对于 NVIDIA GPU,我一直使用这些cudaEvent_t类型来获得非常精确的时间。对于 CPU,我一直使用以下代码:// Timers clock_t start, stop; float elapsedTime = 0; // Capture ...

问题描述:

我正在尝试比较 GPU 与 CPU 的性能。对于 NVIDIA GPU,我一直使用这些cudaEvent_t类型来获得非常精确的时间。

对于 CPU,我一直使用以下代码:

// Timers
clock_t start, stop;
float elapsedTime = 0;

// Capture the start time

start = clock();

// Do something here
.......

// Capture the stop time
stop = clock();
// Retrieve time elapsed in milliseconds
elapsedTime = (float)(stop - start) / (float)CLOCKS_PER_SEC * 1000.0f;

显然,这段代码只适用于以秒为单位计算的情况。而且,结果有时会很奇怪。

有人知道在 Linux 中创建高分辨率计时器的方法吗?


解决方案 1:

查看clock_gettime,它是高分辨率计时器的 POSIX 接口。

CLOCK_REALTIME如果阅读了手册页后,您仍对和之间的区别感到疑惑CLOCK_MONOTONIC,请参阅CLOCK_REALTIME 和 CLOCK_MONOTONIC 之间的区别?

请参阅以下页面以获取完整示例:http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/

#include <iostream>
#include <time.h>
using namespace std;

timespec diff(timespec start, timespec end);

int main()
{
    timespec time1, time2;
    int temp;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
    for (int i = 0; i< 242000000; i++)
        temp+=temp;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
    cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
    return 0;
}

timespec diff(timespec start, timespec end)
{
    timespec temp;
    if ((end.tv_nsec-start.tv_nsec)<0) {
        temp.tv_sec = end.tv_sec-start.tv_sec-1;
        temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
    } else {
        temp.tv_sec = end.tv_sec-start.tv_sec;
        temp.tv_nsec = end.tv_nsec-start.tv_nsec;
    }
    return temp;
}

解决方案 2:

总结目前提供的信息,这是典型应用所需的两个功能。

#include <time.h>

// call this function to start a nanosecond-resolution timer
struct timespec timer_start(){
    struct timespec start_time;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
    return start_time;
}

// call this function to end a timer, returning nanoseconds elapsed as a long
long timer_end(struct timespec start_time){
    struct timespec end_time;
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time);
    long diffInNanos = (end_time.tv_sec - start_time.tv_sec) * (long)1e9 + (end_time.tv_nsec - start_time.tv_nsec);
    return diffInNanos;
}

下面是一个示例,说明如何使用它们来计算输入列表的方差所需的时间。

struct timespec vartime = timer_start();  // begin a timer called 'vartime'
double variance = var(input, MAXLEN);  // perform the task we want to time
long time_elapsed_nanos = timer_end(vartime);
printf("Variance = %f, Time taken (nanoseconds): %ld
", variance, time_elapsed_nanos);

解决方案 3:

struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);

还有 CLOCK_REALTIME_HR,但我不确定它是否有任何区别。

解决方案 4:

您对挂钟时间 (实际经过了多少时间) 或循环计数 (有多少个循环) 感兴趣吗?在第一种情况下,您应该使用类似 的内容gettimeofday

最高分辨率计时器使用RDTSCx86 汇编指令。但是,这会测量时钟滴答,因此您应该确保已禁用省电模式。

TSC 的 wiki 页面给出了一些示例:http://en.wikipedia.org/wiki/Time_Stamp_Counter

解决方案 5:

阅读完该帖子后,我开始测试 clock_gettime 的代码与 c++11 的 chrono 的代码,但它们似乎不匹配。

他们之间的差距实在太大了!

std ::chrono::seconds(1)似乎相当于clock_gettime~70,000

#include <ctime>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <thread>
#include <chrono>
#include <iomanip>
#include <vector>
#include <mutex>

timespec diff(timespec start, timespec end);
timespec get_cpu_now_time();
std::vector<timespec> get_start_end_pairs();
std::vector<timespec> get_start_end_pairs2();
void output_deltas(const std::vector<timespec> &start_end_pairs);

//=============================================================
int main()
{
    std::cout << "Hello waiter" << std::endl; // flush is intentional
    std::vector<timespec> start_end_pairs = get_start_end_pairs2();
    output_deltas(start_end_pairs);

    return EXIT_SUCCESS;
}

//=============================================================
std::vector<timespec> get_start_end_pairs()
{
    std::vector<timespec> start_end_pairs;
    for (int i = 0; i < 20; ++i)
    {
        start_end_pairs.push_back(get_cpu_now_time());
        std::this_thread::sleep_for(std::chrono::seconds(1));
        start_end_pairs.push_back(get_cpu_now_time());
    }

    return start_end_pairs;
}


//=============================================================
std::vector<timespec> get_start_end_pairs2()
{
    std::mutex mu;
    std::vector<std::thread> workers;
    std::vector<timespec> start_end_pairs;
    for (int i = 0; i < 20; ++i) {
        workers.emplace_back([&]()->void {
            auto start_time = get_cpu_now_time();
            std::this_thread::sleep_for(std::chrono::seconds(1));
            auto end_time = get_cpu_now_time();
            std::lock_guard<std::mutex> locker(mu);
            start_end_pairs.emplace_back(start_time);
            start_end_pairs.emplace_back(end_time);
        });
    }

    for (auto &worker: workers) {
        if (worker.joinable()) {
            worker.join();
        }
    }

    return start_end_pairs;
}

//=============================================================
void output_deltas(const std::vector<timespec> &start_end_pairs)
{
    std::cout << "size: " << start_end_pairs.size() << std::endl;
    for (auto it_start = start_end_pairs.begin(); it_start < start_end_pairs.end(); it_start += 2)
    {
        auto it_end = it_start + 1;
        auto delta = diff(*it_start, *it_end);

        std::cout
                << std::setw(2)
                << std::setfill(' ')
                << std::distance(start_end_pairs.begin(), it_start) / 2
                << " Waited ("
                << delta.tv_sec
                << "    s    "
                << std::setw(9)
                << std::setfill('0')
                << delta.tv_nsec
                << "    ns)"
                << std::endl;
    }
}

//=============================================================
timespec diff(timespec start, timespec end)
{
    timespec temp;
    temp.tv_sec = end.tv_sec-start.tv_sec;
    temp.tv_nsec = end.tv_nsec-start.tv_nsec;

    if (temp.tv_nsec < 0) {
        --temp.tv_sec;
        temp.tv_nsec += 1000000000;
    }
    return temp;
}

//=============================================================
timespec get_cpu_now_time()
{
    timespec now_time;
    memset(&now_time, 0, sizeof(timespec));
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now_time);

    return now_time;
}

输出:

Hello waiter
 0 Waited (0    s       000843254       ns)
 1 Waited (0    s       000681141       ns)
 2 Waited (0    s       000685119       ns)
 3 Waited (0    s       000674252       ns)
 4 Waited (0    s       000714877       ns)
 5 Waited (0    s       000624202       ns)
 6 Waited (0    s       000746091       ns)
 7 Waited (0    s       000575267       ns)
 8 Waited (0    s       000860157       ns)
 9 Waited (0    s       000827479       ns)
10 Waited (0    s       000612959       ns)
11 Waited (0    s       000534818       ns)
12 Waited (0    s       000553728       ns)
13 Waited (0    s       000586501       ns)
14 Waited (0    s       000627116       ns)
15 Waited (0    s       000616725       ns)
16 Waited (0    s       000616507       ns)
17 Waited (0    s       000641251       ns)
18 Waited (0    s       000683380       ns)
19 Waited (0    s       000850205       ns)

解决方案 6:

clock_gettime(2)

解决方案 7:

epoll 实现:
https: //github.com/ielife/simple-timer-for-c-language

像这样使用:

timer_server_handle_t *timer_handle = timer_server_init(1024);
if (NULL == timer_handle) {
    fprintf(stderr, "timer_server_init failed
");
    return -1;
}
ctimer timer1;
    timer1.count_ = 3;
    timer1.timer_internal_ = 0.5;
    timer1.timer_cb_ = timer_cb1;
    int *user_data1 = (int *)malloc(sizeof(int));
    *user_data1 = 100;
    timer1.user_data_ = user_data1;
    timer_server_addtimer(timer_handle, &timer1);

    ctimer timer2;
    timer2.count_ = -1;
    timer2.timer_internal_ = 0.5;
    timer2.timer_cb_ = timer_cb2;
    int *user_data2 = (int *)malloc(sizeof(int));
    *user_data2 = 10;
    timer2.user_data_ = user_data2;
    timer_server_addtimer(timer_handle, &timer2);

    sleep(10);

    timer_server_deltimer(timer_handle, timer1.fd);
    timer_server_deltimer(timer_handle, timer2.fd);
    timer_server_uninit(timer_handle);
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用