File: perf.c

package info (click to toggle)
coq 8.20.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 44,116 kB
  • sloc: ml: 234,160; sh: 4,301; python: 3,270; ansic: 2,644; makefile: 882; lisp: 172; javascript: 63; xml: 24; sed: 2
file content (107 lines) | stat: -rw-r--r-- 2,794 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/************************************************************************/
/*         *   The Coq Proof Assistant / The Coq Development Team       */
/*  v      *         Copyright INRIA, CNRS and contributors             */
/* <O___,, * (see version control and CREDITS file for authors & dates) */
/*   \VV/  **************************************************************/
/*    //   *    This file is distributed under the terms of the         */
/*         *     GNU Lesser General Public License Version 2.1          */
/*         *     (see LICENSE file for the text of the license)         */
/************************************************************************/

#include <linux/perf_event.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <errno.h>
#include <string.h>

#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/fail.h>

static int perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                           int cpu, int group_fd, unsigned long flags) {
  return syscall(SYS_perf_event_open, hw_event, pid, cpu, group_fd, flags);
}

#define NOT_INITIALIZED (-2)

int fd = NOT_INITIALIZED;

CAMLprim value CAML_init(value unit) {
  CAMLparam1(unit);

  if (fd != NOT_INITIALIZED) {
    caml_failwith("counter already initialized");
  }

  struct perf_event_attr pe;
  memset(&pe, 0, sizeof(pe));

  pe.type = PERF_TYPE_HARDWARE;
  pe.size = sizeof(pe);
  pe.config = PERF_COUNT_HW_INSTRUCTIONS;
  pe.disabled = 1;
  pe.exclude_kernel = 1;
  pe.exclude_hv = 1;

  fd = perf_event_open(&pe, 0, -1, -1, 0);
  if (fd == -1) {
    fd = NOT_INITIALIZED;
    caml_failwith("initialisation failure");
  }

  if (ioctl(fd, PERF_EVENT_IOC_RESET , 0) == -1) {
    close(fd);
    fd = NOT_INITIALIZED;
    caml_failwith("could not initially reset counter");
  }

  if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) == -1) {
    close(fd);
    fd = NOT_INITIALIZED;
    caml_failwith("could not initailly enable counter");
  }

  CAMLreturn(Val_unit);
}

CAMLprim value CAML_drop(value unit) {
  CAMLparam1(unit);

  if (fd == NOT_INITIALIZED) {
    caml_failwith("counter not initialized");
  }

  close(fd);
  fd = NOT_INITIALIZED;

  CAMLreturn(Val_unit);
}

CAMLprim value CAML_peek(value unit) {
  CAMLparam1(unit);

  if (fd == NOT_INITIALIZED) caml_failwith("counter not initialized");

  if (ioctl(fd, PERF_EVENT_IOC_DISABLE, 0) == -1) {
    caml_failwith("could not disable counter");
  }

  int64_t count = 0;
  size_t n = read(fd, &count, sizeof(count));

  if (n != sizeof(count)) {
    caml_failwith("could not retrieve counter");
  }

  value ret = caml_copy_int64(count);

  if (ioctl(fd, PERF_EVENT_IOC_ENABLE, 0) == -1) {
    caml_failwith("could not enable counter");
  }

  CAMLreturn(ret);
}