【问题标题】:Calculate execution time when sleep() is used计算使用 sleep() 时的执行时间
【发布时间】:2014-05-04 20:57:18
【问题描述】:

我正在尝试从运行 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() 不需要毫秒吗?
  • no sleep() 以秒为单位,usleep() 以微秒为单位
  • 尝试 printf("执行时间 = %f\n",((float)end-(float)begin)/CLOCKS_PER_SEC));
  • @HubertSchölnast 应该没什么区别。

标签: c linux embedded


【解决方案1】:

Unix

Unix 的原始版本不支持亚秒级计时,只有最新版本的 C 标准支持亚秒级“实时”(又名'wall time' 或“经过时间”)。在某个时候,添加了ftime(),然后是gettimeofday(),然后是clock_gettime(),并且clock() 函数在C90 中被标准化。

  • C 标准和至少从第 7 版 UNIX™ 开始的 Unix,通过 time() 函数提供了单秒精度:

    time_t now = time(0);
    
    printf("%ld\n", (long)now);
    
  • 第 7 版 UNIX™(或第 7 版 UNIX™)通过 ftime() 提供毫秒分辨率 — 它包含在 POSIX 中,直到 2004 版本(ftime()),但它不是 POSIX 2008 或稍后,尽管出于向后兼容性的原因,某些机器类型仍将支持它。

    #include <sys/timeb.h>
    
    struct timeb tb;
    if (ftime(&tb) == 0)
        printf("%ld.%.3d\n", (long)tb.time, tb.millitm);
    
  • POSIX 还通过struct timevalgettimeofday() 提供(并且仍然提供)微秒分辨率计时。它在 POSIX 2008 中被标记为过时。它可能是最便携的计时器。

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

    请注意,使用gettimeofday() 时有一些注意事项——如果有人在连续调用之间调整系统,其结果可能会受到影响。类似的 cmets 适用于 clock_gettime()CLOCK_REALTIME

  • POSIX 正朝着使用纳秒级分辨率的方向发展,这是通过struct timespecclock_gettime() 提供的。使用clock_gettime(),您必须选择要测量的时钟。对于许多用途,CLOCK_REALTIME 是正确的选择(但对于某些用途,CLOCK_MONOTONIC 可能更好,如果可用的话)。

    #include <time.h>
    
    struct timespec ts;
    if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
        printf("%ld.%.9d\n", (long)ts.tv_sec, ts.tv_nsec);
    
  • 我不确定clock() 的确切来源。它不在第 7 版 Unix 中,但在 SVR4 中,CLOCKS_PER_SEC 为 100。 C 标准提供了clock() 函数(POSIX 规范(clock() 要求 CLOCKS_PER_SEC 为 1,000,000;C 没有)。请注意,这不测量经过的“墙上时间”;它测量 CPU 时间量的近似值进程已使用。

    clock() 函数应返回实现对进程使用的处理器时间的最佳近似值,因为该实现定义的时代开始时仅与进程调用相关。

    要确定以秒为单位的时间,clock() 返回的值应除以宏CLOCKS_PER_SEC 的值。 [XSI] ⌦ CLOCKS_PER_SEC 在&lt;time.h&gt; 中定义为一百万。 ⌫

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

    由于clock() 函数测量的是使用的 CPU 时间,而不是经过的挂钟时间,因此在使用 sleep() 时测量经过的时间是完全不合适的,因为睡眠进程使用 no CPU 时间。

  • C11 标准提供了一些使用struct timespec 的线程相关函数,它被定义为匹配类型的POSIX 定义。它还提供了timespec_get()的功能:

    7.27.2.5 timespec_get 函数

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

    ¶2 timespec_get 函数设置ts 指向的间隔,以根据指定的时基保存当前日历时间。

    ¶3 如果 base 为 TIME_UTC,则 tv_sec 成员设置为自实现定义的纪元以来的秒数,截断为整数,tv_nsec 成员设置为整数纳秒,四舍五入到系统时钟的分辨率。321)

    ¶4 如果timespec_get 函数成功,则返回非零值base;否则返回零。

    321) 尽管struct timespec 对象以纳秒分辨率描述时间,但可用分辨率取决于系统,甚至可能大于 1 秒。

    此功能可能尚未广泛使用。例如,它在 macOS 10.14.5 Mojave 上不可用,尽管它似乎在 OpenBSD 中可用。它可能在glibc(GNU C 库)中可用,但未在 Linux 手册页中列出(https://linux.die.netsection 2 system callssection 3 functions 中,section 2 system callssection 3 functions 的@ 987654335@)。同样清楚的是,如果clock_gettime() 可用,实现一个体面的近似值是微不足道的:

    #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 提供了替代接口,包括GetTickCount()QueryPerformanceCounter(),它返回一个自参考时间以来的毫秒数(有效期最长为49 天)和QueryPerformanceCounter()。您还可以找到对RDTSC 的引用和使用——这是一条 Intel CPU 指令。

打印time_t

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

计算经过时间涉及计算这些函数返回的两个值之间的差异。使用这些结构有点繁琐。减法时必须处理溢出或下溢。

【讨论】:

  • 优秀的答案,正如预期的那样!
【解决方案2】:

我使用 MACRO 来打印经过时间。

#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 

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      计算执行时间的解决方案是获取程序开始和结束时的时间戳。然后有所作为。

      #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);
      }
      

      编辑:

      #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 作为执行时间而不是 1s;
      • 嗯...让我想想
      • 不...将结果类型转换为 int 也没关系
      • 我在我的计算机中创建了一个 file.c 并运行它。那个工作。您如何编译或使用它? (我在 ubuntu 13.10)
      • @RaNdoM_PoWneD 请参阅我链接的文档:“在 POSIX 系统上,time_t 以秒为单位,difftime 相当于算术减法,但 C 和 C++ 允许 time_t 使用小数单位。”所以它在许多情况下都可以工作,但在其他情况下却不行。
      【解决方案5】:

      确实:在sleep() 期间,程序根本没有运行。由于clock() 计算的是 CPU 时间而不是挂钟时间,因此“没有时间过去”。

      请改用time()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-10-12
        • 2021-06-21
        • 2018-01-28
        • 2019-09-22
        • 2011-11-20
        • 2011-10-21
        • 1970-01-01
        相关资源
        最近更新 更多