저는 이론적으로 캐시 친화적 인 것으로 입증 된 알고리즘을 구현해야하는 프로젝트를 진행 중입니다. 간단히 말해서 N
이 입력이고 B
이 캐시 미스가 발생할 때마다 캐시와 RAM간에 전송되는 요소의 수인 경우 알고리즘에 O(N/B)
이 RAM에 액세스해야합니다.왜 Perf와 Papi는 L3 캐시 참조 및 누락에 대해 다른 값을 제공합니까?
저는 이것이 실제로 실제로 나타나는 행동임을 보여 드리고자합니다. 다양한 캐시 관련 하드웨어 카운터를 측정하는 방법을 더 잘 이해하기 위해 다른 도구를 사용하기로 결정했습니다. 하나는 Perf이고 다른 하나는 PAPI 라이브러리입니다. 불행히도, 이러한 도구로 작업할수록 그들이하는 일을 정확히 이해하지 못합니다.
RAM (8GB RAM, L1 캐시 256KB, L2 캐시 1MB, L3 캐시 6MB)이 장착 된 Intel (R) Core ™ i5-3470 CPU @ 3.20GHz를 사용 중입니다. 캐시 라인 크기는 64 바이트입니다. 블록 크기는 B
이어야합니다.
#include <iostream>
using namespace std;
struct node{
int l, r;
};
int main(int argc, char* argv[]){
int n = 1000000;
node* A = new node[n];
int i;
for(i=0;i<n;i++){
A[i].l = 1;
A[i].r = 4;
}
return 0;
}
각 노드는 캐시 라인이 8 개 노드를 들어갈 수 있음을 의미하는 8 바이트가 필요합니다, 그래서 나는 약 1000000/8 = 125000
L3 캐시 미스를 기대해야합니다
perf stat -B -e cache-references,cache-misses ./cachetests
Performance counter stats for './cachetests':
162,813 cache-references
142,247 cache-misses # 87.368 % of all cache refs
0.007163021 seconds time elapsed
그것은 우리가 기대하는 것과 아주 가까이 있습니다 :
최적화없이(NO -O3
)는,이 반환 한 출력입니다. 이제 우리가 PAPI 라이브러리를 사용한다고 가정 해보십시오.
#include <iostream>
#include <papi.h>
using namespace std;
struct node{
int l, r;
};
void handle_error(int err){
std::cerr << "PAPI error: " << err << std::endl;
}
int main(int argc, char* argv[]){
int numEvents = 2;
long long values[2];
int events[2] = {PAPI_L3_TCA,PAPI_L3_TCM};
if (PAPI_start_counters(events, numEvents) != PAPI_OK)
handle_error(1);
int n = 1000000;
node* A = new node[n];
int i;
for(i=0;i<n;i++){
A[i].l = 1;
A[i].r = 4;
}
if (PAPI_stop_counters(values, numEvents) != PAPI_OK)
handle_error(1);
cout<<"L3 accesses: "<<values[0]<<endl;
cout<<"L3 misses: "<<values[1]<<endl;
cout<<"L3 miss/access ratio: "<<(double)values[1]/values[0]<<endl;
return 0;
}
이것은 내가 얻을 출력은 다음과 같습니다
L3 accesses: 3335
L3 misses: 848
L3 miss/access ratio: 0.254273
이유는 두 가지 도구와 같은 큰 차이?
은 전년 동기 대비 되세요 시도 PAPI_L3_DCA 및 PAPI_L3_DCM를 사용하여 데이터 미스를 계산? – HazemGomaa
PAPI_L3_DCA 만 사용할 수 있으며 같은 번호를주고있는 것 같습니다 – jsguy