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
20 namespace pps
21 {
IntelPerf(const int drm_fd)22 IntelPerf::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
~IntelPerf()42 IntelPerf::~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
get_queries() const55 std::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+
get_oa_exponent(const intel_device_info * devinfo,const uint64_t sampling_period_ns)76 static 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
open(const uint64_t sampling_period_ns,struct intel_perf_query_info * query)81 bool 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
close()100 void IntelPerf::close()
101 {
102 if (ctx) {
103 intel_perf_close(ctx, nullptr);
104 ctx = nullptr;
105 }
106 }
107
oa_stream_ready() const108 bool IntelPerf::oa_stream_ready() const
109 {
110 assert(ctx && "Perf context was not open");
111 return intel_perf_oa_stream_ready(ctx);
112 }
113
read_oa_stream(void * buf,size_t bytes) const114 ssize_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