运行C程序所用的时间

8
我想知道在程序中添加哪些C代码可以告诉我程序运行的总时间。我猜应该在main函数开始时初始化计数器,在main函数结束后再初始化一次。正确的头文件是time.h吗?
非常感谢...
更新:我的机器是Win Xp,只需在程序开头添加clock(),在程序结尾再添加一个clock(),我就可以估算出时间差了。是的,你说得对,应该用time.h
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <share.h>
#include <time.h>


void f(long double fb[], long double fA, long double fB);

int main() {

clock_t start, end;
start = clock();


const int ARRAY_SIZE = 11;

long double* z = (long double*) malloc(sizeof (long double) * ARRAY_SIZE);

int i;
long double A, B;

if (z == NULL) {
    printf("Out of memory\n");
    exit(-1);
}

A = 0.5;
B = 2;


for (i = 0; i < ARRAY_SIZE; i++) {
    z[i] = 0;
}

z[1] = 5;

f(z, A, B);

for (i = 0; i < ARRAY_SIZE; i++)
    printf("z is %.16Le\n", z[i]);



free(z);
z = NULL;

end = clock();
printf("Took %ld ticks\n", end-start);
printf("Took %f seconds\n", (double)(end-start)/CLOCKS_PER_SEC);



return 0;  
}  

void f(long double fb[], long double fA, long double fB) {
    fb[0] = fb[1]* fA;
    fb[1] = fb[1] - 1;
    return;
 }  

MVS2008出现的一些错误:

testim.c(16):error C2143:语法错误:在'const'之前缺少';'
testim.c(18):error C2143:语法错误:在'type'之前缺少';'
testim.c(20):error C2143:语法错误:在'type'之前缺少';'
testim.c(21):error C2143:语法错误:在'type'之前缺少';'
testim.c(23):error C2065:'z':未声明的标识符
testim.c(23):warning C4047:'==':'int'与'void *'的间接级别不同
testim.c(28):error C2065:'A':未声明的标识符
testim.c(28):warning C4244:'=':从'double'转换为'int',可能会丢失数据

错误共计28个。请注意,在没有您的时钟代码时,我没有任何错误/警告。

最新消息:很遗憾我没有得到一个好的答复。但是在谷歌上搜索后,我找到了可以工作的代码。以下是代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>


void f(long double fb[], long double fA);

int main() {

clock_t start = clock();


const int ARRAY_SIZE = 11;

long double* z = (long double*) malloc(sizeof (long double) * ARRAY_SIZE);

int i;
long double A;

if (z == NULL) {
printf("Out of memory\n");
exit(-1);
}

A = 0.5;


for (i = 0; i < ARRAY_SIZE; i++) {
z[i] = 0;
}

z[1] = 5;

f(z, A);

for (i = 0; i < ARRAY_SIZE; i++)
printf("z is %.16Le\n", z[i]);



free(z);
z = NULL;

printf("Took %f seconds\n", ((double)clock()-start)/CLOCKS_PER_SEC);



return 0;
}

void f(long double fb[], long double fA) {
fb[0] = fb[1]* fA;
fb[1] = fb[1] - 1;
return;
}

您好!

4月10日更新:感谢"JustJeff"提供的更好的解决方案。

Cheers

(直译为“干杯”)
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

void f(long double fb[], long double fA);

const int ARRAY_SIZE = 11;

int main(void)
{

   long double* z = (long double*) malloc(sizeof (long double) * ARRAY_SIZE);
   int i;
   long double A;

   LARGE_INTEGER freq;
   LARGE_INTEGER t0, tF, tDiff;
   double elapsedTime;
   double resolution;

   if (z == NULL) {
   printf("Out of memory\n");
   exit(-1);
   }
   QueryPerformanceFrequency(&freq);
   QueryPerformanceCounter(&t0);
   // code to be timed goes HERE
   {
    A = 0.5;


    for (i = 0; i < ARRAY_SIZE; i++) {
    z[i] = 0;
    }

    z[1] = 5;
    f(z, A);


    for (i = 0; i < ARRAY_SIZE; i++)
    printf("z is %.16Le\n", z[i]);

    free(z);
    z = NULL;

   }
QueryPerformanceCounter(&tF);
tDiff.QuadPart = tF.QuadPart - t0.QuadPart;
elapsedTime = tDiff.QuadPart / (double) freq.QuadPart;
resolution = 1.0 / (double) freq.QuadPart;
printf("Your performance counter ticks %I64u times per second\n", freq.QuadPart);
printf("Resolution is %lf nanoseconds\n", resolution*1e9);
printf("Code under test took %lf sec\n", elapsedTime);
return 0;
}


void f(long double fb[], long double fA) {
fb[0] = fb[1]* fA;
fb[1] = fb[1] - 1;
return;
}

它可以在MVS2008和Borland C++ builderX从2003年的版本中使用。


1
如果您认为自己已经得到了最佳答案,可以发布并接受自己的答案。这样做对于正在寻找问题答案的其他人可能会有所帮助(我相信其他人也经常搜索此类问题)。 - Cam
我不确定我的答案是否正确,但它是有效的。由于我仍在学习,我始终欢迎建设性的建议。我可以接受(打勾)自己的答案吗? - yCalleecharan
是的,你可以的。顺便说一下,不是要无礼,但是你怎么没在这里得到一个好的回答呢?你得到了几个很好的答案,应该可以解决问题。如果你遇到错误,那是你自己的代码问题,而不是回答者给你的问题。如果你认为你得到的答案不好,请说出来我们可以改进。 - Javier
我在MVS2008中测试了这里的建议,但是像我在帖子中提到的那样,我一直在遇到错误。我是C编程的新手,我不知道为什么这里建议的代码不起作用。我从谷歌得到了一个答案,用我的代码进行了测试,似乎可以工作。随着时间的推移,我会提高自己的C知识水平,如果这里的建议代码有任何错误,我可以回来指出。也许是我的代码有问题,但我还不知道。我来这里是为了学习和分享知识。以我有限的C知识,很难成为信息提供者,但这将会改变。 - yCalleecharan
6个回答

6
在Unix(我认为)系统中,使用您的程序名称作为命令行参数的time命令将告诉您程序运行所需的时间。请注意,这测量了整个程序的执行时间。如果您只需要测试其中一部分,请包含time.h并使用clock函数,类似于以下方式:
#include <time.h>

int main() {
    clock_t start;
    clock_t end;
    int function_time;
    start = clock();
    function_you_want_to_time();
    end = clock();
    /* Get time in milliseconds */
    function_time = (double)(end - start) / (CLOCKS_PER_SEC / 1000.0);
    return 0;
}

这将给出以毫秒为单位的时间(注意/ 1000.0部分)。如果您想要秒数,请删除/ 1000.0。如果您想要更精确的普通时钟滴答声,请将function_time设置为clock_t并将function_time = ...行替换为:

function_time = end - start;

为了计时整个程序,我建议创建一个名为“_main()”的函数(或类似名称),将所有与程序相关的代码从“main()”中移动(但不包括计时代码!),并从“main()”中调用该函数。这样,可以更清楚地区分计时代码和程序的其余部分。请保留HTML标记。

这样做的一个缺点是,如果你只想计时某个实际计算部分,而不想包括资源/数据加载时间或输出时间等等,time 命令就无法做到这一点(因为它计时整个执行过程)。 - Amber
谢谢。function_you_want_to_time() 函数需要带参数吗?我想计时整个程序。 - yCalleecharan
@yCalleecharan:如果你想计时整个程序,就像我说的那样,用程序的其余部分替换function_you_want_to_time();这一行。如果函数需要一个参数也没有关系。如果你想要非常谨慎地进行测量,请将main()中的所有内容移动到另一个函数中,并从main()中调用该函数。这样做是为了在开始计时之前不声明变量。对于C99或C++,则不适用- - Javier
@yCalleecharan:如果你想要非常小心,可以把 / CLOCKS_PER_SEC 去掉,并将 function_time 改为 clock_t,这样你就可以得到时钟计数,而不是秒数。我会在答案中加上这个。 - Javier
谢谢。一个时钟滴答声等于1秒吗? - yCalleecharan
显示剩余3条评论

3

如果您想测试一段代码,可以使用<time.h>中的clock()函数,或者像其他回答者建议的那样,在*nix上使用time程序。例如:

> time ./foo my args

对于时钟,您需要减去两个检查点之间的差异。例如:

#include <time.h>

void f() {
  clock_t start, end;

  start = clock();

  // some long code.

  end = clock();
  printf("Took %ld ticks\n", end-start);
  // or in (fractional) seconds.
  printf("Took %f seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
}

更新

关于您遇到的新错误,您不能在VC中混合编写代码和声明。您不能先调用任何函数再继续声明变量。请将所有变量声明放在顶部,或者使用C++模式进行编译。


我得到了很多错误。我们需要定义clock_t类型的start吗? - yCalleecharan
我们需要有 void f() 吗?或者我们可以把 clock_t start, end; start = clock();...end = clock();printf("Took %ld ticks\n", end-start); 直接放在 main 函数里吗? - yCalleecharan
抱歉,这对我来说不起作用。MVS208愚蠢地抱怨了102个错误。编译器抱怨很多东西未定义。你确定你的代码片段没有漏掉什么吗? - yCalleecharan
发布你的代码和错误信息。(我假设你包含了 <stdio.h> 用于 printf?) - Alex Budovski
我真的不明白我的程序哪里出了问题。我正在使用C语言。当我没有你的时钟代码时,程序可以正常运行,没有任何警告。请指导我在我的代码中需要修改什么,并且仍然保持C语言程序。谢谢。 - yCalleecharan

3
如果你需要在 Linux 终端中得到程序的总计,则可以执行以下命令:
$ time myProgram

您也可以在您的代码中使用time.h。

#include <time.h>

int main(){
  time_t start, end;
  start = time(0);

  /* some working code */

  end = time(0);
  printf("%i seconds", end - start );
}

我得到了很多错误。我们需要定义time_t类型的start吗? - yCalleecharan
我认为它也可以是“int”。在我的Ubuntu中,我不必定义它的任何地方。 - Draco Ater

1

如果你使用的是Windows系统,想要测量微秒级别的时间,可以尝试使用QueryPerformanceCounter()和QueryPerformanceFrequency()函数。在许多系统上,这些函数可以解析出完整的处理器时钟周期、三分之一纳秒的时间,我认为最粗糙的情况也不会超过3.5795MHz,仍然远低于一微秒。

你可以调用QueryPerformanceFrequency()函数来确定计数器每秒钟计数的次数。然后在测试代码之前和之后分别调用QueryPerformanceCounter()函数。将两个QPC读数的差值除以QPF的周期,即可得到两个QPC调用之间的经过时间。就像这样...

LARGE_INTEGER freq;
LARGE_INTEGER t0, tF, tDiff;
double elapsedTime;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&t0);
// code to be timed goes HERE
QueryPerformanceCounter(&tF);
tDiff.QuadPart = tF.QuadPart - t0.QuadPart;
elapsedTime = tDiff.QuadPart / (double) freq.QuadPart;
// elapsedTime now has your measurement, w/resolution given by freq

显然,这些访问硬件计数设备与主板上的某个系统振荡器相连,因此它们不应受到软件负载的抖动影响。您获得的分辨率取决于您的系统。

后续

这是一个非常简单的完整程序,演示了接口:

#include <windows.h>
int main(void)
{
    LARGE_INTEGER freq;
    LARGE_INTEGER t0, tF, tDiff;
    double elapsedTime;
    double resolution;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&t0);
    // code to be timed goes HERE
    {
        Sleep(10);
    }
    QueryPerformanceCounter(&tF);
    tDiff.QuadPart = tF.QuadPart - t0.QuadPart;
    elapsedTime = tDiff.QuadPart / (double) freq.QuadPart;
    resolution = 1.0 / (double) freq.QuadPart;
    printf("Your performance counter ticks %I64u times per second\n", freq.QuadPart);
    printf("Resolution is %lf nanoseconds\n", resolution*1e9);
    printf("Code under test took %lf sec\n", elapsedTime);
    return 0;
}

对于这样简单的事情,跳过IDE更快,只需将其保存在foo.c文件中,然后(假设使用MS VS 2008)使用命令行即可。

cl foo.c

构建它。这是我系统上的输出:

Your performance counter ticks 3579545 times per second
Resolution is 279.365115 nanoseconds
Code under test took 0.012519 sec

谢谢。这对我来说似乎有点太高级了 :). - yCalleecharan
下载微软Visual Studio Express 2005或2008,它们是免费的,非常适合在Windows上进行编程工作。 - JustJeff
不确定您使用的Borland编译器有多旧,但可能有一种方法可以将其调整为正常工作,但它肯定可以与MS VS Express 2008一起使用,并且我相信同样适用于2005版。 - JustJeff
好的,谢谢。我正在使用2003年发布的Borland C++ BuilderX。是的,我有MS VS 2008。我不喜欢VS的原因是它为一个项目创建了大约15个文件,而BuilderX只创建了7个。当然,我不知道其他文件的用途 :),但我相信它们在调试过程中很有帮助。 - yCalleecharan
非常感谢您的辛勤努力。请查看我的更新帖子。它在MVS和Borland中都可以正常工作。您能否向我解释短语:“每秒钟您的性能计数器会跳动3579545次”和“分辨率为279.365115纳秒”?我猜分辨率只是精度,但性能计数器呢? - yCalleecharan
显示剩余5条评论

1

你可能需要使用time.h库和clock()函数。


0
你也可以试试 GetTickCount。时钟也能很好地工作。但是,如果其他进程或某人手动更改系统时间,时钟值会发生变化,而 GetTickCount 值不受影响。

是的,这是一个备选方案。我会调查一下。 - yCalleecharan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接