Archlinux、"kernel.perf_event_paranoid"は尊重されません。

Archlinux、

CPUSからパフォーマンスカウンタ(PMC)を読み取るときは、次のことを行う必要がありますkernel.perf_event_paranoid<=1カーネル文書)

以下のプログラムはPMCを読み、1カウンタを開けない場合は早く終了する必要があります。kernel.perf_event_paranoidつまり>1(後ろから確認syscall

私はテストしました

  • アーチLinuxLinux host1 5.17.9-arch1-1 #1 SMP PREEMPT Wed, 18 May 2022 17:30:11 +0000 x86_64 GNU/Linux
  • UbuntuLinux 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 に基づいています。スーパー警察)

関連:

ベストアンサー1

おすすめ記事