Archlinux, 'kernel.perf_event_paranoid' it not respected
1
vote
0
answers
319
views
When reading the Performance Counters (PMC) on CPUS, the
kernel.perf_event_paranoid
must be 1
(check after syscall
)
I tested it on
- Archlinux Linux host1 5.17.9-arch1-1 #1 SMP PREEMPT Wed, 18 May 2022 17:30:11 +0000 x86_64 GNU/Linux
- Ubuntu 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
Now, by default, the parameter is 2
(Arch), 4
(Ubuntu).
I run the program and it should not be able to open the perf counter.
On Arch, it can still do it, on Ubuntu fails (as expected).
After tinkering and pointers from Kamil on SU SE , I found that for Ubuntu
there exists a patch which requires the setting to be 4
to actually have an effect.
- Is there anything similar on ArchLinux?
- Can this behaviour be reproduced on other Distros, too?
This script could help to reproduce
#!/bin/bash
cat >pmc.c
#include
#include
#include
#include
#include
#include
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, "\03331m--> 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 code is based on cpucycles/amd64rdpmc.c from [SUPERCOP )
Related:
- setting the kernel parameter
- My question on how I read the PMC
Asked by Joel
(161 rep)
May 25, 2022, 02:59 AM
Last activity: Jun 28, 2022, 06:42 AM
Last activity: Jun 28, 2022, 06:42 AM