시스템콜인 open 계열 함수와 스트림기반의 fopen 계열..
작성자 : 김영철
등록날짜 : 2009.01.13 14:50
시스템콜인 open과 write를 이용한 파일열기, 쓰기와 스트림기반의 fopen, fputc, fputs 를 이용한 파일열기/쓰기를 비교해보았다.
시스템콜함수들은 사용자코드 프로세싱 도중에 커널영역함수를 호출하고 다시 돌아가므로 비용이 꽤 든다고 볼수 있으나 그 코드자체는 매우 최적화되어 있을것이다. 또한 스트림기반의 함수는 glibc에서 버퍼를 이용하여 처리하므로 작은크기를 많이 쓸때는 분명히 이것이 훨씬 더 빠를것이라는 예상이 된다. 궁금한점은 큰 크기를 한번에 쓸때도 과연 어느것이 더 빠를가 하는것이 되겠다.
먼저 1byte의 데이터를 1M까지 쓰기한다
open-1.c
시스템콜함수들은 사용자코드 프로세싱 도중에 커널영역함수를 호출하고 다시 돌아가므로 비용이 꽤 든다고 볼수 있으나 그 코드자체는 매우 최적화되어 있을것이다. 또한 스트림기반의 함수는 glibc에서 버퍼를 이용하여 처리하므로 작은크기를 많이 쓸때는 분명히 이것이 훨씬 더 빠를것이라는 예상이 된다. 궁금한점은 큰 크기를 한번에 쓸때도 과연 어느것이 더 빠를가 하는것이 되겠다.
먼저 1byte의 데이터를 1M까지 쓰기한다
open-1.c
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#define FILE_SIZE 1024 * 1000
int main()
#include <sys/types.h>
#include <fcntl.h>
#define FILE_SIZE 1024 * 1000
int main()
{
int i;
int fp = open("open.txt", O_CREAT | O_TRUNC | O_WRONLY);
for (i = 0; i < FILE_SIZE; i++)
int i;
int fp = open("open.txt", O_CREAT | O_TRUNC | O_WRONLY);
for (i = 0; i < FILE_SIZE; i++)
real 0m5.187s
user 0m0.519s
sys 0m4.011s
fopen-1.c
user 0m0.519s
sys 0m4.011s
fopen-1.c
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 1000
int main()
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 1000
int main()
{
int i;
FILE* fp;
fp = fopen("fopen.txt", "w+");
for (i = 0; i < FILE_SIZE; i++)
int i;
FILE* fp;
fp = fopen("fopen.txt", "w+");
for (i = 0; i < FILE_SIZE; i++)
{
fputc('A', fp);
}
}
<테스트 결과>
fputc('A', fp);
}
}
<테스트 결과>
real 0m0.119s
user 0m0.054s
sys 0m0.010s
두번째론 1M의 데이터를 한번에 쓴다
open-2.c
user 0m0.054s
sys 0m0.010s
두번째론 1M의 데이터를 한번에 쓴다
open-2.c
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#define FILE_SIZE 1024 * 1000
int main()
#include <sys/types.h>
#include <fcntl.h>
#define FILE_SIZE 1024 * 1000
int main()
{
int i;
int fp = open("open.txt", O_CREAT | O_TRUNC | O_WRONLY);
char buff[FILE_SIZE];
memset(buff, 'A', FILE_SIZE);
write(fp, buff, FILE_SIZE);
}
<테스트 결과>
int i;
int fp = open("open.txt", O_CREAT | O_TRUNC | O_WRONLY);
char buff[FILE_SIZE];
memset(buff, 'A', FILE_SIZE);
write(fp, buff, FILE_SIZE);
}
<테스트 결과>
real 0m0.058s
user 0m0.001s
sys 0m0.010s
fopen-2.c
user 0m0.001s
sys 0m0.010s
fopen-2.c
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 1000
int main()
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 1000
int main()
{
int i;
char buff[FILE_SIZE];
FILE* fp;
memset(buff, 'A', FILE_SIZE - 1);
buff[FILE_SIZE] = '\0';
fp = fopen("fopen.txt", "w+");
fputs(buff, fp);
}
<테스트 결과>
int i;
char buff[FILE_SIZE];
FILE* fp;
memset(buff, 'A', FILE_SIZE - 1);
buff[FILE_SIZE] = '\0';
fp = fopen("fopen.txt", "w+");
fputs(buff, fp);
}
<테스트 결과>
real 0m0.029s
user 0m0.002s
sys 0m0.011s
user 0m0.002s
sys 0m0.011s
time은 몇번재서 평균을 보았으나 귀찮아서 여긴 한번한것만 올린다. 시스템호출은 거의 일정한 time을 보여주는데 반해 스트림기반의 함수는 테스트할때마다 약간씩의 차이가 났다. 아무래도 버퍼기반이므로 상황따라 조금씩 차이가 나는듯하다.
결론적으로 적은데이트를 자주쓸땐 버퍼기반이 필요하며 이것은 소켓의 경우에도 마찬가지일터이다. 두번째 테스트에선 write의 user/sys타임이 조금더 빠른것을(거의같은) 알수잇겠다.
결론적으로 적은데이트를 자주쓸땐 버퍼기반이 필요하며 이것은 소켓의 경우에도 마찬가지일터이다. 두번째 테스트에선 write의 user/sys타임이 조금더 빠른것을(거의같은) 알수잇겠다.
1024 바이트씩 쓰기 테스트
1024 바이트씩 1024 * 100 번을 쓰는 테스트를 해보았다.
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 100
int main()
{
int i = 0;
char buff[1024];
FILE* fp;
memset(buff, 'A', 1024);
buff[1024] = '\n';
fp = fopen("fopen.txt", "w+");
while(i < FILE_SIZE)
{
fputs(buff, fp);
i++;
}
}
<테스트 결과>
real 0m3.491s
user 0m0.250s
sys 0m0.570s
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 100
int main()
{
int i = 0;
char buff[1024];
FILE* fp;
memset(buff, 'A', 1024);
buff[1024] = '\n';
fp = fopen("fopen.txt", "w+");
while(i < FILE_SIZE)
{
fputs(buff, fp);
i++;
}
}
<테스트 결과>
real 0m3.491s
user 0m0.250s
sys 0m0.570s
다음은 open버젼이다.
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 100
int main()
{
int i = 0;
char buff[1024];
int fd;
memset(buff, 'A', 1024);
buff[1024] = '\n';
fd = open("open.txt", O_CREAT|O_WRONLY|O_CREAT);
while(i < FILE_SIZE)
{
write(fd, buff, 1024);
i++;
}
}
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 100
int main()
{
int i = 0;
char buff[1024];
int fd;
memset(buff, 'A', 1024);
buff[1024] = '\n';
fd = open("open.txt", O_CREAT|O_WRONLY|O_CREAT);
while(i < FILE_SIZE)
{
write(fd, buff, 1024);
i++;
}
}
<테스트 결과>
real 0m3.124s
user 0m0.060s
sys 0m0.990s
결과를 확인해 보면 open이 미세? 하게 더 빠른 듯 하다. 그런데, 저 차이를 과연 미세하다고 해야할지 결정하기가 좀 애매모호하다.
real 0m3.124s
user 0m0.060s
sys 0m0.990s
결과를 확인해 보면 open이 미세? 하게 더 빠른 듯 하다. 그런데, 저 차이를 과연 미세하다고 해야할지 결정하기가 좀 애매모호하다.
fopen은 사용자레벨에서 버퍼를 관리하는 함수 답게 user시간을 꽤나 많이 잡아 먹고 있다는걸 확인할 수 있다.
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 100
int main()
{
int i = 0;
char buff[1024];
FILE* fp;
memset(buff, 'A', 1024);
buff[1024] = '\n';
while( i < 2048)
{
fp = fopen("fopen.txt", "w+");
if (fp == NULL)
{
perror("error");
exit(0);
}
printf("%d\n", i);
i++;
}
}
테스트 결과 1020이 나왔는데, 프로세스 생성되는 0, 1, 2를 감안한다면 1024로 open과 동일함을 확인할 수 있었다.
혹시 fopen으로 열수 있는 파일객체의 수에 제한이 있을 까 해서 오픈 테스트를 해보았다.
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#define FILE_SIZE 1024 * 100
int main()
{
int i = 0;
char buff[1024];
FILE* fp;
memset(buff, 'A', 1024);
buff[1024] = '\n';
while( i < 2048)
{
fp = fopen("fopen.txt", "w+");
if (fp == NULL)
{
perror("error");
exit(0);
}
printf("%d\n", i);
i++;
}
}
테스트 결과 1020이 나왔는데, 프로세스 생성되는 0, 1, 2를 감안한다면 1024로 open과 동일함을 확인할 수 있었다.
언뜻 봤을때 open()계열과 fopen()계열은 그리 큰 성능상의 차이가 없고. 어떤 경우에는 fopen이 더 나은 성능을 보장해주고 있다. 그렇다면 open()과 fopen() 둘중 어느것을 사용할런지는 순전히 개발자의 기호에 의존하는가 ? 반드시 그렇다고 볼 수 없다. fopen() 계열의 함수는 재진입불가 함수다. 이 말은 멀티 쓰레드 프로그램에서의 사용이나 비동기적 사건을 다루어야 하는 프로그램에서 사용될 경우 문제가 될 소지가 있음을 의미한다. 이 점만을 유의한다면 어느 함수를 쓰건 별 차이는 없을 것으로 생각된다.
"쇼핑몰·홈페이지·오픈마켓
블로그·페이스북·이메일 등의 각종 마케팅 글쓰기, 각종 광고, 영업, 판매, 제안서, 전단지 반응율 3배×10배 이상 높이는 마법의 8단계 공식" |
☞자세히보기 |
|
|