Linux Manual Pages development
 help / color / mirror / Atom feed
* Behavior of wakeup_events being 0 in perf_event_open(2)
@ 2026-11-09  2:08 Nick Krichevsky
  2026-11-09  9:16 ` Alejandro Colomar
  0 siblings, 1 reply; 2+ messages in thread
From: Nick Krichevsky @ 2026-11-09  2:08 UTC (permalink / raw)
  To: alx+linux-man; +Cc: linux-man

Hi,

I was experimenting with perf_event_open(2) and caught this sentence in the
man page.

    Prior to Linux 3.0, setting wakeup_events to 0 resulted in no overflow
    notifications; more recent kernels treat 0 the same as 1.

I wrote a small test program (below) to test this behavior. On
kernel 7.1.13-200.fc44.x86_64, my experience seems to contradict the man page;
it seems that when wakeup_events is 0, it actually notifies the file descriptor
when the ring buffer is half filled (4096 byte size buffer here, (4096 bytes /
2) / (8 bytes per event) = 256 events). Setting this to 1 sends a notification
after every event.

My (rough) reading of the source code supports this understanding:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/kernel/events/ring_buffer.c?id=7475ea8b58616b33c04afb976cf0fbaad9dd63fb#n322

Is this a stale entry in the man page, or is my understanding of this facility
incorrect? If it is indeed stale, perhaps this could read

  Prior to Linux 3.0, setting wakeup_events to 0 resulted in no overflow
  notifications; more recent kernels generate notifications based on a default
  watermark of half the ring buffer size.

Test run of program:
    $ gcc main.c
    $ ./a.out 0
    wakeup_events = 0
    wakeup 1: 257 samples of 8 bytes
    wakeup 2: 256 samples of 8 bytes
    wakeup 3: 256 samples of 8 bytes
    wakeup 4: 256 samples of 8 bytes
    $ ./a.out 1
    wakeup_events = 1
    wakeup 1: 1 samples of 8 bytes
    wakeup 2: 1 samples of 8 bytes
    wakeup 3: 1 samples of 8 bytes
    wakeup 4: 1 samples of 8 bytes

Program:
    #define _GNU_SOURCE
    #include <linux/perf_event.h>
    #include <poll.h>
    #include <pthread.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/ioctl.h>
    #include <sys/mman.h>
    #include <sys/syscall.h>
    #include <unistd.h>

    #define PAGE_SIZE 4096

    static void *workload(void *unused) {
      for (;;) {
      }

      return unused;
    }

    int main(int argc, char **argv) {
      unsigned wakeup_events = argc > 1 ? atoi(argv[1]) : 0;

      pthread_t workload_thread;
      pthread_create(&workload_thread, NULL, workload, NULL);
      // Needs glibc >= 2.42
      pid_t workload_tid = pthread_gettid_np(workload_thread);

      struct perf_event_attr attrs = {.size = sizeof(attrs)};
      attrs.type = PERF_TYPE_SOFTWARE;
      attrs.config = PERF_COUNT_SW_CPU_CLOCK;
      attrs.freq = 1;
      attrs.sample_freq = 49;
      attrs.disabled = 1;
      attrs.exclude_kernel = 1;
      attrs.wakeup_events = wakeup_events;

      int fd = syscall(SYS_perf_event_open, &attrs, workload_tid, -1, -1, 0);
      if (fd < 0) {
        perror("perf_event_open");
        return 1;
      }

      void *buffer =
          mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (buffer == MAP_FAILED) {
        perror("mmap");
        return 1;
      }

      struct perf_event_mmap_page *meta = buffer;
      char *data = (char *)buffer + meta->data_offset;

      ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
      printf("wakeup_events = %u\n", wakeup_events);

      for (int i = 1; i <= 4; i++) {
        struct pollfd poll_fd = {.fd = fd, .events = POLLIN};
        poll(&poll_fd, 1, -1);

        uint64_t head = __atomic_load_n(&meta->data_head, __ATOMIC_ACQUIRE);
        uint64_t tail = meta->data_tail;
        int sample_count = 0;
        int sample_size = 0;

        while (tail < head) {
          struct perf_event_header *header =
              (struct perf_event_header *)(data + tail % meta->data_size);

          if (header->type == PERF_RECORD_SAMPLE) {
            sample_count++;
            sample_size = header->size;
          }

          tail += header->size;
        }
        __atomic_store_n(&meta->data_tail, tail, __ATOMIC_RELEASE);

        printf(
          "wakeup %d: %d samples of %d bytes\n",
          i, sample_count, sample_size
        );
      }

      return 0;
    }




-Nick Krichevsky

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-09  9:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09  2:08 Behavior of wakeup_events being 0 in perf_event_open(2) Nick Krichevsky
2026-11-09  9:16 ` Alejandro Colomar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox