2016-09-29 7 views
1

32 비트 조각 (u32 = unsigned int) 주위를 감싸고 해당 메모리 내의 개별 비트 또는 범위에 대한 액세스를 제공하는 비트 필드 추상 클래스를 작성 중입니다.std :: map (및 family) 조회 성능 문제

이를 구현하기 위해, 나는 고유 키가 니모닉을 나타내는 C-문자 배열에 포인터 (표준 없습니다 : : 문자열) 인 표준 : :지도를 사용하고, 값이 포함 된 구조체이다 비트 필드 속성 (예 : 니모닉, 시작 위치, 길이, 초기 값 및 필드 값) 이러한 모든 속성은 기본 u32 값이 변경 될 때만 변경되는 필드 값을 제외하고는 시작시에 상수 및 정의됩니다. (메모 : 나는 니모닉 포인터 값을 고유 키로 다시 사용했습니다).

이 값은 비트 필드 값 (읽기 전용)을 반환하는 getBitfieldValue()이 초당 여러 번 호출되는 에뮬레이터에서 사용됩니다. VS 아래의 코드를 컴파일 및 프로파일 링에

2015 업데이트 3 (-O2를 사용하고 내가 찾을 수있는 속도 최적화가), 그것은 getBitfieldValue() 기능 및 확장에 의해 std::find() 총 CPU의 약 60~70%을하고 있음을 보여줍니다 시간은 ... 너무 느립니다. , google::dense_hash_map 또는 std::unordered_map과 같은 다른지도 구현을 사용해 보았지만 어느 정도 도움이되지만 여전히 너무 느립니다 (~ 50-60 %).

내 생각 엔 잘못된 목적으로지도를 사용하고 있지만 5-20 비트 필드 매핑 (작은 조회 크기) 만 있다고 생각하지는 않습니다. 단지 너무 느린 것 같습니다. 대부분의 시간은 동일한 분야를 찾는 데에도 소비됩니다.

관련 클래스의 소스 코드를

는 여기에서 찾을 수 있습니다 : BitfieldMap32

지도가 시작할 때 initalised 방법의 예 (단 한 번 실행) :

struct Fields 
{ 
    static constexpr char * ADDR = "ADDR"; 
    static constexpr char * SPR = "SPR"; 
}; 
ExampleClass() // constructor 
{ 
    // registerField(mnemonic, start position, length, initial value) 
    registerField(Fields::ADDR, 0, 31, 0); 
    registerField(Fields::SPR, 31, 1, 0); 
} 

을 그리고 필드 값이 얼마나 액세스 된 (읽기 전용) :

// getFieldValue definition. 
const u32 & BitfieldMap32_t::getFieldValue(const char* fieldName) 
{ 
    return mFieldMap.find(fieldName)->second.mFieldValue; 
} 

// Field access. 
const u32 value = ExampleClassPointer->getFieldValue(Fields::ADDR) 

조회 시간을 줄이는 방법에 대한 아이디어가 있으십니까? 아니면 구현을 모두 변경해야합니까?

+0

std :: bitset을 사용하지 않는 이유는 무엇입니까? – Davidbrcz

+0

그래서 코드가 CPU를 너무 많이 사용한다는 것을 측정했습니다. 그러나, 정말로 느린가 *? CPU 또는 런타임의 백분율은 실제로 "충분히 빠르다"면 중요하지 않습니다. 프로그램의 실행 시간은 얼마입니까? 사용자 입력을 기다려야합니까? 사용자가 무언가를 입력하면 사용자는 몇 밀리 초 이상 기다려야합니까? 사용자는 얼마나 오래 기다려야합니까? 30 초 미만의 시간은 실제로 거의 즉각적으로 보입니다. 0.5 초가 아닌 0.4 초에 실행하기 위해 (아마도 * 많은 *) 일을 복잡하게 만들고 싶습니까? –

+0

아마도 'std :: unordered_map'을 사용하는 것이 해싱을 사용하고 더 빨라야하는 반면,'std :: map'은 이진 검색을 사용하는 것이 좋습니다. –

답변

4

IIUC 사전 (std::map 또는 std::unordered_map)을 사용하는 것은 엄청난 과잉입니다. 클래스는 단지 정수 (또는 std::bitset 최대)의 내부 저장 래퍼해야

  1. : 아마도 당신은 다음을 사용해야합니다.

  2. 니모닉은 std::string이 아니라 enum입니다.

  3. 내부적으로 std::vector은 각각 값을 bitmask에 효율적으로 매핑해야합니다. (C++ 11 enum을 사용하는 경우 hereenum 값을 std::vector 내의 위치로 변환하는 방법 참조).

  4. 각 작업은 니모 닉을 가져 와서 비트 마스크를 찾아서 내부 저장소에 적용해야합니다.

+0

내 코멘트에서 언급했듯이, "range"기능 (항상 단일 비트는 아님)을 제공하기 때문에 비트셋을 반복해야 할 때 성능에 도움이되는 std :: bitset이 어떻게 도움이 될지 잘 모르겠습니다. 열거 형 및 벡터 조합을 시도해보고 어떻게 진행되는지 살펴 보겠습니다. – marco9999

+0

@ marco9999 코드를 좀 더 살펴볼 것입니다. 어쨌든'std :: string' 니모닉을'enum'으로 대체하는 것을 제안합니다. –

+0

std :: vector로 끝나고 0 (enum/ints)부터 시작하는 인덱스 키를 정렬합니다. 훨씬 잘 작동합니다. 추측지도는 과잉이었다. – marco9999