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