无法在C(popen)中执行时间命令?

时间:2017-06-22 20:09:11

标签: c macos time clock

我一直试图计算调用popen完成所需的时间。 popen初始化一个进程,然后创建一个管道,分叉并调用shell。在我的特定情况下,我使用该调用来读取另一个程序stdout输出。

问题:我希望我所做的调用能够返回程序执行所需的正确时间(测试程序大约需要15秒)。我得到的是该程序完全没有时间完成(0.000223s)。尽管我尝试了各种各样的功能,但我似乎无法正确计时。

这是我的问题的可重现的例子。它由计时程序和计时程序运行的子计划组成(孩子需要大约15秒才能在我的系统上运行):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif

#define MAXBUF 10

static void gettime (struct timespec *t) {
#ifdef __MACH__
    clock_serv_t cclock;
    mach_timespec_t mts;
    host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);
    t->tv_sec = mts.tv_sec;
    t->tv_nsec = mts.tv_nsec;
#else
    clock_gettime(CLOCK_REALTIME, t);
#endif
}

int main (void) {
    FILE *fp;
    struct timespec tic, toc;
    char *executableName = "./a.out";
    char answer[MAXBUF];

    gettime(&tic);
    if ((fp = popen(executableName, "r")) == NULL) {
        fprintf(stderr, "The file couldn't be opened.\n");
        return 1;
    }
    gettime(&toc);

    fgets(answer, MAXBUF, fp);
    double elapsed = (double)(toc.tv_nsec - tic.tv_nsec) / 1E9;
    fprintf(stdout, "The program says %s, and took %fs to run!\n", answer, elapsed);

    pclose(fp);
    return 0;
}

这是儿童计划:

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

int timeWastingFunction (long long n) {
    if ((n % 2) == 0) {
        return 1;
    }
    for (int i = 1; i < (n / 2); i += 2) {
        if ((n % i) == 0) {
            return 1;
        }
    }
    return 0;
}

int main (void) {
    int start = 687217000;

    while (start--) {
        timeWastingFunction(start);
    }
    fprintf(stdout, "Hello!");
    return 0;
}

这可能看起来有点过头了,但我以前曾尝试使用clock_t(基于CPU的计时工具)来完成计时,并从中获得相同的答案。因此,我尝试了上面看到的this解决方案。我选择了CLOCK_REALTIME,因为它似乎适合这项工作。遗憾的是,我没有选择指定此时钟是在每个进程还是每个线程级别(我希望它与进程无关)。

注意:我还没有尝试使用gettimeofday,但我不想,因为它显然不适合这种方式,取决于日期使用它的系统,并逐步取消clock_gettime

编辑:为了清楚起见,当我运行这个时发生的事情是,在打印之前,调用popen的程序实际上会停止其他程序运行的15秒&#39;错误&#39;时间。它没有立即打印时间,暗示它没有等待电话完成。

1 个答案:

答案 0 :(得分:3)

popen()只分叉并打开一根烟斗。您的测试仅显示popen()创建子项和管道的时间。

解决问题的一个简单方法是在pclose()之后得到时间,注意这并不完美,因为当您阅读孩子的数据返回时,它可能会在您致电{{1 }}

再加上你的解决方案得到的结果是破碎的,你只能在纳秒之间做出差异,我在git上找到了一个解决方案:

pclose()

最后一点是,如果你想要日期,应该使用void timespec_diff(struct timespec *start, struct timespec *stop, struct timespec *result) { if ((stop->tv_nsec - start->tv_nsec) < 0) { result->tv_sec = stop->tv_sec - start->tv_sec - 1; result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000; } else { result->tv_sec = stop->tv_sec - start->tv_sec; result->tv_nsec = stop->tv_nsec - start->tv_nsec; } return; } 。在这里你只想要一个持续时间。因此,如果CLOCK_REALTIME可用,则应使用CLOCK_MONOTONIC,因为CLOCK_REALTIME可以回滚。 (REALTIME_CLOCK接缝单调的host_get_clock_service()

  

CLOCK_MONOTONIC:无法设置的时钟,表示自某个未指定的起点以来的单调时间。

     

REALTIME_CLOCK:一种中等分辨率的时钟服务,它(通常)跟踪自系统上次启动以来的时间。

所以工作代码看起来像这样:

int main (void) {
    FILE *fp;
    struct timespec tic, toc;
    char *executableName = "./a.out";
    char answer[MAXBUF];

    gettime(&tic);
    if ((fp = popen(executableName, "r")) == NULL) {
        fprintf(stderr, "The file couldn't be opened.\n");
        return 1;
    }

    fgets(answer, MAXBUF, fp);

    pclose(fp);
    gettime(&toc);
    struct timespec result;
    timespec_diff(&tic, &toc, &result);
    fprintf(stdout, "The program says %s, and took %lld.%.9lds\n", answer, (long long)result.tv_sec, result.tv_nsec);

    return 0;
}

信用: