2 * Copyright (C) ARM Limited 2014. 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_COUNTER_SET[] = "counter_set";
32 static const char ATTR_COUNT[] = "count";
33 static const char ATTR_DESCRIPTION[] = "description";
34 static const char ATTR_DISPLAY[] = "display";
35 static const char ATTR_EVENT[] = "event";
36 static const char ATTR_EVENT_DELTA[] = "event_delta";
37 static const char ATTR_NAME[] = "name";
38 static const char ATTR_OPTION_SET[] = "option_set";
39 static const char ATTR_TITLE[] = "title";
40 static const char ATTR_UNITS[] = "units";
42 static const char XP_REGION[] = "XP_Region";
43 static const char HNF_REGION[] = "HN-F_Region";
44 static const char RNI_REGION[] = "RN-I_Region";
45 static const char SBAS_REGION[] = "SBAS_Region";
46 static const char CCN_5XX[] = "CCN-5xx";
47 #define ARM_CCN_5XX "ARM_CCN_5XX_"
49 static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
50 static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
51 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." };
52 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" };
53 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." };
54 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" };
55 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." };
56 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" };
57 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." };
59 // This class is used only to poll for CCN-5xx configuration and emit events XML for it. All other operations are handled by PerfDriver
61 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) {
62 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
65 static unsigned int getConfig(unsigned int node, unsigned int type, unsigned int event, unsigned int port, unsigned int vc) {
67 ((node & 0xff) << 0) |
68 ((type & 0xff) << 8) |
69 ((event & 0xff) << 16) |
70 ((port & 0x03) << 24) |
75 static bool perfPoll(struct perf_event_attr *const pea) {
76 int fd = sys_perf_event_open(pea, -1, 0, -1, 0);
84 CCNDriver::CCNDriver() : mNodeTypes(NULL), mXpCount(0) {
87 CCNDriver::~CCNDriver() {
91 bool CCNDriver::claimCounter(const Counter &) const {
92 // Handled by PerfDriver
96 void CCNDriver::resetCounters() {
97 // Handled by PerfDriver
100 void CCNDriver::setupCounter(Counter &) {
101 // Handled by PerfDriver
104 void CCNDriver::readEvents(mxml_node_t *const) {
106 if (stat("/sys/bus/event_source/devices/ccn", &st) != 0) {
112 if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
113 logg->logError(__FILE__, __LINE__, "Unable to read CCN-5xx type");
117 // Detect number of xps
118 struct perf_event_attr pea;
119 memset(&pea, 0, sizeof(pea));
121 pea.size = sizeof(pea);
125 pea.config = getConfig(0, 0x08, 1, 0, 1) | mXpCount;
126 if (!perfPoll(&pea)) {
132 int lower = mXpCount/2 + 1;
133 while (lower < mXpCount) {
134 int mid = (lower + mXpCount)/2;
135 pea.config = getConfig(0, 0x08, 1, 0, 1) | mid;
136 if (perfPoll(&pea)) {
144 mNodeTypes = new NodeType[2*mXpCount];
147 for (int i = 0; i < 2*mXpCount; ++i) {
148 pea.config = getConfig(0, 0x04, 1, 0, 0) | i;
149 if (perfPoll(&pea)) {
150 mNodeTypes[i] = NT_HNF;
154 pea.config = getConfig(0, 0x16, 1, 0, 0) | i;
155 if (perfPoll(&pea)) {
156 mNodeTypes[i] = NT_RNI;
160 pea.config = getConfig(0, 0x10, 1, 0, 0) | i;
161 if (perfPoll(&pea)) {
162 mNodeTypes[i] = NT_SBAS;
166 mNodeTypes[i] = NT_UNKNOWN;
170 int CCNDriver::writeCounters(mxml_node_t *const) const {
171 // Handled by PerfDriver
175 void CCNDriver::writeEvents(mxml_node_t *const root) const {
176 mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
177 mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
178 mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
180 mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
181 mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
182 mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
184 mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
185 mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
186 mxmlElementSetAttr(clock_event, ATTR_EVENT, "0xff00");
187 mxmlElementSetAttr(clock_event, ATTR_TITLE, "CCN-5xx Clock");
188 mxmlElementSetAttr(clock_event, ATTR_NAME, "Cycles");
189 mxmlElementSetAttr(clock_event, ATTR_DISPLAY, "hertz");
190 mxmlElementSetAttr(clock_event, ATTR_UNITS, "Hz");
191 mxmlElementSetAttr(clock_event, ATTR_AVERAGE_SELECTION, "yes");
192 mxmlElementSetAttr(clock_event, ATTR_DESCRIPTION, "The number of core clock cycles");
194 mxml_node_t *const xp_option_set = mxmlNewElement(category, TAG_OPTION_SET);
195 mxmlElementSetAttr(xp_option_set, ATTR_NAME, XP_REGION);
197 for (int i = 0; i < mXpCount; ++i) {
198 mxml_node_t *const option = mxmlNewElement(xp_option_set, TAG_OPTION);
199 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
200 mxmlElementSetAttrf(option, ATTR_NAME, "XP %i", i);
201 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Crosspoint %i", i);
204 for (int vc = 0; vc < ARRAY_LENGTH(VC_TYPES); ++vc) {
205 if (VC_TYPES[vc] == NULL) {
208 for (int bus = 0; bus < 2; ++bus) {
209 for (int eventId = 0; eventId < ARRAY_LENGTH(XP_EVENT_NAMES); ++eventId) {
210 if (XP_EVENT_NAMES[eventId] == NULL) {
213 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
214 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x08, eventId, bus, vc));
215 mxmlElementSetAttr(event, ATTR_OPTION_SET, XP_REGION);
216 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
217 mxmlElementSetAttrf(event, ATTR_NAME, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_NAMES[eventId]);
218 mxmlElementSetAttrf(event, ATTR_DESCRIPTION, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_DESCRIPTIONS[eventId]);
223 mxml_node_t *const hnf_option_set = mxmlNewElement(category, TAG_OPTION_SET);
224 mxmlElementSetAttr(hnf_option_set, ATTR_NAME, HNF_REGION);
226 for (int eventId = 0; eventId < ARRAY_LENGTH(HNF_EVENT_NAMES); ++eventId) {
227 if (HNF_EVENT_NAMES[eventId] == NULL) {
230 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
231 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x04, eventId, 0, 0));
232 mxmlElementSetAttr(event, ATTR_OPTION_SET, HNF_REGION);
233 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
234 mxmlElementSetAttr(event, ATTR_NAME, HNF_EVENT_NAMES[eventId]);
235 mxmlElementSetAttr(event, ATTR_DESCRIPTION, HNF_EVENT_DESCRIPTIONS[eventId]);
238 mxml_node_t *const rni_option_set = mxmlNewElement(category, TAG_OPTION_SET);
239 mxmlElementSetAttr(rni_option_set, ATTR_NAME, RNI_REGION);
241 for (int eventId = 0; eventId < ARRAY_LENGTH(RNI_EVENT_NAMES); ++eventId) {
242 if (RNI_EVENT_NAMES[eventId] == NULL) {
245 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
246 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x16, eventId, 0, 0));
247 mxmlElementSetAttr(event, ATTR_OPTION_SET, RNI_REGION);
248 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
249 mxmlElementSetAttr(event, ATTR_NAME, RNI_EVENT_NAMES[eventId]);
250 mxmlElementSetAttr(event, ATTR_DESCRIPTION, RNI_EVENT_DESCRIPTIONS[eventId]);
253 mxml_node_t *const sbas_option_set = mxmlNewElement(category, TAG_OPTION_SET);
254 mxmlElementSetAttr(sbas_option_set, ATTR_NAME, SBAS_REGION);
256 for (int eventId = 0; eventId < ARRAY_LENGTH(SBAS_EVENT_NAMES); ++eventId) {
257 if (SBAS_EVENT_NAMES[eventId] == NULL) {
260 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
261 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x10, eventId, 0, 0));
262 mxmlElementSetAttr(event, ATTR_OPTION_SET, SBAS_REGION);
263 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
264 mxmlElementSetAttr(event, ATTR_NAME, SBAS_EVENT_NAMES[eventId]);
265 mxmlElementSetAttr(event, ATTR_DESCRIPTION, SBAS_EVENT_DESCRIPTIONS[eventId]);
268 for (int i = 0; i < 2*mXpCount; ++i) {
269 switch (mNodeTypes[i]) {
271 mxml_node_t *const option = mxmlNewElement(hnf_option_set, TAG_OPTION);
272 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
273 mxmlElementSetAttrf(option, ATTR_NAME, "HN-F %i", i);
274 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Fully-coherent Home Node %i", i);
278 mxml_node_t *const option = mxmlNewElement(rni_option_set, TAG_OPTION);
279 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
280 mxmlElementSetAttrf(option, ATTR_NAME, "RN-I %i", i);
281 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "I/O-coherent Requesting Node %i", i);
285 mxml_node_t *const option = mxmlNewElement(sbas_option_set, TAG_OPTION);
286 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
287 mxmlElementSetAttrf(option, ATTR_NAME, "SBAS %i", i);
288 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "ACE master to CHI protocol bridge %i", i);