형식을 알고있는 사용자 지정 이진 파일 구조를 구문 분석하고 있습니다.
일반적인 아이디어는 각 파일이 순차적 인 바이트 블록으로 나뉘어 병렬로 분리 및 디코딩하려는 것입니다.
읽을 수 있고 성능이 좋은 대안을 찾고 있습니다. decode_block()
현재 작업중인 작업은 다음과 같습니다.
#include <stdio.h>
int decode_block(uint8_t buffer[]);
int main(){
FILE *ptr;
ptr = fopen("example_file.bin", "rb");
if (!ptr){
printf("can't open.\n");
return 1;
}
int block1_size = 2404;
uint8_t block1_buffer[block1_size];
fread(block1_buffer, sizeof(char), block1_size, ptr);
int block2_size = 3422;
uint8_t block2_buffer[block2_size];
fread(block2_buffer, sizeof(char), block2_size, ptr);
fclose(ptr);
//Do these in parallel
decode_block(block1_buffer);
decode_block(block2_buffer);
return 0;
}
int decode_block(uint8_t buffer[]){
unsigned int size_of_block = (buffer[3] << 24) + (buffer[2] << 16) + (buffer[1] << 8) + buffer[0];
unsigned int format_version = buffer[4];
unsigned int number_of_values = (buffer[8] << 24) + (buffer[7] << 16) + (buffer[6] << 8) + buffer[5];
unsigned int first_value = (buffer[10] << 8) + buffer[9];
// On and on and on
int ptr = first_value
int values[number_of_values];
for(int i = 0; i < number_of_values; i++){
values[i] = (buffer[ptr + 3] << 24) + (buffer[ptr + 2] << 16) + (buffer[ptr + 1] << 8) + buffer[ptr];
ptr += 4
}
// On and on and on
return 0
}
전체 파일을 바이트 배열로 읽은 다음 배열을 바이트 단위로 해석하는 것은 약간 중복 된 느낌입니다. 또한 매우 부피가 큰 코드를 만듭니다.
그러나 파일의 여러 부분을 병렬로 작업해야하므로 다른 방법을 생각할 수 없습니다. 또한 초기 바이트를 buffer
존경받는 메타 데이터 값으로 변환하는 더 간단하거나 빠른 방법이 있습니까?
신분증:
원시 데이터를로드하지 않으려면 "메모리 매핑 파일"을 사용하십시오 (예 : mmap()
POSIX 시스템). 이것은 이식 가능한 "일반 C"가 아니지만 거의 모든 OS가이를 수행하는 방법을 지원합니다.
파일 형식 사양에서 값이 파일의 4 바이트 경계에 정렬되어야하며 (실제로 부호있는 정수를 지원해야하는 경우) 값이 "부호가 아닌"2의 보완 "형식으로 저장되어야합니다. 및 규모 "또는 기타)
파일이 가능한 한 사양을 준수하는지 확인하십시오 (정렬 요구 사항뿐만 아니라 "데이터는 헤더 중간에서 시작할 수 없습니다", "데이터 시작 + 항목 * entry_size는 파일 크기를 초과 할 수 없음"과 같은 항목을 포함하여, "인식되지 않는 버전"등).
#ifdef
메모리 매핑 파일의 데이터를 int32_t
(또는 uint32_t
)로 캐스팅 할 수있는 리틀 엔디안 머신 (예 : 컴파일 타임에 사용되는 코드를 선택할 수있는 위치)에 대해 다른 코드를 사용 합니다. 표시 한 코드 (예 : (buffer[ptr + 3] << 24) + (buffer[ptr + 2] << 16) + (buffer[ptr + 1] << 8) + buffer[ptr])
"2의 칭찬"컴퓨터에서도 음수로 구분됨)에 유의하십시오. 따라서 대체 코드 ( "리틀 엔디안이 아님"의 경우)는 귀하의 코드보다 더 복잡하고 느립니다. 물론 음수를 지원할 필요가 없다면 부호있는 정수 유형 (예 int
:)을 사용해서는 안되며, 솔직히 int
32 비트 값에 "아마도 16 비트" 를 사용해서는 안됩니다 .
사용할 스레드 수를 결정합니다 (명령 줄 인수 일 수 있습니다. 컴퓨터에 실제로있는 CPU 수를 OS에 물어볼 수도 있음). 스레드를 시작하고 어떤 "스레드 번호"인지 알려주십시오 (기존 스레드는 0 번, 처음 생성 된 스레드는 1 번 등).
스레드가 "스레드 번호", 전역 "총 스레드", 전역 "총 항목"및 전역 "첫 항목 오프셋"에서 시작 및 끝 오프셋 (메모리 매핑 파일에서)을 계산하도록합니다. 이것은 대부분 반올림에 특별한주의를 기울인 분할입니다. (전역 변수를 피하기 위해) 대신 각 스레드에 세부 정보가 포함 된 구조를 전달할 수 있습니다. 스레드는 데이터를 읽기만하기 때문에이 데이터에 대한 보호 장치 (예 : 잠금, 중요 섹션)가 필요하지 않습니다.
각 스레드가 데이터 섹션을 병렬로 구문 분석하도록합니다. 그런 다음 모두 완료 될 때까지 기다립니다 (예 : 나중에 사용하기 위해 스레드를 유지하지 않으려면 "thread number 0"이 "pthread_join ()"을 수행함).
모든 값 (모든 스레드에 의해 구문 분석 됨)이 허용 된 범위 내에 있는지 (파일 형식 사양을 준수하기 위해) 확인해야 할 수도 있습니다. 그렇지 않은 경우 (예 : 파일이 손상되었거나 악의적으로 변조 된 경우)에 대해 일종의 오류 처리 기능이 있습니다. 이것은 (전역 적으로 원자 적으로 증가 된) "지금까지 발견 된 이상한 값의 수"카운터처럼 간단 할 수 있습니다. 모든 값이 구문 분석 된 후 "N dodgy values found"오류 메시지를 표시 할 수 있습니다.
참고 1 : 메모리 매핑 파일을 사용하지 않으려는 경우 (또는 사용할 수없는 경우) 하나의 "파일 판독기 스레드"와 여러 "파일 파서 스레드"를 가질 수 있습니다. 이는 훨씬 더 많은 동기화를 필요로합니다 (흐름 제어 기능이있는 FIFO 대기열로 넘어갑니다. 예를 들어 공급자 스레드가 "대기열이 가득 차는 동안 {대기}"를 수행하고 소비자 스레드가 "대기열이 비어있을 때 {대기}"를 수행하는 경우)). 이 추가 동기화는 메모리 매핑 된 파일을 사용하는 것에 비해 오버 헤드를 증가시키고 더 느리게 만듭니다 (더 복잡 할뿐만 아니라).
참고 2 : 파일의 데이터가 운영 체제의 파일 데이터 캐시에 의해 캐시되지 않는 경우 수행하는 작업에 관계없이 파일 IO에 의해 병목 현상이 발생할 수 있으며 여러 스레드를 사용하는 것이이 경우 성능에 도움이되지 않을 것입니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다