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