无法在 C (popen) 中对命令执行进行计时?
Unable to time command execution within C (popen)?
我一直在尝试计算 popen
调用完成所需的时间。 popen
初始化一个进程,然后创建一个管道、分支并调用 shell。在我的特殊情况下,我正在使用调用来读取另一个程序 stdout
输出。
问题:我期待我对 return 程序执行的正确时间长度的调用(测试大约 15 秒程序)。我得到的是该程序完全没有时间完成(0.000223 秒)。尽管我尝试了各种功能,但我似乎无法正确计时。
这是我的问题的一个可重现的例子。它由计时程序和一个子程序组成,计时程序运行s(子程序在我的系统上运行大约需要15s):
#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 秒在打印 'wrong' 时间之前,其他程序需要 运行。它不会立即打印时间,这意味着它没有等待调用完成。
popen()
只叉开一个管道。您的测试仅显示 popen()
创建 child 和管道所花费的时间。
解决问题的一个简单方法是在 pclose()
之后获取时间,请注意,这并不完美,因为当您通过 child 读取数据 return 时,它可能会在您致电 pclose()
之前完成
再加上你得到结果的解决方案被破坏了,你只做了纳秒之间的差异,我在 git:
上找到了解决方案
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
可以回滚。 (host_get_clock_service()
的 REALTIME_CLOCK
接缝也是单调的)。
CLOCK_MONOTONIC: Clock that cannot be set and represents monotonic time since some unspecified starting point.
REALTIME_CLOCK: A moderate resolution clock service that (typically) tracks time since the system last boot.
因此工作代码可能如下所示:
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;
}
致谢:
- How to subtract two struct timespec?
- How to print struct timespec?
我一直在尝试计算 popen
调用完成所需的时间。 popen
初始化一个进程,然后创建一个管道、分支并调用 shell。在我的特殊情况下,我正在使用调用来读取另一个程序 stdout
输出。
问题:我期待我对 return 程序执行的正确时间长度的调用(测试大约 15 秒程序)。我得到的是该程序完全没有时间完成(0.000223 秒)。尽管我尝试了各种功能,但我似乎无法正确计时。
这是我的问题的一个可重现的例子。它由计时程序和一个子程序组成,计时程序运行s(子程序在我的系统上运行大约需要15s):
#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 秒在打印 'wrong' 时间之前,其他程序需要 运行。它不会立即打印时间,这意味着它没有等待调用完成。
popen()
只叉开一个管道。您的测试仅显示 popen()
创建 child 和管道所花费的时间。
解决问题的一个简单方法是在 pclose()
之后获取时间,请注意,这并不完美,因为当您通过 child 读取数据 return 时,它可能会在您致电 pclose()
再加上你得到结果的解决方案被破坏了,你只做了纳秒之间的差异,我在 git:
上找到了解决方案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
可以回滚。 (host_get_clock_service()
的 REALTIME_CLOCK
接缝也是单调的)。
CLOCK_MONOTONIC: Clock that cannot be set and represents monotonic time since some unspecified starting point.
REALTIME_CLOCK: A moderate resolution clock service that (typically) tracks time since the system last boot.
因此工作代码可能如下所示:
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;
}
致谢:
- How to subtract two struct timespec?
- How to print struct timespec?