65.9K
CodeProject 正在变化。 阅读更多。
Home

多个性能计时器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (10投票s)

2002 年 10 月 14 日

CPOL

5分钟阅读

viewsIcon

122669

downloadIcon

1595

计时您的代码的多个部分并显示累积结果。

引言

本文包含一个名为 MultiTimer.h 的文件,该文件可让您轻松计时代码的各个部分。它会在多次调用时累积时间,并生成一个输出摘要,其中包含每个计时器的总计和调用次数。这里及其他地方有许多类似的示例,但我认为添加本文仍然值得,因为我认为我的计时器类添加了一些额外的功能并且非常易于使用。

示例

void testfun()
{
    printf("Hello World!\n");
}

int main(int argc, char* argv[])
{
    for (int i = 0; i < 10; i++)
        testfun();

    return 0;
}

这并不是要计时代码的最佳示例,但它是一个很好的示例,说明了如何使用计时代码。请参阅下面的使用指南,了解如何计时代码的想法。

添加计时代码

添加计时代码需要以下步骤:

  • 添加 #include "MultiTimer.h"
  • 向要计时代码的代码中添加计时宏
  • 调用 TIMER_DUMP 或类似的宏来显示结果

添加了一些测试计时代码后,上面的示例看起来像这样:

#include "MultiTimer.h"

void testfun()
{
    TIME_LINE(printf("Hello World!\n");)
}

int main(int argc, char* argv[])
{
    {
    TIME_SCOPE("total test")
    for (int i = 0; i < 10; i++)
        TIME_FUN(testfun())
    }
    TIMER_DUMP("c:\\times.txt", SORT_CALLORDER)
    
    return 0;
}

这将产生以下输出文件:

-----------------------------------------------------------------
Timings at 10:41:56 Friday, January 03, 2003
-----------------------------------------------------------------
total test took 606.80 micro secs (called 1 time)
testfun() took 591.42 micro secs (called 10 times)
printf("Hello World!\n"); took 561.52 micro secs (called 10 times)

结果相当直接。如果您下载了演示代码,您将看到更详细的代码,它分解了 testfun() 调用所花费的时间。这是该代码的示例输出:

Total: 668.20 micro secs
Minimum: 39.39 micro secs
Maximum: 302.55 micro secs
Average: 66.82 micro secs

-----------------------------------------------------------------
testfun() at 10:22:06 Friday, January 03, 2003
-----------------------------------------------------------------
Sample  1 = 302.55 micro secs
Sample  2 = 58.11 micro secs
Sample  3 = 55.87 micro secs
Sample  4 = 41.63 micro secs
Sample  5 = 42.46 micro secs
Sample  6 = 41.07 micro secs
Sample  7 = 42.46 micro secs
Sample  8 = 39.39 micro secs
Sample  9 = 50.29 micro secs
Sample 10 = 43.02 micro secs

您可以从上面看出,第一个 printf 在 Windows 2000 上花费的时间要长得多,我猜这与某些初始化有关。

从上面的示例中,您可以看到此计时代码在很大程度上由宏驱动。以下是使用的宏列表:

TIMER_SETUP

这需要包含在项目中的一个 .cpp 文件中,并且处于全局作用域。它为计时代码设置存储。

TIME_SCOPE(name)

将其放置在您的代码中,以从该点计时到当前作用域的结束。name 是一个字符串,用于输出中标识这些时间。

TIME_FUN(fun())

用此宏替换函数调用 fun() 以计时该调用。

TIME_LINE(line)

用此宏包装任何行以对其进行计时。避免在该行中声明任何变量,因为此宏将该行放入一个单独的作用域。

TIMER_START(name) 和 TIMER_STOP(name)

这些宏允许您手动启动和停止计时器。请参阅演示示例。

TIMER_DUMP(dest, sort)

转储当前时间。如果 dest 是文件名,则输出将写入该文件。否则,它可以是:

  • OUT_MSGBOX - 在消息框中显示输出
  • OUT_TRACE - 将输出发送到跟踪窗口
  • OUT_CONSOLE - 将输出发送到 stdout

输出可以按 3 种方式排序:

  • SORT_TIMES - 最长的时间显示在最前面,直到最短
  • SORT_CALLORDER - 时间按计时器调用顺序显示
  • SORT_NAMES - 输出按字母顺序排序

TIMER_DUMP_FILE(dest, sort, mode)

这允许 3 个额外的模式值:

  • FILE_NEW - 每次创建新文件
  • FILE_APPEND - 将每次输出添加到文件末尾
  • FILE_PREPEND - 将每次输出添加到文件开头

如果您想比较几次测试运行,这很有用。

TIMER_DUMP_CSV(dest, sort, mode)

这与 TIMER_DUMP_FILE 相同,但输出是逗号分隔格式。

TIMER_DUMP_SAMPLES*(timer, ...)

TIMER_DUMP_SAMPLES 宏会转储指定计时器的所有样本,这可以是它的名称或 CHiFreqTimer 对象。请参阅演示示例。

有 3 个 TIMER_DUMP_SAMPLES 宏,它们对应于 TIMER_DUMP 宏,只是没有 sort 参数 - 样本按升序转储。

GET_TIMER(name)

返回计时器 nameCHiFreqTimer 对象。然后可以使用进一步的统计信息,请参阅演示示例。

T2S(time)

将从 CHiFreqTimer 调用返回的时间转换为有意义的字符串,请参阅演示示例。

CLEAR_TIMERS

移除所有计时器。

禁用计时代码

MultiTimer.h 的顶部有一个 #define USE_TIMERS。注释掉它将编译掉您可能添加的任何计时代码。

计时多个文件

您可以将计时代码放在多个文件中。每个文件都需要包含 multitimer.h,除了第一个文件外,所有文件都需要在 #include 之前添加以下行:

#define ANOTHER_TIMER_FILE

时钟滴答

了解一段代码花费了多少个时钟滴答有时很有用。我添加了一些宏,可以将花费的时间转换为时钟周期,首先您必须取消注释 multitimer.h 文件顶部的 #define _CLOCKTICKS 行。它们是:

T2C(time)

将时间转换为包含所花费时钟周期的字符串。

T2S_WITHCYCLES(time)

将时间转换为包含时间和周期数的字符串。

CLOCK_SPEED

这是一个 int,表示您的机器速度,例如 733。该数字的准确度在您的特定机器速度的 1 到 2 个以内。

使用指南

此类代码的目的是识别项目中的慢速部分。如果项目的一部分很慢,它应该有助于您缩小导致问题的代码范围。您应该避免计时非常快的语句 - 计时可能不准确。也不要计时所有代码,而是专注于需要加速的慢速区域。了解特定行或函数被调用了多少次也很有帮助,因为这通常很难仅从代码中找出。

理想情况下,应该始终使用发行版代码来获得准确的计时,调试代码中的额外检查和缺乏优化可能会导致误导性的结果。其他正在运行的进程也会影响时间,例如杀毒软件可能会扭曲文件访问时间。

准确性和计时开销

用于计时文件的任何代码本身也会花费一些时间。此代码试图对此进行补偿,但如果计时器和/或计时调用数量非常大,可能会导致精度略有损失。

QueryPerformanceCounter() 调用用于计时。这仅在 Pentium 处理器上受支持。如果您在旧机器上运行,升级可能会加快速度……

变更历史

  • 6/11/02
    • MultiTimer.h 文件的通用改进
    • 添加了 TIMER_DUMP_FILE
  • 7/11/02
    • 添加了 TIMER_START + TIMER_STOP
    • 添加了 USE_TIMERS #define
  • 3/1/03
    • 整理了 TIMER_STARTTIMER_STOP 手动计时器
    • 添加了 TIMER_DUMP_CSV
    • 添加了 TIMER_DUMP_SAMPLESTIMER_DUMP_SAMPLES_FILETIMER_DUMP_SAMPLES_CSV
    • 添加了时钟滴答宏
    • 移除了 TIMER_SETUP
    © . All rights reserved.