내 Mac에서 fseek()
/fwrite()
의 쓰기 성능에 문제가 있습니다. 저는 4GB의 대용량 파일에서 작동하고 있으며 아래 테스트는 120MB의 작은 파일로 수행되었습니다. 디스크 이상한 fseek()/fwrite() 성능 MacOS에서
fopen()
새 파일이 제로 사용하여 파일 (소요 ~ 삼초)- 이 (4K 각각 30.000 블록) 작은 임의의 위치에 데이터 블록 쓰기를 채우기 다음과 같이 내 전략은
전체 절차는 약 120 초 걸립니다.
쓰기 전략 (내 질문 here 참조) 이미지 회전 알고리즘에 바인딩하고 누군가가 회전 문제에 대한 빠른 해결책을 제공하지 않는 한, 나는 fseek()
을 사용하는 전략을 변경할 수 아니에요 다음 4K를 쓰고있다 이하로 설정하십시오.
처음 몇 천인 fseek()
/fwrite()
은 성능이 뛰어나지 만 시스템 캐시가 채워지는 속도보다 빠 르게 빠 르게 성능이 떨어집니다. 아래 차트는 초당 fwrite()
초와 시간을 초 단위로 보여줍니다. 보시다시피, 7 초 후 fseek()
/fwrite()
속도가 약. 초당 200 개이지만 프로세스가 끝날 때마다 초당 100에 도달 할 때까지 계속 진행됩니다. 프로세스의 중간에
fclose()
후에 시스템이 전체 파일을 쓰는 것처럼 보입니다. 오랜 기간 동안 20 MB/s 디스크 활동이 나타납니다. 5.000 fwrite()
마다 fflush()
을 사용하면 동작이 전혀 변경되지 않습니다. 플러시를 강요하기 위해 fclose()
/fopen()
을 입력하면 어떻게 든 전체적으로 속도가 빨라집니다. 10 %.
나는 프로세스 (아래 스크린 샷)를 프로파일 링 했으므로 실제로는 항상 fwrite()
및 fseek()
내부에 머무르며 둘 다 __write_nocancel()
까지 드릴 다운 할 수 있습니다.
완전히 터무니없는
내 입력 데이터는 완전히 내 버퍼에 맞는 때문에 나는 쓰기를 분리 할 필요없이 선형 내 회전 출력 데이터를 기록 할 수있어 경우를 상상해 요약 과정을 파편으로. 필자는 여전히 fseek()
을 사용하여 쓰기 함수의 논리가 그런 식으로 동작하기 때문에 파일 포인터의 위치를 지정하지만이 경우 파일 포인터는 이미 있던 위치와 동일한 위치로 설정됩니다. 성능에 아무런 영향이 없다고 기대할 수 있습니다. 틀린입니다.
불합리한 점은 해당 특수한 경우에 fseek()
에 대한 호출을 제거하면 내 기능이 2.7 초 내에서 120 초가 끝나는 것입니다.
긴 머리말을 보낸 후 질문 : 동일한 위치를 검색하더라도 fseek()
이 성능에 그렇게 큰 영향을주는 이유는 무엇입니까? 어떻게하면 속도를 높일 수 있습니까? (다른 전략이나 다른 함수 호출, 가능한 경우 캐싱을 사용 불가능하게 설정, 메모리 맵핑 된 액세스 등 ...)? 내가 이해하지 않기 때문에 시스템이 내 "최적화"어떻게 좀 잃었어요
-(bool)writeRotatedRaw:(TIFF*)tiff toFile:(NSString*)strFile
{
if(!tiff) return NO;
if(!strFile) return NO;
NSLog(@"Starting to rotate '%@'...", strFile);
FILE *f = fopen([strFile UTF8String], "w");
if(!f)
{
NSString *msg = [NSString stringWithFormat:@"Could not open '%@' for writing.", strFile];
NSRunAlertPanel(@"Error", msg, @"OK", nil, nil);
return NO;
}
#define LINE_CACHE_SIZE (1024*1024*256)
int h = [tiff iImageHeight];
int w = [tiff iImageWidth];
int iWordSize = [tiff iBitsPerSample]/8;
int iBitsPerPixel = [tiff iBitsPerSample];
int iLineSize = w*iWordSize;
int iLinesInCache = LINE_CACHE_SIZE/iLineSize;
int iLinesToGo = h, iLinesToRead;
NSLog(@"Creating temporary file");
double time = CACurrentMediaTime();
double lastTime = time;
unsigned char *dummy = calloc(iLineSize, 1);
for(int i=0; i<h; i++) fwrite(dummy, 1, iLineSize, f);
free(dummy);
fclose(f);
f = fopen([strFile UTF8String], "w");
NSLog(@"Created temporary file (%.1f MB) in %.1f seconds", (float)iLineSize*(float)h/1024.0f/1024.0f, CACurrentMediaTime()-time);
fseek(f, 0, SEEK_SET);
lastTime = CACurrentMediaTime();
time = CACurrentMediaTime();
int y=0;
unsigned char *ucRotatedPixels = malloc(iLinesInCache*iWordSize);
unsigned short int *uRotatedPixels = (unsigned short int*)ucRotatedPixels;
unsigned char *ucLineCache = malloc(w*iWordSize*iLinesInCache);
unsigned short int *uLineCache = (unsigned short int*)ucLineCache;
unsigned char *uc;
unsigned int uSizeCounter=0, uMaxSize = iLineSize*h, numfwrites=0, lastwrites=0;
while(iLinesToGo>0)
{
iLinesToRead = iLinesToGo;
if(iLinesToRead>iLinesInCache) iLinesToRead = iLinesInCache;
for(int i=0; i<iLinesToRead; i++)
{
// read as much lines as fit into buffer
uc = [tiff getRawLine:y+i withBitsPerPixel:iBitsPerPixel];
memcpy(ucLineCache+i*iLineSize, uc, iLineSize);
}
for(int x=0; x<w; x++)
{
if(iBitsPerPixel==8)
{
for(int i=0; i<iLinesToRead; i++)
{
ucRotatedPixels[iLinesToRead-i-1] = ucLineCache[i*w+x];
}
fseek(f, w*x+(h-y-1), SEEK_SET);
fwrite(ucRotatedPixels, 1, iLinesToRead, f);
numfwrites++;
uSizeCounter += iLinesToRead;
if(CACurrentMediaTime()-lastTime>1.0)
{
lastTime = CACurrentMediaTime();
NSLog(@"Progress: %.1f %%, x=%d, y=%d, iLinesToRead=%d\t%d", (float)uSizeCounter * 100.0f/(float)uMaxSize, x, y, iLinesToRead, numfwrites);
}
}
else
{
for(int i=0; i<iLinesToRead; i++)
{
uRotatedPixels[iLinesToRead-i-1] = uLineCache[i*w+x];
}
fseek(f, (w*x+(h-y-1))*2, SEEK_SET);
fwrite(uRotatedPixels, 2, iLinesToRead, f);
uSizeCounter += iLinesToRead*2;
if(CACurrentMediaTime()-lastTime>1.0)
{
lastTime = CACurrentMediaTime();
NSLog(@"Progress: %.1f %%, x=%d, y=%d, iLinesToRead=%d\t%d", (float)uSizeCounter * 100.0f/(float)uMaxSize, x, y, iLinesToRead, numfwrites);
}
}
}
y += iLinesInCache;
iLinesToGo -= iLinesToRead;
}
free(ucLineCache);
free(ucRotatedPixels);
fclose(f);
NSLog(@"Finished, %.1f s", (CACurrentMediaTime()-time));
return YES;
}
: 참고로
, 여기에 (디버그 출력을 많이 포함하는 최적화되지, 최대 정돈되지) 내 코드입니다 전화. 모든 입력을 부탁드립니다.
데이터가 더 이상 파일 시스템 캐시에 적합하지 않으면 디스크 쓰기 성능을 측정하기 시작합니다. 그리고 fseek()는 디스크 쓰기 헤드가 얼마나 빨리 움직일 수 있는지 알려줍니다. 어느 것이 * 매우 느립니다. OSX에 대해서는 충분히 알지 못하지만 일반적으로 64 비트 OS와 많은 RAM이 큰 캐시를 구입합니다. –
"전체적으로 불합리한 요약"을 다시 읽으십시오 : fseek없이 30,000 개의 블록을 모두 선형 적으로 작성하면 전체 프로세스가 3 초 미만이됩니다. 만약 파일 포인터가 이미있는 위치와 같은 위치에 있다면 성능은 거의 40 배 정도 떨어집니다. 시스템이 디스크 머리를 후자의 변형으로 옮기려한다고 말하지 마십시오.이 동작은 첫 번째 * 몇 * 메가 바이트 및 캐시가 작을 수는 없습니다 (실제로 해당 머신에서 2GB의 사용 가능하지 않은 RAM이 있음을 감안할 때). 그리고 네, 내 OSX는 64 비트이고 위의 경우 충분한 8GB의 RAM이 있습니다. – nullp01nter