2016-08-19 3 views
7

매우 큰 (10-100GB) 바이너리 파일의 데이터 스트림을 분석하는 코드가 있습니다. 잘 작동하므로 최적화를 시작할 때가되었으며 현재는 디스크 IO가 가장 큰 병목입니다.디스크 입출력 최적화

두 가지 유형의 파일이 사용 중입니다. 첫 번째 유형의 파일은 물리적으로 의미있는 부동 소수점 값으로 변환하기 위해 I/O 이후에 크기를 조정해야하는 16 비트 정수 스트림으로 구성됩니다. 청크로 파일을 읽었고 한 번에 하나의 16 비트 코드를 읽고 필요한 확장을 수행 한 다음 결과를 배열에 저장하여 데이터 청크를 읽었습니다. 코드는 다음과 같습니다 :

int64_t read_current_chimera(FILE *input, double *current, 
          int64_t position, int64_t length, chimera *daqsetup) 
{ 
    int64_t test; 
    uint16_t iv; 

    int64_t i; 
    int64_t read = 0; 

    if (fseeko64(input, (off64_t)position * sizeof(uint16_t), SEEK_SET)) 
    { 
     return 0; 
    } 

    for (i = 0; i < length; i++) 
    { 
     test = fread(&iv, sizeof(uint16_t), 1, input); 
     if (test == 1) 
     { 
      read++; 
      current[i] = chimera_gain(iv, daqsetup); 
     } 
     else 
     { 
      perror("End of file reached"); 
      break; 
     } 
    } 
    return read; 
} 

chimera_gain 함수는 16 비트 정수를 취하고 크기를 조정하며 저장을 위해 double을 반환합니다.

두 번째 파일 형식에는 64 비트 double이 포함되어 있지만 두 개의 열이 포함되어 있습니다. 그 중 두 번째 열에는 첫 번째 파일 만 필요합니다. 이렇게하려면 두 개의 쌍을 자유롭게 설정하고 두 번째 쌍을 버립니다. 이중은 사용 전에 엔디 언 스왑되어야합니다. 나는이 작업을 수행하는 데 사용하는 코드는 다음과 같습니다 :

int64_t read_current_double(FILE *input, double *current, int64_t position, int64_t length) 
{ 
    int64_t test; 
    double iv[2]; 

    int64_t i; 
    int64_t read = 0; 

    if (fseeko64(input, (off64_t)position * 2 * sizeof(double), SEEK_SET)) 
    { 
     return 0; 
    } 

    for (i = 0; i < length; i++) 
    { 
     test = fread(iv, sizeof(double), 2, input); 
     if (test == 2) 
     { 
      read++; 
      swapByteOrder((int64_t *)&iv[0]); 
      current[i] = iv[0]; 
     } 
     else 
     { 
      perror("End of file reached: "); 
      break; 
     } 
    } 
    return read; 
} 

사람은 빨리 나는 현재 일을하고있는 것보다 크게 될 것이다 이러한 파일 형식을 읽는 방법을 제안 할 수 있습니까?

+0

디스크 I/O의 속도를 높이기 위해 할 수있는 방법은 없습니다. 당신이 할 수있는 유일한 방법은 당신이하는 I/O의 양을 최소화하는 것입니다. 파일에서 많은 부분을 뛰어 넘지 말고 파일의 같은 부분에서 값을 함께 사용하십시오. – Barmar

+2

캐시 사용을 최적화하려면 한 번에 두 개 이상의 값을 읽어야합니다. –

+0

@Barmar 음, 모든 디스크 IO 방법이 동일하지는 않습니다. 예를 들어, fscanf를 사용하는 것은 fread보다 훨씬 느립니다. 어쩌면 fread를 사용하여 한 번에 하나씩이 아닌 많은 양의 데이터를 읽으면 차이가 생길 수 있습니다. 옵션이 아직없는 것 같습니다. HDD의 실제 입출력 작업은 내가 제어 할 수있는 것이 아니라는 것을 알고 있습니다. 그러나 소프트웨어 측면에서 오버 헤드를 줄이는 방법은 거의 확실합니다. – KBriggs

답변

4

먼저 profile r을 사용하여 프로그램의 hot spots을 식별하는 것이 유용합니다. 문제에 대한 설명을 기반으로, 당신은 엄청난 양의 괴물에 의해 많은 오버 헤드가 발생합니다. 파일이 클수록 io 당 읽는 데이터 양을 늘리는 것이 큰 이점입니다.

스트림을 읽는 2 개의 작은 프로그램을 모아서 자신을 설득하십시오.

1) read it as you are in the example above, of 2 doubles. 

2) read it the same way, but make it 10,000 doubles. 

시간이 모두 몇 번 실행되며 확률이 높으면 2 번 관찰이 훨씬 빠르게 진행됩니다.

행운을 빈다.

+0

이것은 OP와 이것에 기반한 나의 첫 번째 최적화 시도 일 것입니다. 고맙습니다. – KBriggs

+2

아주 좋습니다. 바드를 잘못 인용하려면 ... 너를 프로파일 러로 데려 와라. 모든 개발자가 필요합니다. 코드에 대한 생각을 바꿀 것입니다. – EvilTeach

+2

또한 fread는 INT_MAX 바이트 덩어리 (반환 유형은'size_t')까지 읽을 수 있기 때문에 거기에 들어갈 수있는 숫자로 재생할 수 있고 최적화가 어떻게 진행되는지 볼 수 있습니다. –