blob: d77513acc4e42e82c01e8dec78aedc55dc161d34 [file] [log] [blame]
Jon Medhurst96b56152014-10-30 18:01:15 +00001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2014-2015. All rights reserved.
Jon Medhurst96b56152014-10-30 18:01:15 +00003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "CCNDriver.h"
10
11#include <unistd.h>
12#include <sys/syscall.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <unistd.h>
16
17#include "k/perf_event.h"
18
19#include "Config.h"
20#include "DriverSource.h"
21#include "Logging.h"
22
23static const char TAG_CATEGORY[] = "category";
24static const char TAG_COUNTER_SET[] = "counter_set";
25static const char TAG_EVENT[] = "event";
26static const char TAG_OPTION[] = "option";
27static const char TAG_OPTION_SET[] = "option_set";
28
29static const char ATTR_AVERAGE_SELECTION[] = "average_selection";
30static const char ATTR_COUNTER[] = "counter";
Jon Medhurst96b56152014-10-30 18:01:15 +000031static const char ATTR_COUNT[] = "count";
32static const char ATTR_DESCRIPTION[] = "description";
33static const char ATTR_DISPLAY[] = "display";
34static const char ATTR_EVENT[] = "event";
35static const char ATTR_EVENT_DELTA[] = "event_delta";
36static const char ATTR_NAME[] = "name";
37static const char ATTR_OPTION_SET[] = "option_set";
38static const char ATTR_TITLE[] = "title";
39static const char ATTR_UNITS[] = "units";
40
41static const char XP_REGION[] = "XP_Region";
42static const char HNF_REGION[] = "HN-F_Region";
43static const char RNI_REGION[] = "RN-I_Region";
44static const char SBAS_REGION[] = "SBAS_Region";
45static const char CCN_5XX[] = "CCN-5xx";
46#define ARM_CCN_5XX "ARM_CCN_5XX_"
47
48static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
49static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
50static const char *const XP_EVENT_DESCRIPTIONS[] = { NULL, "Set H-bit, signaled when this XP sets the H-bit.", "Set S-bit, signaled when this XP sets the S-bit.", "Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC.", "No TknV, signaled when this XP transmits a valid packet." };
51static const char *const HNF_EVENT_NAMES[] = { NULL, "Cache Miss", "L3 SF Cache Access", "Cache Fill", "POCQ Retry", "POCQ Reqs Recvd", "SF Hit", "SF Evictions", "Snoops Sent", "Snoops Broadcast", "L3 Eviction", "L3 Fill Invalid Way", "MC Retries", "MC Reqs", "QOS HH Retry" };
52static const char *const HNF_EVENT_DESCRIPTIONS[] = { NULL, "Counts the total cache misses. This is the first time lookup result, and is high priority.", "Counts the number of cache accesses. This is the first time access, and is high priority.", "Counts the total allocations in the HN L3 cache, and all cache line allocations to the L3 cache.", "Counts the number of requests that have been retried.", "Counts the number of requests received by HN.", "Counts the number of snoop filter hits.", "Counts the number of snoop filter evictions. Cache invalidations are initiated.", "Counts the number of snoops sent. Does not differentiate between broadcast or directed snoops.", "Counts the number of snoop broadcasts sent.", "Counts the number of L3 evictions.", "Counts the number of L3 fills to an invalid way.", "Counts the number of transactions retried by the memory controller.", "Counts the number of requests to the memory controller.", "Counts the number of times a highest-priority QoS class was retried at the HN-F." };
53static const char *const RNI_EVENT_NAMES[] = { NULL, "S0 RDataBeats", "S1 RDataBeats", "S2 RDataBeats", "RXDAT Flits received", "TXDAT Flits sent", "Total TXREQ Flits sent", "Retried TXREQ Flits sent", "RRT full", "WRT full", "Replayed TXREQ Flits" };
54static const char *const RNI_EVENT_DESCRIPTIONS[] = { NULL, "S0 RDataBeats.", "S1 RDataBeats.", "S2 RDataBeats.", "RXDAT Flits received.", "TXDAT Flits sent.", "Total TXREQ Flits sent.", "Retried TXREQ Flits sent.", "RRT full.", "WRT full.", "Replayed TXREQ Flits." };
55static const char *const SBAS_EVENT_NAMES[] = { NULL, "S0 RDataBeats", NULL, NULL, "RXDAT Flits received", "TXDAT Flits sent", "Total TXREQ Flits sent", "Retried TXREQ Flits sent", "RRT full", "WRT full", "Replayed TXREQ Flits" };
56static const char *const SBAS_EVENT_DESCRIPTIONS[] = { NULL, "S0 RDataBeats.", NULL, NULL, "RXDAT Flits received.", "TXDAT Flits sent.", "Total TXREQ Flits sent.", "Retried TXREQ Flits sent.", "RRT full.", "WRT full.", "Replayed TXREQ Flits." };
57
58// This class is used only to poll for CCN-5xx configuration and emit events XML for it. All other operations are handled by PerfDriver
59
60static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
61 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
62}
63
64static unsigned int getConfig(unsigned int node, unsigned int type, unsigned int event, unsigned int port, unsigned int vc) {
65 return
66 ((node & 0xff) << 0) |
67 ((type & 0xff) << 8) |
68 ((event & 0xff) << 16) |
69 ((port & 0x03) << 24) |
70 ((vc & 0x07) << 26) |
71 0;
72}
73
74static bool perfPoll(struct perf_event_attr *const pea) {
75 int fd = sys_perf_event_open(pea, -1, 0, -1, 0);
76 if (fd < 0) {
77 return false;
78 }
79 close(fd);
80 return true;
81}
82
83CCNDriver::CCNDriver() : mNodeTypes(NULL), mXpCount(0) {
84}
85
86CCNDriver::~CCNDriver() {
87 delete mNodeTypes;
88}
89
90bool CCNDriver::claimCounter(const Counter &) const {
91 // Handled by PerfDriver
92 return false;
93}
94
95void CCNDriver::resetCounters() {
96 // Handled by PerfDriver
97}
98
99void CCNDriver::setupCounter(Counter &) {
100 // Handled by PerfDriver
101}
102
103void CCNDriver::readEvents(mxml_node_t *const) {
104 struct stat st;
105 if (stat("/sys/bus/event_source/devices/ccn", &st) != 0) {
106 // Not found
107 return;
108 }
109
110 int type;
111 if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100112 logg->logError("Unable to read CCN-5xx type");
Jon Medhurst96b56152014-10-30 18:01:15 +0000113 handleException();
114 }
115
116 // Detect number of xps
117 struct perf_event_attr pea;
118 memset(&pea, 0, sizeof(pea));
119 pea.type = type;
120 pea.size = sizeof(pea);
121
122 mXpCount = 1;
123 while (true) {
124 pea.config = getConfig(0, 0x08, 1, 0, 1) | mXpCount;
125 if (!perfPoll(&pea)) {
126 break;
127 }
128 mXpCount *= 2;
129 };
130 {
131 int lower = mXpCount/2 + 1;
132 while (lower < mXpCount) {
133 int mid = (lower + mXpCount)/2;
134 pea.config = getConfig(0, 0x08, 1, 0, 1) | mid;
135 if (perfPoll(&pea)) {
136 lower = mid + 1;
137 } else {
138 mXpCount = mid;
139 }
140 }
141 }
142
143 mNodeTypes = new NodeType[2*mXpCount];
144
145 // Detect node types
146 for (int i = 0; i < 2*mXpCount; ++i) {
147 pea.config = getConfig(0, 0x04, 1, 0, 0) | i;
148 if (perfPoll(&pea)) {
149 mNodeTypes[i] = NT_HNF;
150 continue;
151 }
152
153 pea.config = getConfig(0, 0x16, 1, 0, 0) | i;
154 if (perfPoll(&pea)) {
155 mNodeTypes[i] = NT_RNI;
156 continue;
157 }
158
159 pea.config = getConfig(0, 0x10, 1, 0, 0) | i;
160 if (perfPoll(&pea)) {
161 mNodeTypes[i] = NT_SBAS;
162 continue;
163 }
164
165 mNodeTypes[i] = NT_UNKNOWN;
166 }
167}
168
169int CCNDriver::writeCounters(mxml_node_t *const) const {
170 // Handled by PerfDriver
171 return 0;
172}
173
174void CCNDriver::writeEvents(mxml_node_t *const root) const {
175 mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
176 mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
177 mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
178
179 mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
180 mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
181 mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
182
183 mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
184 mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
185 mxmlElementSetAttr(clock_event, ATTR_EVENT, "0xff00");
186 mxmlElementSetAttr(clock_event, ATTR_TITLE, "CCN-5xx Clock");
187 mxmlElementSetAttr(clock_event, ATTR_NAME, "Cycles");
188 mxmlElementSetAttr(clock_event, ATTR_DISPLAY, "hertz");
189 mxmlElementSetAttr(clock_event, ATTR_UNITS, "Hz");
190 mxmlElementSetAttr(clock_event, ATTR_AVERAGE_SELECTION, "yes");
191 mxmlElementSetAttr(clock_event, ATTR_DESCRIPTION, "The number of core clock cycles");
192
193 mxml_node_t *const xp_option_set = mxmlNewElement(category, TAG_OPTION_SET);
194 mxmlElementSetAttr(xp_option_set, ATTR_NAME, XP_REGION);
195
196 for (int i = 0; i < mXpCount; ++i) {
197 mxml_node_t *const option = mxmlNewElement(xp_option_set, TAG_OPTION);
198 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
199 mxmlElementSetAttrf(option, ATTR_NAME, "XP %i", i);
200 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Crosspoint %i", i);
201 }
202
203 for (int vc = 0; vc < ARRAY_LENGTH(VC_TYPES); ++vc) {
204 if (VC_TYPES[vc] == NULL) {
205 continue;
206 }
207 for (int bus = 0; bus < 2; ++bus) {
208 for (int eventId = 0; eventId < ARRAY_LENGTH(XP_EVENT_NAMES); ++eventId) {
209 if (XP_EVENT_NAMES[eventId] == NULL) {
210 continue;
211 }
212 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
213 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x08, eventId, bus, vc));
214 mxmlElementSetAttr(event, ATTR_OPTION_SET, XP_REGION);
215 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
216 mxmlElementSetAttrf(event, ATTR_NAME, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_NAMES[eventId]);
217 mxmlElementSetAttrf(event, ATTR_DESCRIPTION, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_DESCRIPTIONS[eventId]);
218 }
219 }
220 }
221
222 mxml_node_t *const hnf_option_set = mxmlNewElement(category, TAG_OPTION_SET);
223 mxmlElementSetAttr(hnf_option_set, ATTR_NAME, HNF_REGION);
224
225 for (int eventId = 0; eventId < ARRAY_LENGTH(HNF_EVENT_NAMES); ++eventId) {
226 if (HNF_EVENT_NAMES[eventId] == NULL) {
227 continue;
228 }
229 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
230 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x04, eventId, 0, 0));
231 mxmlElementSetAttr(event, ATTR_OPTION_SET, HNF_REGION);
232 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
233 mxmlElementSetAttr(event, ATTR_NAME, HNF_EVENT_NAMES[eventId]);
234 mxmlElementSetAttr(event, ATTR_DESCRIPTION, HNF_EVENT_DESCRIPTIONS[eventId]);
235 }
236
237 mxml_node_t *const rni_option_set = mxmlNewElement(category, TAG_OPTION_SET);
238 mxmlElementSetAttr(rni_option_set, ATTR_NAME, RNI_REGION);
239
240 for (int eventId = 0; eventId < ARRAY_LENGTH(RNI_EVENT_NAMES); ++eventId) {
241 if (RNI_EVENT_NAMES[eventId] == NULL) {
242 continue;
243 }
244 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
245 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x16, eventId, 0, 0));
246 mxmlElementSetAttr(event, ATTR_OPTION_SET, RNI_REGION);
247 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
248 mxmlElementSetAttr(event, ATTR_NAME, RNI_EVENT_NAMES[eventId]);
249 mxmlElementSetAttr(event, ATTR_DESCRIPTION, RNI_EVENT_DESCRIPTIONS[eventId]);
250 }
251
252 mxml_node_t *const sbas_option_set = mxmlNewElement(category, TAG_OPTION_SET);
253 mxmlElementSetAttr(sbas_option_set, ATTR_NAME, SBAS_REGION);
254
255 for (int eventId = 0; eventId < ARRAY_LENGTH(SBAS_EVENT_NAMES); ++eventId) {
256 if (SBAS_EVENT_NAMES[eventId] == NULL) {
257 continue;
258 }
259 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
260 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x10, eventId, 0, 0));
261 mxmlElementSetAttr(event, ATTR_OPTION_SET, SBAS_REGION);
262 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
263 mxmlElementSetAttr(event, ATTR_NAME, SBAS_EVENT_NAMES[eventId]);
264 mxmlElementSetAttr(event, ATTR_DESCRIPTION, SBAS_EVENT_DESCRIPTIONS[eventId]);
265 }
266
267 for (int i = 0; i < 2*mXpCount; ++i) {
268 switch (mNodeTypes[i]) {
269 case NT_HNF: {
270 mxml_node_t *const option = mxmlNewElement(hnf_option_set, TAG_OPTION);
271 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
272 mxmlElementSetAttrf(option, ATTR_NAME, "HN-F %i", i);
273 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Fully-coherent Home Node %i", i);
274 break;
275 }
276 case NT_RNI: {
277 mxml_node_t *const option = mxmlNewElement(rni_option_set, TAG_OPTION);
278 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
279 mxmlElementSetAttrf(option, ATTR_NAME, "RN-I %i", i);
280 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "I/O-coherent Requesting Node %i", i);
281 break;
282 }
283 case NT_SBAS: {
284 mxml_node_t *const option = mxmlNewElement(sbas_option_set, TAG_OPTION);
285 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
286 mxmlElementSetAttrf(option, ATTR_NAME, "SBAS %i", i);
287 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "ACE master to CHI protocol bridge %i", i);
288 break;
289 }
290 default:
291 continue;
292 }
293 }
294}