当使用sleep()函数时,如何计算执行时间

3
我正在尝试从运行Angstrom Linux发行版的Beagle Bone中的ADC读取数据。我需要使用像sleep()这样的延迟机制,只在特定时间读取样本,以帮助符合特定的采样率。我还需要计算执行时间。
以下是演示我面临问题的样本POC(概念验证):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int main()
{
    clock_t begin, end;

    while(1)
    {
        begin = clock();
        sleep(1); // delay for 1 sec
        end = clock();
        printf("Execution time = %f\n",((float)(end-begin)/CLOCKS_PER_SEC));    
    }    
}

我总是得到执行时间为0.000000

为什么我没有得到1.000000秒的结果?我猜想调用sleep()会抢占我的程序,但我不确定。

我有哪些其他选项来计算包括延迟的经过时间?


sleep() 不是以毫秒为单位吗? - dkasipovic
没有sleep()函数是以秒为单位的,usleep()函数是以微秒为单位的。 - Barath Ravikumar
尝试使用 printf("Execution time = %f\n",((float)end-(float)begin)/CLOCKS_PER_SEC)); - Hubert Schölnast
@HubertSchölnast 不应该有任何影响。 - glglgl
5个回答

6

Unix

最初版本的Unix不支持亚秒级别的计时方式,只有C标准的最新版本支持亚秒级别的“真实时间”(也称为“墙上时间”或“经过时间”)。后来,ftime()被添加进去,然后是gettimeofday(),再是clock_gettime(),并且在C90中对clock()函数进行了标准化。

  • The C standard, and Unix since at least 7th Edition UNIX™, has provided single-second accuracy with the time() function:

    time_t now = time(0);
    
    printf("%ld\n", (long)now);
    
  • 7th Edition UNIX™ (or Version 7 UNIX™) provided millisecond resolution with ftime() — and it was included in POSIX up to and including the 2004 version (ftime()), but it is not part of POSIX 2008 or later, though it will still be supported on some machine types for reasons of backwards compatibility.

    #include <sys/timeb.h>
    
    struct timeb tb;
    if (ftime(&tb) == 0)
        printf("%ld.%.3d\n", (long)tb.time, tb.millitm);
    
  • POSIX also provided (and still provides) microsecond resolution timing via struct timeval and gettimeofday(). It is marked obsolescent in POSIX 2008. It may be the most portable timer.

    #include <sys/time.h>
    
    struct timeval tv;
    if (gettimeofday(&tv, NULL) == 0)
        printf("%ld.%.6d\n", (long)tv.tv_sec, tv.tv_usec);
    

    Note that there are caveats about using gettimeofday() — its result can be affected if someone adjusts the system between successive calls. Similar comments apply to clock_gettime() and CLOCK_REALTIME.

  • POSIX is moving towards using nanosecond resolution timing, which is provided via struct timespec and clock_gettime(). With clock_gettime(), you must choose which clock you wish to measure. For many purposes, CLOCK_REALTIME is the correct choice (but CLOCK_MONOTONIC may be better for some purposes, if it is available).

    #include <time.h>
    
    struct timespec ts;
    if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
        printf("%ld.%.9d\n", (long)ts.tv_sec, ts.tv_nsec);
    
  • I'm not sure exactly where clock() came from. It wasn't in 7th Edition Unix, but it was in SVR4 with 100 for CLOCKS_PER_SEC. The C standard provides the clock() function (the POSIX specification for (clock() requires 1,000,000 for CLOCKS_PER_SEC; C does not). Note that this does not measure elapsed 'wall time'; it measures an approximation to the amount of CPU time that a process has used.

    The clock() function shall return the implementation's best approximation to the processor time used by the process since the beginning of an implementation-defined era related only to the process invocation.

    To determine the time in seconds, the value returned by clock() should be divided by the value of the macro CLOCKS_PER_SEC. [XSI] ⌦ CLOCKS_PER_SEC is defined to be one million in <time.h>. ⌫

    clock_t clk = clock();
    
    printf("%.6f\n", (double)clk / CLOCKS_PER_SEC);
    

    Since the clock() function measures the CPU time used, not the wall clock time that elapses, it is wholly inappropriate to measure elapsed time when sleep() is used because a sleeping process uses no CPU time.

  • The C11 standard provides some thread-related functions which use struct timespec, which is defined to match the POSIX definition of the type. It also provides the function timespec_get():

    7.27.2.5 The timespec_get function

        #include <time.h>
        int timespec_get(struct timespec *ts, int base);
    

    ¶2 The timespec_get function sets the interval pointed to by ts to hold the current calendar time based on the specified time base.

    ¶3 If base is TIME_UTC, the tv_sec member is set to the number of seconds since an implementation defined epoch, truncated to a whole value and the tv_nsec member is set to the integral number of nanoseconds, rounded to the resolution of the system clock.321)

    ¶4 If the timespec_get function is successful it returns the nonzero value base; otherwise, it returns zero.

    321) Although a struct timespec object describes times with nanosecond resolution, the available resolution is system dependent and may even be greater than 1 second.

    This function may not be widely available yet. It is not available on macOS 10.14.5 Mojave, for example, though it seems to be available in OpenBSD. It may be available in glibc (GNU C Library) but it isn't listed in the Linux man pages (neither in section 2 system calls or section 3 functions at https://linux.die.net, nor in section 2 system calls or section 3 functions at https://man7.org/). Equally clearly, it's trivial to implement a decent approximation to it if clock_gettime()is available:

    #if !defined(HAVE_TIMESPEC_GET) && defined(HAVE_CLOCK_GETTIME)
    enum { TIME_UTC = 1 };
    static inline int timespec_get(struct timespec *ts, int base)
    {
        assert(base != 0);
        if (clock_gettime(CLOCK_REALTIME, ts) != 0)
            return 0;
        return base;
    }
    #endif /* HAVE_TIMESPEC_GET */
    

Windows

Windows提供替代接口,包括GetTickCount(),它返回自参考时间以来的毫秒数(有效期最长为49天),以及QueryPerformanceCounter()。你还可以找到关于使用RDTSC——Intel CPU指令的参考和用法。

打印time_t

请注意,在这段代码中,我假设可以通过将time_t值转换为long并使用%ld格式来打印该值。对于64位Unix系统是正确的。对于Windows 64位,以及Unix和Windows 32位系统直到2038年1月,当当前时间与“时代”(1970-01-01 00:00:00 +00:00)之间的差距的值增长超过232-1秒时,也是正确的——32位算术溢出。然后强制类型转换应该是long long(保证至少是64位类型),格式应该是%lld。唯一的问题(也是现在不执行它的原因)是MS Visual Studio支持的格式——据我所知,它使用非标准名称和格式说明符来表示64位类型。

计算经过时间需要计算这些函数返回的两个值之间的差异。与结构一起工作有点棘手;在进行减法运算时必须处理溢出或下溢。


1
非常好的回答,果然如此! - Antti Haapala -- Слава Україні

3

计算执行时间的解决方案是在程序开始和结束时获取时间戳,然后计算它们的差值。

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

int main() {

    time_t begin;
    time(&begin);

  // Somethings

   time_t end;
   time(&end);

  printf("Execution time %f\n", difftime(end, begin));
  return (0);
}

EDIT:

#include <stdio.h>
#include <time.h>
#include <sys/time.h>

int main() {

  struct timeval  tv;
  gettimeofday(&tv, NULL);

double begin =
  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ;


 sleep(2);

 gettimeofday(&tv, NULL);

double end =
  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000 ;

  printf("Execution time %f\n", end - begin);
  return (0);
}

代码编译没有问题,但和我发布的代码一样,当我使用sleep(1);时,执行时间显示为0.0而不是1秒。 - Barath Ravikumar
嗯...让我想一想。 - Orelsanpls
不需要将结果强制转换为整数类型 - Barath Ravikumar
我在我的电脑上创建了一个file.c文件并运行它。这个工作正常。你如何编译它或使用它?(我使用的是Ubuntu 13.10) - Orelsanpls
1
@RaNdoM_PoWneD 请看我提供的文档:“在POSIX系统中,time_t以秒为单位衡量,difftime相当于算术减法,但C和C++允许time_t使用分数单位。” 因此,在许多情况下它可以工作,但在其他情况下则可能无法正常使用。 - glglgl
哦,是的,你说得对,我没有看到那部分。今天我学到了新东西!谢谢 :) 所以我编辑了我的帖子。 - Orelsanpls

2

实际上,在sleep()期间,程序根本不运行。而且,由于clock()计算的是CPU时间而不是挂钟时间,因此“没有时间流逝”。

请使用time()代替。


0

clock_gettime是用于此目的的函数。不要使用gettimeofday()...它已被弃用,并且在Opengroup和Linux man页面中有反对使用它的指导。

<<


0

我使用宏来打印经过的时间。

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#define ELPS_TIME(func_name) do { \
    struct timeval tval_before, tval_after, tval_result; \
    gettimeofday(&tval_before, NULL); \
    func_name; \
    gettimeofday(&tval_after, NULL); \
    timersub(&tval_after, &tval_before, &tval_result); \
    printf("Time elapsed: %ld.%06ld seconds\n", \
        (long int)tval_result.tv_sec, \
        (long int)tval_result.tv_usec); } while(0)

static void test_func1() {
    printf("%s:", __FUNCTION__);
    sleep(1);
}

static void test_func2() {
    printf("%s:", __FUNCTION__);
    sleep(2);
}

int main() {
    ELPS_TIME(test_func1()); //calling test_func1 
    ELPS_TIME(test_func2()); //calling test_func2
    return 0;
}

输出:

test_func1:Time elapsed: 1.000103 seconds                                                                             
test_func2:Time elapsed: 2.000974 seconds 

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