2 * Copyright (C) ARM Limited 2014-2015. All rights reserved.
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.
12 #include <sys/syscall.h>
13 #include <sys/types.h>
17 #include "k/perf_event.h"
20 #include "DriverSource.h"
23 static const char TAG_CATEGORY[] = "category";
24 static const char TAG_COUNTER_SET[] = "counter_set";
25 static const char TAG_EVENT[] = "event";
26 static const char TAG_OPTION[] = "option";
27 static const char TAG_OPTION_SET[] = "option_set";
29 static const char ATTR_AVERAGE_SELECTION[] = "average_selection";
30 static const char ATTR_COUNTER[] = "counter";
31 static const char ATTR_COUNT[] = "count";
32 static const char ATTR_DESCRIPTION[] = "description";
33 static const char ATTR_DISPLAY[] = "display";
34 static const char ATTR_EVENT[] = "event";
35 static const char ATTR_EVENT_DELTA[] = "event_delta";
36 static const char ATTR_NAME[] = "name";
37 static const char ATTR_OPTION_SET[] = "option_set";
38 static const char ATTR_TITLE[] = "title";
39 static const char ATTR_UNITS[] = "units";
41 static const char XP_REGION[] = "XP_Region";
42 static const char HNF_REGION[] = "HN-F_Region";
43 static const char RNI_REGION[] = "RN-I_Region";
44 static const char SBAS_REGION[] = "SBAS_Region";
45 static const char CCN_5XX[] = "CCN-5xx";
46 #define ARM_CCN_5XX "ARM_CCN_5XX_"
48 static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
49 static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
50 static 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." };
51 static 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" };
52 static 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." };
53 static 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" };
54 static 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." };
55 static 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" };
56 static 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." };
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
60 static 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);
64 static unsigned int getConfig(unsigned int node, unsigned int type, unsigned int event, unsigned int port, unsigned int vc) {
66 ((node & 0xff) << 0) |
67 ((type & 0xff) << 8) |
68 ((event & 0xff) << 16) |
69 ((port & 0x03) << 24) |
74 static bool perfPoll(struct perf_event_attr *const pea) {
75 int fd = sys_perf_event_open(pea, -1, 0, -1, 0);
83 CCNDriver::CCNDriver() : mNodeTypes(NULL), mXpCount(0) {
86 CCNDriver::~CCNDriver() {
90 bool CCNDriver::claimCounter(const Counter &) const {
91 // Handled by PerfDriver
95 void CCNDriver::resetCounters() {
96 // Handled by PerfDriver
99 void CCNDriver::setupCounter(Counter &) {
100 // Handled by PerfDriver
103 void CCNDriver::readEvents(mxml_node_t *const) {
105 if (stat("/sys/bus/event_source/devices/ccn", &st) != 0) {
111 if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
112 logg->logError("Unable to read CCN-5xx type");
116 // Detect number of xps
117 struct perf_event_attr pea;
118 memset(&pea, 0, sizeof(pea));
120 pea.size = sizeof(pea);
124 pea.config = getConfig(0, 0x08, 1, 0, 1) | mXpCount;
125 if (!perfPoll(&pea)) {
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)) {
143 mNodeTypes = new NodeType[2*mXpCount];
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;
153 pea.config = getConfig(0, 0x16, 1, 0, 0) | i;
154 if (perfPoll(&pea)) {
155 mNodeTypes[i] = NT_RNI;
159 pea.config = getConfig(0, 0x10, 1, 0, 0) | i;
160 if (perfPoll(&pea)) {
161 mNodeTypes[i] = NT_SBAS;
165 mNodeTypes[i] = NT_UNKNOWN;
169 int CCNDriver::writeCounters(mxml_node_t *const) const {
170 // Handled by PerfDriver
174 void 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");
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");
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");
193 mxml_node_t *const xp_option_set = mxmlNewElement(category, TAG_OPTION_SET);
194 mxmlElementSetAttr(xp_option_set, ATTR_NAME, XP_REGION);
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);
203 for (int vc = 0; vc < ARRAY_LENGTH(VC_TYPES); ++vc) {
204 if (VC_TYPES[vc] == NULL) {
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) {
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]);
222 mxml_node_t *const hnf_option_set = mxmlNewElement(category, TAG_OPTION_SET);
223 mxmlElementSetAttr(hnf_option_set, ATTR_NAME, HNF_REGION);
225 for (int eventId = 0; eventId < ARRAY_LENGTH(HNF_EVENT_NAMES); ++eventId) {
226 if (HNF_EVENT_NAMES[eventId] == NULL) {
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]);
237 mxml_node_t *const rni_option_set = mxmlNewElement(category, TAG_OPTION_SET);
238 mxmlElementSetAttr(rni_option_set, ATTR_NAME, RNI_REGION);
240 for (int eventId = 0; eventId < ARRAY_LENGTH(RNI_EVENT_NAMES); ++eventId) {
241 if (RNI_EVENT_NAMES[eventId] == NULL) {
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]);
252 mxml_node_t *const sbas_option_set = mxmlNewElement(category, TAG_OPTION_SET);
253 mxmlElementSetAttr(sbas_option_set, ATTR_NAME, SBAS_REGION);
255 for (int eventId = 0; eventId < ARRAY_LENGTH(SBAS_EVENT_NAMES); ++eventId) {
256 if (SBAS_EVENT_NAMES[eventId] == NULL) {
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]);
267 for (int i = 0; i < 2*mXpCount; ++i) {
268 switch (mNodeTypes[i]) {
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);
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);
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);