C プログラムを使用して、C コードで実行される機械命令の数を計算します (一部の Linux システムのみがサポートされています) [ビデオ紹介]

動画を見たい友達はここをクリックしてください!

1. 出典

最近、時間計算量について勉強していたときに、実行時間に加えて、命令数によって 2 つのアルゴリズムのパフォーマンスを比較できるのではないかと考えたのです。
書き方が分からないのでネットで調べたところ、一番イメージに近い結果が stackoverflow: Quick way to count count of infection in a C programの回答でした。


2、C言語コード

#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>

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(int argc, char **argv) {
    
    
  struct perf_event_attr pe;
  long long count;
  int fd;
  uint64_t n;
  if (argc > 1) {
    
    
    n = strtoll(argv[1], NULL, 0);
  } else {
    
    
    n = 10000;
  }
  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 = 1;
  pe.exclude_hv = 1; // Don't count hypervisor events.
  fd = perf_event_open(&pe, 0, -1, -1, 0);
  if (fd == -1) {
    
    
    fprintf(stderr, "Error opening leader %llx\n", pe.config);
    exit(EXIT_FAILURE);
  }
  ioctl(fd, PERF_EVENT_IOC_RESET, 0);
  ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

  /* ---------------------- 以下是需要测试的业务代码 ---------------------- */
  for (int i = 0; i < 10000; ++i);
  /* ---------------------- 以上是需要测试的业务代码 ---------------------- */

  ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
  read(fd, &count, sizeof(long long));
  printf("Used %lld instructions\n", count);
  close(fd);
}

例証します:

  1. テスト対象の業務コードは 43 行目です。この例では、for ループで実行される命令の数を 1000 回テストします。他のコードは基本的に理解できないので、変更しないことをお勧めします。
  2. このプログラムは Linux 環境に依存しているため、Windows では実行できません。

3. コンパイルして実行する

通常の C プログラムのコンパイルと実行に違いはありません。ファイル名を とした場合perf_event_open.c、コンパイルおよび実行するコマンドは次のようになります。

gcc perf_event_open.c -o perf_event_open.out  && ./perf_event_open.out

正常に実行すると、次の情報が出力されます。

Used 30018 instructions

動作が異常な場合、次の情報が出力される場合があります。

Error opening leader 1

4. リーダーを開く際のエラーの問題

直接正常に実行できた場合は、おめでとうございます。このセクションはスキップしても問題ありません。
実行に失敗してError opening leader 1プロンプトが表示される場合は、次の 2 つの理由が考えられます。

  1. vmware 仮想マシン上で実行していますが、仮想マシンが正しくセットアップされていません。
  2. お使いの CPU はこのプログラムの実行をサポートしていません。

4.1 vmware 仮想マシンの設定

vmware 仮想マシン上で実行している場合は、この機能を有効にする必要があります虚拟化 CPU 性能计数器(U)
メニュー: 编辑虚拟机配置(最初に仮想マシンを閉じる必要があります) ->硬件タブ -> 处理器-> チェック虚拟化 CPU 性能计数器(U)
ここに画像の説明を挿入
ここに画像の説明を挿入
次に、仮想マシンを起動します。


4.2 CPU はこのプログラムをサポートしていません

このプログラムは、CPUが提供するPMU(Performance Monitoring Units)機能、すなわち性能監視ユニットを利用します。CPU が PMU をサポートしていない場合、この状況を回避する方法はありません。
それをサポートするかどうかを判断するにはどうすればよいですか? これに関する関連記事が見つからなかったので正確な答えはありませんが、推測される答えは 2 つあります。


4.2.1 最初の方法: dmesg コマンドを使用する

次のコマンドを実行します。

 dmesg | grep PMU

サポートされている場合は次のような結果が得られますが、サポート
ここに画像の説明を挿入
されていない場合は何も出力されません。


4.2.1 2 番目の方法: perf コマンドを使用する

perfコマンドが存在しない場合は、最初にインストールする必要があります。
Centos8 のインストールパフォーマンス:

yum install -y perf

Ubuntu20.04のインストールパフォーマンス:

apt install -y linux-tools-common linux-tools-generic linux-tools-5.11.0-44-generic linux-cloud-tools-5.11.0-44-generic

インストール後、次のコマンドを実行します。

perf list pmu

PMU がサポートされている場合、結果は次のようになります (命令は命令に関連しています)。

List of pre-defined events (to be used in -e):

  branch-instructions OR cpu/branch-instructions/    [Kernel PMU event]
  branch-misses OR cpu/branch-misses/                [Kernel PMU event]
  bus-cycles OR cpu/bus-cycles/                      [Kernel PMU event]
  cache-misses OR cpu/cache-misses/                  [Kernel PMU event]
  cache-references OR cpu/cache-references/          [Kernel PMU event]
  cpu-cycles OR cpu/cpu-cycles/                      [Kernel PMU event]
  instructions OR cpu/instructions/                  [Kernel PMU event]
  ref-cycles OR cpu/ref-cycles/                      [Kernel PMU event]
  topdown-fetch-bubbles OR cpu/topdown-fetch-bubbles/ [Kernel PMU event]
  topdown-recovery-bubbles OR cpu/topdown-recovery-bubbles/ [Kernel PMU event]
  topdown-slots-issued OR cpu/topdown-slots-issued/  [Kernel PMU event]
  topdown-slots-retired OR cpu/topdown-slots-retired/ [Kernel PMU event]
  topdown-total-slots OR cpu/topdown-total-slots/    [Kernel PMU event]
  msr/pperf/                                         [Kernel PMU event]
  msr/smi/                                           [Kernel PMU event]
  msr/tsc/                                           [Kernel PMU event]

サポートされていない場合、結果は次のようになります。

List of pre-defined events (to be used in -e):

  ref-cycles OR cpu/ref-cycles/                      [Kernel PMU event]
  topdown-fetch-bubbles OR cpu/topdown-fetch-bubbles/ [Kernel PMU event]
  topdown-recovery-bubbles OR cpu/topdown-recovery-bubbles/ [Kernel PMU event]
  topdown-slots-issued OR cpu/topdown-slots-issued/  [Kernel PMU event]
  topdown-slots-retired OR cpu/topdown-slots-retired/ [Kernel PMU event]
  topdown-total-slots OR cpu/topdown-total-slots/    [Kernel PMU event]
  msr/pperf/                                         [Kernel PMU event]
  msr/smi/                                           [Kernel PMU event]
  msr/tsc/                                           [Kernel PMU event]

5. エラーの説明

0上記の C 言語コードで、43 行目のビジネス コードをコメント アウトし、保存、コンパイル、実行すると14、命令の数が 1 ではないことがわかります13。自分の環境によっては異なる値が出る場合もありますが、この値は誤差値となるため、実際に計算する際にはこの値を差し引く必要があります。


本文の終わり

おすすめ

転載: blog.csdn.net/h837087787/article/details/122384335