Repository: google/benchmark
File: src/perf_counters.cc (C++)

Code before:
    const int pfm_get = pfm_get_os_event_encoding(name.c_str(), kCounterMode,
                                                  PFM_OS_PERF_EVENT, &arg);
    if (pfm_get != PFM_SUCCESS) {
      GetErrorLogInstance()
          << "Unknown performance counter name: " << name << "\n";
      continue;
    }

    // We then proceed to populate the remaining fields in our attribute struct
    // Note: the man page for perf_event_create suggests inherit = true and
    // read_format = PERF_FORMAT_GROUP don't work together, but that's not the
    // case.
    attr.disabled = is_first;
    attr.inherit = true;
    attr.pinned = is_first;
    attr.exclude_kernel = true;
    attr.exclude_user = false;
    attr.exclude_hv = true;

    // Read all counters in a group in one read.
    attr.read_format = PERF_FORMAT_GROUP;  //| PERF_FORMAT_TOTAL_TIME_ENABLED |
                                           // PERF_FORMAT_TOTAL_TIME_RUNNING;

    uint64_t base_config = attr.config;
    for (uint64_t pmu : GetPMUTypesForEvent(attr)) {
      attr.config = (pmu << 32) | base_config;
      int id = -1;
      while (id < 0) {
        static constexpr size_t kNrOfSyscallRetries = 5;
        // Retry syscall as it was interrupted often (b/64774091).
        for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries;
             ++num_retries) {
          id = perf_event_open(&attr, 0, -1, group_id, 0);
          if (id >= 0 || errno != EINTR) {
            break;
          }
        }
        if (id < 0) {
          // If the file descriptor is negative we might have reached a limit
          // in the current group. Set the group_id to -1 and retry
          if (group_id >= 0) {
            // Create a new group
            group_id = -1;
          } else {
            // At this point we have already retried to set a new group id and
            // failed. We then give up.
            break;
          }
        }
      }


Review comment (suggestion):
Fwiw, the 32 constant is PERF_PMU_TYPE_SHIFT in perf_event.h:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/perf_event.h#n55

Code after:
    // This struct will be populated by libpfm from the counter string
    // and then fed into the syscall perf_event_open
    struct perf_event_attr attr {};
    attr.size = sizeof(attr);

    // This is the input struct to libpfm.
    pfm_perf_encode_arg_t arg{};
    arg.attr = &attr;
    const int pfm_get = pfm_get_os_event_encoding(name.c_str(), kCounterMode,
                                                  PFM_OS_PERF_EVENT, &arg);
    if (pfm_get != PFM_SUCCESS) {
      GetErrorLogInstance()
          << "Unknown performance counter name: " << name << "\n";
      continue;
    }

    // We then proceed to populate the remaining fields in our attribute struct
    // Note: the man page for perf_event_create suggests inherit = true and
    // read_format = PERF_FORMAT_GROUP don't work together, but that's not the
    // case.
    attr.disabled = is_first;
    attr.inherit = true;
    attr.pinned = is_first;
    attr.exclude_kernel = true;
    attr.exclude_user = false;
    attr.exclude_hv = true;

    // Read all counters in a group in one read.
    attr.read_format = PERF_FORMAT_GROUP;  //| PERF_FORMAT_TOTAL_TIME_ENABLED |
                                           // PERF_FORMAT_TOTAL_TIME_RUNNING;

    uint64_t base_config = attr.config;
    for (uint64_t pmu : GetPMUTypesForEvent(attr)) {
      attr.config = (pmu << PERF_PMU_TYPE_SHIFT) | base_config;
      int id = -1;
      while (id < 0) {
        static constexpr size_t kNrOfSyscallRetries = 5;
        // Retry syscall as it was interrupted often (b/64774091).
        for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries;
             ++num_retries) {
          id = perf_event_open(&attr, 0, -1, group_id, 0);
          if (id >= 0 || errno != EINTR) {
            break;
          }
        }
        if (id < 0) {
          // If the file descriptor is negative we might have reached a limit
          // in the current group. Set the group_id to -1 and retry
          if (group_id >= 0) {
            // Create a new group
            group_id = -1;