실행시간 구하는 프로그램 소스

[code:2k8xxsnp]
#include <stdio.h>
#include <sys/time.h>
#include <stdint.h>
#include <string.h>
void main(int argc, char *argv[]) {
struct timeval t;
gettimeofday(&t,0);
if (argc<2) {
printf("%lu.%06lu\n",t.tv_sec,t.tv_usec);
} else {
char s[80];
char *p;
strcpy(s,argv[1]);
p = strchr(s,‘.’);
*p++ = ‘\0’;

	int64_t v = (t&#46;tv_sec - atoll(s)) * 1000000 + t&#46;tv_usec - atol(p);
	printf(&quot;%lu&#46;%06lu\n&quot;,v/1000000, v%1000000);
}

}
[/code:2k8xxsnp]

gcc -o elapsed elapsed.c

이렇게 컴파일 하시면 되구요.
사용은

T=$(elapsed)
find $HOME -type d
echo "Elapsed: $(elapsed $T) seconds"

최소단위는 마이크로초(1/1000000초 입니다)

물론, 실행시간 구하는 프로그램이 많이 있겠지만, 쉘 프로그래밍할 때 사용하려고 만들어 봤습니다.
라이브러리가 플랫폼 종속적이지 않아서, 윈도우즈에서도 그냥 컴파일해서 사용하면 됩니다.
x86_64-w64-mingw32-gcc -o elapsed.exe elapsed.c

아~ 좋네요. shell에서 CPU time 측정하는데 time command를 사용해왔는데, 그것은 하
나의 program에 대해서만 측정 가능하기 때문에 어려움이 있을 때가 있었습니다. 감사합니다.

그런데 이 경우, 소수점 이하의 시간이 얼마나 정확한 것인가요? micro-second 단위가 그에 걸맞게 정확하려면, system clock을 읽어서 측정해야 할 것 같은데, 진짜 그렇게 되나요?

다음의 코드는 web 검색하다보면 일반적으로 흔하게 나오는 예제인데, 이 경우를 program에서 실험해 보면, time resolution이 대략 15~20 mili-second라서 AC 전원의 주파수와 일치하는 것으로 보이더라구요. 즉, CLOCKS_PER_SEC가 60 내외인 것으로 보이더라구요. 그래서 정확도가 매우 떨어지거든요. 그래서, protochaos님이 주신 예제의 경우, 상당히 정확하다면 좋겠습니다.

출처 : [url:21svwjou]http://www.gnu.org/software/libc/manual/html_node/CPU-Time.html[/url:21svwjou]

[code:21svwjou]
#include <time.h>
int main(void) {
clock_t start, stop;
double cputime;
start = clock();

/* do something to measure CPU time */

stop = clock();
cputime = (double)(stop - start)/CLOCKS_PER_SEC;
}
[/code:21svwjou]

어떤 의도로 사용하시려는지 모르겠네요.

1.측정프로그램 준비
2.측정
3.결과 출력
4.측정프로그램 종료

5.프로그램 준비
6.프로그램 실행
7.프로그램 종료

8.측정프로그램 준비
9.측정
10.실행프로그램 시간 차이 츨력
11.측정프로그램 종료

이때, 1,5,8 등의 프로그램 준비시간이 필요합니다.
쉘프로그램으로 동작시킨다면, 쉘이 명령을 해석하는 시간, 측정프로그램이 메모리에 올라가는 시간 등이 필요한 것이죠.
이것은 시스템이나, 동작중인 프로그램들, 메모리 상황등에 따라 달라질 수 밖에 없습니다.
어자피 정확한 측정은 어렵구요.
또한 민감한 것 중의 하나가 메모리에 올리는 시간으로, 디스크에서 읽는 속도에 따라 달라지는데,
이것은 초기에 몇번 반복해주면, 캐시에 올리게 되어, 메모리에서 접근하게 되서, 빠르게 로드됩니다.
일단 어떤 프로그램 속도 측정 프로그램이든, 먼저 여러번 실행시켜 캐시를 사용하도록 강제해야
더 정확한 측정결과를 얻을 수 있습니다.
아니면, 처음에서 디스크에서 읽었다가, 다음 프로그램은 메모리에서 읽게 되어 속도차이가 엄청나는 것으로 나타나게 되죠.

시간단위에 대해서 말씀드리자면, 컴퓨터에서 대부분은 CPU에 의해 지시받고, 명령은 CPU의 클럭에 동기화 되어 실행됩니다.
그러니까, CPU클럭과 다음 클럭 중간에 두개의 프로그램이 실행될 수도 없고, 무조건 실행시간의 차이는 클럭의 속도이상 차이가 나게 됩니다.
그러나, 시간 측정의 경우, CPU의 시간을 누적 측정하여 측정될 수 도 있지만, 시간측정 칩이 따로 존재한다면,
시간 측정칩에서 CPU와는 무관하게 계속해서 시간을 측정하여 그 값을 기억하고 있을 것이고, CPU가 시간을 요구할 때,
내부적으로 저장되거나,측정한 값을 CPU에게 알려줄 것입니다.
측정은 CPU의 클럭 속도에 의존하지만, 그 사이 클럭속도가 변경되더라도 (전원설정에 의해 클럭 속도는 달라질 수 있음)
시간측정칩의 클럭속도는 변경되지 않아, 좀 더 정확한 측정이 가능하겠죠.
왜냐면, 클럭속도가 달라지더라도, 시각은 정확히 측정되어야 하므로, CMOS클럭속도는 달라지지 않을 것이기 때문입니다.
달라지더라도, 변경된 값에 따른 시각보정을 하겠지요.

정리해 드리자면, 인터벌을 구하기 위해 clock으로 시간을 측정하는 것은, CPU의 클럭에 따라 카운트하는 것일 것이나,
시간을 측정하기 위해 gettimeofday로 시간을 측정하는 것은, CMOS클럭에 따라 측정되는 것입니다.
그러므로, 최초에 명령이 전달되기 까지의 시간, 준비시간의 차이와, 다시 명령이 전달되기 까지의 시간과 준비시간의 차이는
CPU의 클럭 속도와 환경에 따라 달라질 수 있지만, 측정값과 측정값 사이의 시간은 CMOS 시간측정기의 정확도에 따릅니다.
사실 CMOS시각을 무시한다면, 시각을 측정할 방법이 따로 없는 것이나 마찬가지 입니다.

CPU클럭속도가 항상 일정한가, CPU 클럭속도가 달라진다면, 측정프로그램이 변경된 클럭 속도를 감지하고 시각 보정을 하는가에 대한
의구심을 가집니다.
즉, 매 tick마다 클럭속도를 적용하지 않고, tick카운트만 하여, 클럭 속도를 곱하는 것은, 정확하지 않을 수 있다는 것입니다.

또한, 프로그램의 시작시점을 어디로 볼 것인가 하는 것에도 차이가 있을 수 있지요.
프로그램의 실제 동작되기 전의 프로그램 준비시간은 프로그램 외부적인 요인에 의한 것이라, 이것을 프로그램 실행시간으로 포함시켜야 하는 것인가도 생각해 봐야죠.
보다 정확이 시간차를 측정하려면, 측정될 프로그램자체에서 시간을 측정하여 보고하여야 합니다.
그렇지만, 이것은 시간차 측정프로그램에서는 어떤 식으로 거의 불가능하기에 생각해 볼 수 없는 것이죠.

마지막으로, 클럭이라는 것은, 고전적으로 수정발진기(일반적인 시계에서 사용되는 클럭발생기)의 출력을 말하는 것으로,
그 출력이 디지털 칩을 통과하면, 클럭(사인파형과 같은 아날로그 신호 모양이 아닌, 네모형의 디지털 신호)으로 바뀌게 됩니다.
수정발진기도 자체적으로 오차를 가지고 있습니다.

정확성을 요구하시기에, 나노초 단위 까지 확장해봤습니다.
pow함수는 math 라이브러리에 포함되어 -lm 옵션을 넣어주어야 하기에,
그냥 정적으로 정의했습니다.

[code:2w0u3278]#include <stdio.h>
#include <time.h>
#include <inttypes.h>
#include <string.h>
#include <malloc.h>

#define PRECESION 9
#define COUNT_PER_SEC 1000000000

uintmax_t atou(char *s, int size) {
uintmax_t n;
if (size>0)
s = strndup(s, size);
sscanf(s, "%ju", &n);
if (size>0)
free(s);
return n;
}

void main(int argc, char *argv[]) {
struct timespec t;

while(clock_gettime(CLOCK_REALTIME, &amp;t));

if (argc&lt;2) {
	printf(&quot;%2$ju&#46;%3$0*1$ju\n&quot;,PRECESION,(uintmax_t)t&#46;tv_sec, (uintmax_t)t&#46;tv_nsec);
} else {
	char s&#91;80&#93;;
	char *p;
	strcpy(s,argv&#91;1&#93;);
	p = strchr(s,'&#46;');
	if (p) *p++ = '\0';

	uintmax_t v = ((uintmax_t)t&#46;tv_sec - atou(s,0)) * COUNT_PER_SEC + t&#46;tv_nsec - atou(p,0);

	uintmax_t v2 = t&#46;tv_nsec - atou(p,0);

	printf(&quot;%2$ju&#46;%3$0*1$ju\n&quot;,PRECESION,(uintmax_t)v/COUNT_PER_SEC, (uintmax_t)v%COUNT_PER_SEC);
}

}
[/code:2w0u3278]

테스트용 쉘 스크립트입니다.

[code:l2ptm4y2]#!/bin/sh
main() {
T=$($prog)
"$@"
E=$($prog $T)

SEP=$(printf %$(stty -a|sed -n -z 's!^&#46;*columns \(&#91;0-9&#93;\+\);&#46;*$!\1!p')s &quot; &quot;|tr &quot; &quot; =)
echo 1&gt;&amp;2
echo &quot;$SEP&quot; 1&gt;&amp;2
echo &quot;Initial date&#58; $(date +&quot;%F %T&quot; -d &quot;@${T%&#46;*}&quot;)&#46;${T#*&#46;}&quot; 1&gt;&amp;2

single_quote() {
    printf &quot;'%s'&quot; &quot;$(printf &quot;%s&quot; &quot;$*&quot;|sed &quot;s,','\&quot;'\&quot;',g&quot;)&quot;
}

printf &quot;Command&#58; '$1'&quot; 1&gt;&amp;2
for i in $( seq 2 $# ); do
    printf  &quot; $(single_quote $(eval echo \$$i))&quot; 1&gt;&amp;2
done
echo 1&gt;&amp;2
echo &quot;Elapsed&#58; $E seconds&quot; 1&gt;&amp;2
echo &quot;$SEP&quot; 1&gt;&amp;2

}

prog=elapsed main "$@"

[ 0 -eq "${TEST:-0}" ] && exit
elapsed_sh() {
t=$(date +%s.%9N)
if [ -z "$1" ]; then
echo $t
else
t=$(echo $t|tr -d .)
v=$(( t - $(echo $1|tr -d .) ))
printf "%s.%09d" "$((v/1000000000))" "$((v%1000000000))"
fi
}

echo 1>&2
echo "Run elapsed_sh .." 1>&2

prog=elapsed_sh main "$@"
[/code:l2ptm4y2]

TEST=1 elapsed-run.sh true

결과

Initial date: 2014-08-19 16:25:23.133130466
Command: ‘true’
Elapsed: 0.001370565 seconds

Run elapsed_sh …

===================================================================================
Initial date: 2014-08-19 16:25:23.148363408
Command: ‘true’
Elapsed: 0.002359099 seconds

차이가 0.001초 정도 나는데,
이것이 elapsed가 실행되어 clock_gettime이 호출되기 까지의 시간과
elpased_sh 함수가 호출되어 date가 실행되어 결과를 얻기까지의 시간의 차이라고 보시면 됩니다.
반복 호출되어도 그 시간의 차이는 있겠지요.