1/*
2 * Copyright © 2021 Collabora, Ltd.
3 * Author: Antonio Caggiano <antonio.caggiano@collabora.com>
4 *
5 * SPDX-License-Identifier: MIT
6 */
7
8#include "intel_pps_perf.h"
9
10#include <math.h>
11#include <sys/ioctl.h>
12#include <util/ralloc.h>
13#include <utility>
14
15#include "drm-uapi/i915_drm.h"
16
17#include <pps/pps.h>
18#include <pps/pps_device.h>
19
20namespace pps
21{
22IntelPerf::IntelPerf(const int drm_fd)
23   : drm_fd {drm_fd}
24   , ralloc_ctx {ralloc_context(nullptr)}
25   , ralloc_cfg {ralloc_context(nullptr)}
26   , cfg {intel_perf_new(ralloc_cfg)}
27{
28   assert(drm_fd >= 0 && "DRM fd is not valid");
29
30   if (!intel_get_device_info_from_fd(drm_fd, &devinfo)) {
31      PPS_LOG_FATAL("Failed to get devinfo");
32   }
33
34   intel_perf_init_metrics(cfg,
35      &devinfo,
36      drm_fd,
37      false, // no pipeline statistics
38      false  // no register snapshots
39   );
40}
41
42IntelPerf::~IntelPerf()
43{
44   close();
45
46   if (ralloc_ctx) {
47      ralloc_free(ralloc_ctx);
48   }
49
50   if (ralloc_cfg) {
51      ralloc_free(ralloc_cfg);
52   }
53}
54
55std::vector<struct intel_perf_query_info *> IntelPerf::get_queries() const
56{
57   assert(cfg && "Intel perf config should be valid");
58   assert(cfg->n_queries && "Intel perf queries not initialized");
59
60   std::vector<struct intel_perf_query_info *> queries = {};
61
62   for (int i = 0; i < cfg->n_queries; ++i) {
63      struct intel_perf_query_info *query = &cfg->queries[i];
64      // Skip invalid queries
65      if (query && query->symbol_name) {
66         queries.push_back(query);
67      }
68   }
69
70   return queries;
71}
72
73// The period_exponent gives a sampling period as follows:
74// sample_period = timestamp_period * 2^(period_exponent + 1)
75// where timestamp_period is 80ns for Haswell+
76static uint32_t get_oa_exponent(const intel_device_info *devinfo, const uint64_t sampling_period_ns)
77{
78   return static_cast<uint32_t>(log2(sampling_period_ns * devinfo->timestamp_frequency / 1000000000ull)) - 1;
79}
80
81bool IntelPerf::open(const uint64_t sampling_period_ns,
82                     struct intel_perf_query_info *query)
83{
84   assert(!ctx && "Perf context should not be initialized at this point");
85
86   ctx = intel_perf_new_context(ralloc_ctx);
87   intel_perf_init_context(ctx, cfg, nullptr, nullptr, nullptr, &devinfo, 0, drm_fd);
88
89   auto oa_exponent = get_oa_exponent(&devinfo, sampling_period_ns);
90
91   return intel_perf_open(ctx,
92      query->oa_metrics_set_id,
93      query->oa_format,
94      oa_exponent,
95      drm_fd,
96      INTEL_PERF_INVALID_CTX_ID,
97      true /* enable stream immediately */);
98}
99
100void IntelPerf::close()
101{
102   if (ctx) {
103      intel_perf_close(ctx, nullptr);
104      ctx = nullptr;
105   }
106}
107
108bool IntelPerf::oa_stream_ready() const
109{
110   assert(ctx && "Perf context was not open");
111   return intel_perf_oa_stream_ready(ctx);
112}
113
114ssize_t IntelPerf::read_oa_stream(void *buf, size_t bytes) const
115{
116   assert(ctx && "Perf context was not open");
117   return intel_perf_read_oa_stream(ctx, buf, bytes);
118}
119
120} // namespace pps
121