1MB 크기의 파일을 구문 분석하고 처음 300KB를 읽고 특정 서명 수를 검색합니다. 내 전략은 각 바이트에 대해 해당 바이트가지도/벡터에 있는지/내가 서명의 시작 부분에있을 수있는 바이트가 무엇인지를 확인한 후 전체 서명을 찾습니다.이 예에서는 전체 바이트는 x37, x50 및 x52입니다. 파일 (90) (9 개 파일 실제로 10 배)의 총 처리 다음 코드는 2.122 초에서 실행 :벡터 및지도 검색이 정적 비교보다 훨씬 느린 이유
byte * bp = &buffer[1];
const byte * endp = buffer + bytesRead - 30; // a little buffer for optimization - no signature is that long
//multimap<byte, vector<FileSignature> >::iterator lb, ub;
map<byte, vector<FileSignature> >::iterator findItr;
vector<FileSignature>::iterator intItr;
while (++bp != endp)
{
if (*bp == 0x50 || *bp == 0x52 || *bp == 0x37) // Comparison line
{
findItr = mapSigs.find(*bp);
for (intItr = findItr->second.begin(); intItr != findItr->second.begin(); intItr++)
{
bool bMatch = true;
for (UINT i = 1; i < intItr->mSignature.size(); ++i)
{
if (intItr->mSignature[i] != bp[i])
{
bMatch = false;
break;
}
}
if (bMatch)
{
CloseHandle(fileHandle);
return true;
}
}
}
}
하지만, 내 초기 구현은 부진 84초에서 종료한다.
findItr = mapSigs.find(*bp);
if (findItr != mapSigs.end())
...
매우 유사한 구현도 매우 느린 처리 결과 3 개 개의 값 (1백90초)를 함유하는 벡터를 사용 :
if (find(vecFirstChars.begin(), vecFirstChars.end(), *bp) != vecFirstChars.end())
{
findItr = mapSigs.find(*bp);
...
를 유일한 차이점은 상기 "// 비교 선을"로 표시된 라인에 관련
그러나 벡터의 요소에 액세스하는 구현은 비교적 잘 수행합니다 (8.1 초). 안 정적 비교만큼 좋은,하지만 다른 옵션에 비해 여전히 훨씬 훨씬 더 :
if (vecFirstChars[0] == *bp || vecFirstChars[1] == *bp || vecFirstChars[2] == *bp)
{
findItr = mapSigs.find(*bp);
...
지금까지 (아래 구성 요소 (10)에 의해 영감을) 가장 빠른 구현 약 2.0 초에서 클러킹 다음입니다 :
은bool validSigs[256] = {0};
validSigs[0x37] = true;
validSigs[0x50] = true;
validSigs[0x52] = true;
while (++bp != endp)
{
if (validSigs[*bp])
{
...
두 번째 char가 유효한지 확인하기 위해 2 개의 validSigs를 사용하도록 확장하면 총 실행 시간이 0.4 초가됩니다.
다른 구현이 더 잘 수행되어야한다고 생각합니다. 특히 더 많은 접두사 접두사로 확장되어야하며 검색은 O (log (n)) vs O (n)입니다. 내가 뭘 놓치고 있니? 내 유일한 어둠의 추측은 정적 비교와 (덜 현존하는) 벡터 인덱싱에서 레지스터 나 다른 위치에 캐시 된 비교 값이 읽기보다 훨씬 빠릅니다. 기억으로부터. 이것이 사실이라면 컴파일러에게 특정 값이 자주 사용된다는 것을 알릴 수 있습니까? 명백하지 않은 아래의 코드를 활용할 수있는 다른 최적화가 있습니까? 난 비주얼 스튜디오로 컴파일하고
는 2008 년
3 개의 값만 사전 필터링하면 다른 잠재적 인 알려진 미스 조건을 효과적으로 제거하므로이 속도가 빨라집니다. 지도에 3 개의 값만 있으면 솔직하게 왜 당신이 하나의 값을 가지는지 알지 못합니다. 세 가지 값 (이미 수행하고있는)에 대한 인라인 테스트와 적절한 후속 조치를 취하는 것이 더 빠를 것입니다. 이 부분 문자열 (바이트 등 ..)에 대한 검색에 관한 모든 경우 [Knuth-Morris-Pratt] (http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm)와 같은 알고리즘에 대해 읽어 보시기 바랍니다. – WhozCraig
Have 서명 값에 희소 벡터를 사용하는 것이 좋습니다. 이러한 상황에서 적절한 최적화가 될 수있는 것처럼 들리는데, 특히 서명 범위가 1 바이트 인 경우 특히 그렇습니다. –
나는 Knuth-Morris-Pratt에 대해 읽지 않았는데, 재미있는 읽기 였지만 그렇게 적용 할 수는 없습니다. 바이트의 균등 분포를 가정 할 때, 256 비교 당 3 (또는 7)의 첫 번째 문자에 대해서만 일치를 볼 것입니다. 경기가 끝나면 이후의 각 캐릭터가 매치 할 확률은 1/256입니다. 나는 여기에있을 이득이별로 없다고 생각합니다. @ Component10 희소 한 벡터가 도움이 될지 모르겠지만 연속 배열은 속도를 높이므로 질문이 다른 경우로 업데이트됩니다. – Rollie