C语言 窗口中的查询性能计数器和查询性能频率


#include <windows.h>
#include <stdio.h>
#include <stdint.h>
// assuming we return times with microsecond resolution
#define STOPWATCH_TICKS_PER_US  1
uint64_t GetStopWatch()
{
    LARGE_INTEGER t, freq;
    uint64_t val;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&freq);
    return (uint64_t) (t.QuadPart / (double) freq.QuadPart * 1000000);
}
void task()
{
    printf("hin");
}
int main()
{
  uint64_t start = GetStopWatch();
  task();
  uint64_t stop = GetStopWatch();
  printf("Elapsed time (microseconds): %lldn", stop - start);
}
上面包含一个查询性能计数器函数 检索高分辨率性能计数器

的当前值和查询性能频率函数 检索高分辨率性能计数器的频率。如果我正在调用任务();函数多次,然后开始和停止时间之间的差异会有所不同,但我应该多次调用任务函数时获得相同的时差。谁能帮我识别上述代码中的错误?

问题是,Windows是一个先发制人的多任务操作系统。你问这到底是什么意思?

"简单" - 窗口将时间片分配给系统中每个正在运行的进程。这给人一种数十或数百个进程并行运行的错觉。实际上,在典型的台式机/笔记本电脑中,您只能有 2、4、8 或 16 个并行进程。英特尔 i3 有 2 个物理内核,每个内核都给人一种同时做两件事的印象。(但实际上,有一些硬件技巧可以在每个内核可以同时处理的两个线程中的每一个之间切换执行)这是对Windows/Linux/MacOSX的软件上下文切换的补充。

这些时间片不保证每次的持续时间相同。您可能会发现PC与windows.time同步以更新您的时钟,您可能会发现病毒扫描程序决定开始工作,或者许多其他事情中的任何一个。所有这些事件都可能发生在 task() 函数开始之后,但在它结束之前。

在DOS时代,每次对task()进行单次迭代计时时,你都会得到几乎相同的结果。不过,多亏了TSR程序,您仍然可以发现在执行过程中触发了中断并窃取了一些机器时间。

正是由于这些原因,可以通过运行任务 N 次来计算任务执行时间的更准确确定,将经过的时间除以 N 以获得每次迭代的时间。

对于过去的某些函数,我使用了高达 1 亿的 N 值。

编辑:一小段。

LARGE_INTEGER tStart, tEnd;
LARGE_INTEGER tFreq;
double tSecsElapsed;
QueryPerformanceFrequency(&tFreq);
QueryPerformanceCounter(&tStart);
int i, n = 100;
for (i=0; i<n; i++)
{
// Do Something
}
QueryPerformanceCounter(&tEnd);
tSecsElapsed = (tEnd.QuadPart - tStart.QuadPart) / (double)tFreq.QuadPart;
double tMsElapsed = tSecElapsed * 1000;
double tMsPerIteration = tMsElapsed / (double)n;

现代操作系统和处理器上的代码执行时间非常不可预测。 在无法确定经过的时间实际测量代码所花费时间的情况下,程序很可能在执行时将处理器丢失到另一个进程。 处理器使用的缓存起着重要作用,当缓存尚未包含程序使用的代码和数据时,代码在第一次执行时总是慢得多。 与处理器相比,内存总线非常慢。

当你测量一个printf()语句时,它变得特别没有意义。 控制台窗口由另一个进程拥有,因此存在大量进程互操作开销,其执行时间严重取决于该进程的状态。 例如,当控制台窗口需要滚动时,您会突然看到巨大的差异。 最重要的是,实际上你无能为力让它更快,所以测量它只是出于好奇。

仅分析可以改进的代码。 采集许多样本,以便摆脱异常值。 永远不要选择最低的测量值,这只会产生不切实际的期望。 也不要选择平均值,这会受到其他进程在测试中可能产生的长时间延迟的影响。 中值是一个不错的选择。

最新更新