CPUS에서 성능 카운터(PMC)를 읽을 때 다음 을 수행해야 합니다 kernel.perf_event_paranoid
(<=1
커널 문서)
아래 프로그램은 PMC를 읽고 1
카운터를 열 수 없으면 일찍 종료해야 합니다. kernel.perf_event_paranoid
즉 >1
(뒤에서 확인 syscall
)
나는 테스트했다
- 아치리눅스
Linux host1 5.17.9-arch1-1 #1 SMP PREEMPT Wed, 18 May 2022 17:30:11 +0000 x86_64 GNU/Linux
- 우분투
Linux host2 5.15.0-30-generic #31-Ubuntu SMP Thu May 5 10:00:34 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
이제 기본적으로 매개변수는 2
(Arch), 4
(Ubuntu)입니다. 프로그램을 실행했는데 성능 카운터가 열리지 않습니다. Arch에서는 여전히 작동하지만 Ubuntu에서는 (예상대로) 실패합니다.
수리하고바늘~에서SU SE의 카밀, 실제로 적용 Ubuntu
하려면 설정해야 할 패치 가 있다는 것을 발견했습니다 .4
- ArchLinux에도 비슷한 것이 있나요?
- 이 동작이 다른 배포판에서도 재현될 수 있습니까?
이 스크립트는 재현에 도움이 될 수 있습니다
#!/bin/bash
cat >pmc.c <<'EOF'
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
static struct perf_event_attr attr;
static int fdperf = -1;
static struct perf_event_mmap_page *buf = 0;
long long cpucycles_amd64rdpmc(void) {
long long result;
unsigned int seq;
long long index;
long long offset;
if (fdperf == -1) {
attr.type = PERF_TYPE_HARDWARE;
attr.config = PERF_COUNT_HW_CPU_CYCLES;
attr.exclude_kernel = 1;
fdperf = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
if (fdperf == -1){
fprintf(stderr, "\033[31m--> could not open perf counter. Check paranoid setting\033[0m\n");
exit(1);
}
buf = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ, MAP_SHARED, fdperf, 0);
}
do {
seq = buf->lock;
asm volatile("" ::: "memory");
index = buf->index;
offset = buf->offset;
asm volatile("rdpmc;shlq $32,%%rdx;orq %%rdx,%%rax"
: "=a"(result)
: "c"(index - 1)
: "%rdx");
asm volatile("" ::: "memory");
} while (buf->lock != seq);
result += offset;
result &= 0xffffffffffff;
return result;
}
int main() {
long long c = cpucycles_amd64rdpmc();
printf("counter: %llx\n", c);
return 0;
}
EOF
param_name=kernel.perf_event_paranoid
read_pmc() {
echo -n "--> reading, "
sysctl "${param_name}"
}
set_pmc() {
n=$1
echo -e "--> setting to ${n}"
sudo sysctl -w "${param_name}=${n}"
read_pmc
echo "should be ${n}"
}
run() {
echo "--> running"
./pmc
}
#compile
gcc pmc.c -o pmc
read_pmc
run
echo -e "\n--> if ${param_name} as >1, that should have printed the error message\n\n"
set_pmc 1
run
echo -e "\n--> that should have worked and printed the counter.\n"
#re-set to 2
set_pmc 2
run
echo -e "\033[31m--> that should NOT have worked but it printed the counter\033[0m.\n"
rm pmc.c pmc
(rdpmc 코드는 cpucycles/amd64rdpmc.c를 기반으로 합니다.슈퍼 경찰)
관련된: