私はLinuxカーネル4.19.2で作業しています。 perfやそのようなツールを使わずに利用可能なパフォーマンスカウンタを読みたいです。
ユーザースペースでは、以下のコードを使用します。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>
#define rdpmc(counter,low,high) \
__asm__ __volatile__("rdpmc" \
: "=a" (low), "=d" (high) \
: "c" (counter))
void test(){
printf(".");
}
static long
perf_event_open (struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;
ret = syscall (__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
return ret;
}
int
main ()
{
unsigned long values1, values2;
unsigned int fixed0, low, high;
struct perf_event_attr pe;
int fd, i;
fixed0 = (1 << 30);
memset (&pe, 0, sizeof (struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof (struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 1;
pe.exclude_kernel = 0;
pe.exclude_user = 0;
pe.exclude_hv = 0;
pe.exclude_idle = 0;
fd = perf_event_open (&pe, 0, -1, -1, 0);
if (fd == -1)
{
fprintf (stderr, "Error opening leader %llx\n", pe.config);
exit (EXIT_FAILURE);
}
for (i=1; i<=50; i++)
{
ioctl (fd, PERF_EVENT_IOC_RESET, 0);
ioctl (fd, PERF_EVENT_IOC_ENABLE, 0);
rdpmc (fixed0, low, high);
values1 = ((unsigned long) high << 32) + (unsigned long) low;
test();
rdpmc (fixed0, low, high);
values2 = ((unsigned long) high << 32) + (unsigned long) low;
ioctl (fd, PERF_EVENT_IOC_DISABLE, 0);
printf (" %lu\n", values2 );
}
close (fd);
}
では、カーネルコードで同じものを実装したいと思います。
私の目標は、すべてのコンテキストスイッチからイベント数を取得し、作業構造に保存することです。だから最終的にカーネルの context_switch() 関数でカウンタを呼び出したいと思います。カーネルでこれを行うと、常に現在のスレッドのコンテキストで実行されるという利点があります。
ほとんどのコードはカーネルでも再利用できると思います。しかし、ioctl()の部分についてはよくわかりません。
答え1
技術的には、ioctlはカーネルコードから呼び出すことができます。知られているksys_ioctl().[*]init/
唯一の他のコードが ksys_ioctl() を呼び出す方法に注意してください。軽く言うと、これは珍しいことです。呼ぶパフォーマンスカーネル内のioctlはもっと疑わしいようです。
到着スタートksys_ioctl()
これがなぜ珍しいのかを理解しながら、私はまだ議論の余地があることを指摘したいと思いますfd
。ファイル記述子の番号です。現在の作業範囲内で(プロセス/スレッド)。
[編集] 私の目標は、すべてのコンテキストスイッチからイベント数を取得し、作業構造に保存することです。だから最終的にカーネルの context_switch() 関数でカウンタを呼び出したいと思います。
あああ。
だからあなたはそうだったいいえカーネルでioctl()を呼び出したいです。 (ioctl()を呼び出すことができるファイル記述子はありません。いいえ各 context_switch() の間、現在のジョブのファイルテーブルにファイル記述子を開き始めたいと思います。後で閉じても)。
perf
この時点で、Linuxサブシステム(マイナーバージョン)を実装する方法を尋ねています。サブシステムにはperf
パフォーマンスカウンタがあります。パフォーマンスカウンタを使用する場合いいえサブシステムの場合は、まずカーネルでサポートを無効にするperf
必要があります。perf
プロセスの後半に、次の関連資料を確認するために時間を費やす必要があります。SDM(または関連マニュアル - まだ確認されていません)。
ksys_*()
[*] 注意: 関数にポインタを渡す際に制限があります。デフォルトでは、彼らは__user
あなたが使用しない限り、カーネルメモリではなくメモリを期待しています。set_fs()
..
コード作成はperf
別の話になります。たとえば、「次へ」をクリックすると、簡単にコードを参照できます。PERF_EVENT_IOC_RESET。特定の行に加えて、表示するソースファイル(およびディレクトリ)も提供され、クリックを続けることができます:-)。だから私はこれがあなたの問題だとは思わない。