【问题标题】:Computing CPU time in C++ on Windows在 Windows 上用 C++ 计算 CPU 时间
【发布时间】:2012-09-26 15:55:36
【问题描述】:

在 C++ 中有什么方法可以计算运行给定程序或例程需要多长时间在 CPU 时间中

我使用在 Windows 7 上运行的 Visual Studio 2008。

【问题讨论】:

  • 如果您使用的是 POSIX 系统,请查看getrusage
  • 这是一个依赖于平台的非概念性问题,因此它属于 SO,而不是这里。
  • 我使用在 Windows 7 上运行的 Visual Studio 2008。我已经编辑了我的问题。感谢您将其移至正确的论坛。 :)
  • @pyCthon,我想我很困惑。我认为在 Windows 7 上的 Visual C++ 中存在某种问题,因此 time.h 函数没有提供任何方法来测量 CPU 时间,而只是 实际经过的时间
  • 我的意思是,this example 会满足我的需求吗?期待您的反馈。

标签: c++ performance visual-studio-2008 windows-7 cpu-usage


【解决方案1】:

如果您想知道进程使用的 CPU 时间总量,clockrdtsc(直接或通过编译器内在函数)都不是最好的选择,至少在 IMO 中是这样。如果您需要代码可移植,您可以做的最好的事情是使用clock,在系统尽可能静止的情况下进行测试,并希望最好(但如果您这样做,请注意clock 的分辨率是CLOCKS_PER_SEC,它可能是也可能不是1000,即使是,你的实际时间分辨率通常也不会那么好——它可能会给你以毫秒为单位的时间,但至少通常会提前几十毫秒时间)。

但是,由于您似乎并不介意特定于 Windows 的代码,因此您可以做得更好。至少如果我对您正在寻找的内容的理解是正确的,那么您真正想要的可能是GetProcessTimes,它将(分别)告诉您进程的内核模式和用户模式 ​​CPU 使用情况(以及开始时间和退出时间,如果你关心的话,你可以从中计算出所用的时间)。还有QueryProcessCycleTime,它会告诉你进程使用的CPU时钟周期总数(所有线程中用户模式和内核模式的总和)。就个人而言,我很难想象后者有多大用处——计算单个时钟周期对于部分需要进行密集优化的代码很有用,但我不太确定你是如何使用的d 将其应用到一个完整的过程中。 GetProcessTimes 使用 FILETIME 结构,它支持 100 纳秒的分辨率,但实际上大多数时候您会看到调度程序的时间片的倍数(随 windows 的版本而异,但在毫秒到几十毫秒)。

无论如何,如果您真的想要从头到尾的时间,GetProcessTimes 会让您这样做——如果您生成程序(例如,使用 CreateProcess),您将获得该过程的句柄这将在子进程退出时发出信号。然后,您可以在该句柄上调用 GetProcessTimes,并检索时间,即使孩子已经退出 - 只要该进程的至少一个句柄保持打开状态,该句柄就会保持有效。

【讨论】:

  • 谢谢你,@Jerry。 @Doc pointed out clock() 在 Windows 环境中使用时不提供 CPU 时间,而是提供挂钟时间。与GetProcessTimes 不一样,是吗?我的意思是,我猜它在 Windows 上运行良好,因为您引用的文档是关于 Windows 的。顺便说一句,我应该添加哪个库才能使其正常工作?
  • @Vicent:很像任何 Windows 程序——你 #include <windows.h> 并与 kernel32.lib 链接——但本质上 所有 Windows 程序都与 kernel32.lib 链接,所以你可能不需要做任何事情来获得它。
【解决方案2】:

这是一种方法。它以毫秒为单位测量例行执行时间。

clock_t begin=clock(); 在路由执行之前启动,clock_t end=clock(); 在例程退出后立即启动。

然后将两个时间集相减,结果是毫秒值。

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

double get_CPU_time_usage(clock_t clock1,clock_t clock2)
{
    double diffticks=clock1-clock2;
    double diffms=(diffticks*1000)/CLOCKS_PER_SEC;
    return diffms;
} 

void test_CPU_usage()
{
  cout << "Standby.. measuring exeution time:  ";

  for (int i=0; i<10000;i++)
  {
        cout << "\b\\" << std::flush;
        cout << "\b|" << std::flush;
        cout << "\b/" << std::flush;
        cout << "\b-" << std::flush;
  }

  cout << " \n\n";
}

int main (void)
{

    clock_t begin=clock();

    test_CPU_usage();

    clock_t end=clock();

    cout << "Time elapsed: " << double(get_CPU_time_usage(end,begin)) << " ms ("<<double(get_CPU_time_usage(end,begin))/1000<<" sec) \n\n";
    return 0;
}

【讨论】:

  • 我再次认为这是衡量执行时间,而不是CPU时间?
  • 好的,谢谢。我认为this other example 是相似的......我很困惑,我认为在 Windows 上的 Visual C++ 中计算 CPU 时间存在问题。对不起,再次感谢您!!! :)
  • @AK4749,你为什么这么认为?
  • 詹姆斯的回答至少测量了真正的 CPU 时间,尽管他提到你应该小心使用这样一个函数的结果
  • @Vicent: AFAIK clock 在 Unix 或 Linux 下测量 CPU 时间,但在 Windows 下测量挂钟时间(参见此处msdn.microsoft.com/en-us/library/4e2ess30%28v=vs.110%29.aspx
【解决方案3】:

__rdtscp 内在函数将为您提供 CPU 周期时间,但有一些注意事项。 这里是the MSDN article

这实际上取决于您要测量的内容。为了获得更好的结果,平均进行几百万(如果不是十亿)次迭代。

【讨论】:

  • 谢谢你,@James。您如何看待@Clark 提出的解决方案,使用clock() 函数??
  • @Vicent 这取决于你想测量什么
  • 我想测量程序在执行时真正使用的时间,从开始到结束。据我所知,它通常被称为CPU time。是否有任何相关的概念、微妙的细节……应该考虑到?
  • @Vicent 在这种情况下 rdtscp 对你来说可能分辨率太高了。使用时钟方法
【解决方案4】:

clock() 函数 [由 Visual C++ 2008 提供] 不返回程序使用的处理器时间,但它应该(根据 C 标准和/或 C++ 标准)。也就是说,为了测量 Windows 上的 CPU 时间,我有这个帮助类(它不可避免地是不可移植的):

class ProcessorTimer
{
  public:
    ProcessorTimer() { start(); }
    void start() { ::GetProcessTimes(::GetCurrentProcess(), &ft_[3], &ft_[2], &ft_[1], &ft_[0]); }
    std::tuple<double, double> stop()
    {
        ::GetProcessTimes(::GetCurrentProcess(), &ft_[5], &ft_[4], &ft_[3], &ft_[2]);
        ULARGE_INTEGER u[4];
        for (size_t i = 0; i < 4; ++i)
        {
            u[i].LowPart = ft_[i].dwLowDateTime;
            u[i].HighPart = ft_[i].dwHighDateTime;
        }
        double user = (u[2].QuadPart - u[0].QuadPart) / 10000000.0;
        double kernel = (u[3].QuadPart - u[1].QuadPart) / 10000000.0;
        return std::make_tuple(user, kernel);
    }
  private:
    FILETIME ft_[6];
};


class ScopedProcessorTimer
{
  public:
    ScopedProcessorTimer(std::ostream& os = std::cerr) : timer_(ProcessorTimer()), os_(os) { }
    ~ScopedProcessorTimer()
    {
        std::tuple<double, double> t = timer_.stop();
        os_ << "user " << std::get<0>(t) << "\n";
        os_ << "kernel " << std::get<1>(t) << "\n";
    }
  private:
    ProcessorTimer timer_;
    std::ostream& os_;
}

例如,可以通过在该 {} 块的开头定义一个 ScopedProcessorTimer 来测量执行该块需要多长时间。

【讨论】:

【解决方案5】:

这段代码是进程CPU使用率

ULONGLONG LastCycleTime = NULL;
LARGE_INTEGER LastPCounter;
LastPCounter.QuadPart = 0; // LARGE_INTEGER Init

                           // cpu get core number
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
int numProcessors = sysInfo.dwNumberOfProcessors;

HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, Process::pid);

if (hProcess == NULL)
    nResult = 0;

int count = 0;
while (true)
{
    ULONG64 CycleTime;
    LARGE_INTEGER qpcLastInt;

    if (!QueryProcessCycleTime(hProcess, &CycleTime))
        nResult = 0;

    ULONG64 cycle = CycleTime - LastCycleTime;

    if (!QueryPerformanceCounter(&qpcLastInt))
        nResult = 0;

    double Usage = cycle / ((double)(qpcLastInt.QuadPart - LastPCounter.QuadPart));

    // Scaling
    Usage *= 1.0 / numProcessors;
    Usage *= 0.1;

    LastPCounter = qpcLastInt;
    LastCycleTime = CycleTime;

    if (count > 3)
    {
        printf("%.1f", Usage);
        break;
    }

    Sleep(1); // QueryPerformanceCounter Function Resolution is 1 microsecond

    count++;
}

CloseHandle(hProcess);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 2021-02-27
    • 1970-01-01
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多