brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · 53383e9 Raw
333 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright IBM Corp. 20194 * Author(s): Thomas Richter <tmricht@linux.ibm.com>5 *6 * This program is free software; you can redistribute it and/or modify7 * it under the terms of the GNU General Public License (version 2 only)8 * as published by the Free Software Foundation.9 *10 * Architecture specific trace_event function. Save event's bc000 raw data11 * to file. File name is aux.ctr.## where ## stands for the CPU number the12 * sample was taken from.13 */14 15#include <unistd.h>16#include <stdio.h>17#include <string.h>18#include <inttypes.h>19 20#include <sys/stat.h>21#include <linux/compiler.h>22#include <asm/byteorder.h>23 24#include "debug.h"25#include "session.h"26#include "evlist.h"27#include "color.h"28#include "sample-raw.h"29#include "s390-cpumcf-kernel.h"30#include "util/pmu.h"31#include "util/sample.h"32 33static size_t ctrset_size(struct cf_ctrset_entry *set)34{35	return sizeof(*set) + set->ctr * sizeof(u64);36}37 38static bool ctrset_valid(struct cf_ctrset_entry *set)39{40	return set->def == S390_CPUMCF_DIAG_DEF;41}42 43/* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte44 * aligned and might have trailing padding bytes.45 * Display the raw data on screen.46 */47static bool s390_cpumcfdg_testctr(struct perf_sample *sample)48{49	size_t len = sample->raw_size, offset = 0;50	unsigned char *buf = sample->raw_data;51	struct cf_trailer_entry *te;52	struct cf_ctrset_entry *cep, ce;53 54	while (offset < len) {55		cep = (struct cf_ctrset_entry *)(buf + offset);56		ce.def = be16_to_cpu(cep->def);57		ce.set = be16_to_cpu(cep->set);58		ce.ctr = be16_to_cpu(cep->ctr);59		ce.res1 = be16_to_cpu(cep->res1);60 61		if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) {62			/* Raw data for counter sets are always multiple of 863			 * bytes. Prepending a 4 bytes size field to the64			 * raw data block in the sample causes the perf tool65			 * to append 4 padding bytes to make the raw data part66			 * of the sample a multiple of eight bytes again.67			 *68			 * If the last entry (trailer) is 4 bytes off the raw69			 * area data end, all is good.70			 */71			if (len - offset - sizeof(*te) == 4)72				break;73			pr_err("Invalid counter set entry at %zd\n", offset);74			return false;75		}76		offset += ctrset_size(&ce);77	}78	return true;79}80 81/* Dump event bc000 on screen, already tested on correctness. */82static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,83				    struct cf_trailer_entry *tep)84{85	struct cf_trailer_entry  te;86 87	te.flags = be64_to_cpu(tep->flags);88	te.cfvn = be16_to_cpu(tep->cfvn);89	te.csvn = be16_to_cpu(tep->csvn);90	te.cpu_speed = be32_to_cpu(tep->cpu_speed);91	te.timestamp = be64_to_cpu(tep->timestamp);92	te.progusage1 = be64_to_cpu(tep->progusage1);93	te.progusage2 = be64_to_cpu(tep->progusage2);94	te.progusage3 = be64_to_cpu(tep->progusage3);95	te.tod_base = be64_to_cpu(tep->tod_base);96	te.mach_type = be16_to_cpu(tep->mach_type);97	te.res1 = be16_to_cpu(tep->res1);98	te.res2 = be32_to_cpu(tep->res2);99 100	color_fprintf(stdout, color, "    [%#08zx] Trailer:%c%c%c%c%c"101		      " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n",102		      offset, te.clock_base ? 'T' : ' ',103		      te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ',104		      te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ',105		      te.cfvn, te.csvn, te.cpu_speed, te.timestamp);106	color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx"107		      " Type:%x\n\n",108		      te.progusage1, te.progusage2, te.progusage3,109		      te.tod_base, te.mach_type);110}111 112/* Return starting number of a counter set */113static int get_counterset_start(int setnr)114{115	switch (setnr) {116	case CPUMF_CTR_SET_BASIC:		/* Basic counter set */117		return 0;118	case CPUMF_CTR_SET_USER:		/* Problem state counter set */119		return 32;120	case CPUMF_CTR_SET_CRYPTO:		/* Crypto counter set */121		return 64;122	case CPUMF_CTR_SET_EXT:			/* Extended counter set */123		return 128;124	case CPUMF_CTR_SET_MT_DIAG:		/* Diagnostic counter set */125		return 448;126	case PERF_EVENT_PAI_NNPA_ALL:		/* PAI NNPA counter set */127	case PERF_EVENT_PAI_CRYPTO_ALL:		/* PAI CRYPTO counter set */128		return setnr;129	default:130		return -1;131	}132}133 134struct get_counter_name_data {135	int wanted;136	char *result;137};138 139static int get_counter_name_callback(void *vdata, struct pmu_event_info *info)140{141	struct get_counter_name_data *data = vdata;142	int rc, event_nr;143	const char *event_str;144 145	if (info->str == NULL)146		return 0;147 148	event_str = strstr(info->str, "event=");149	if (!event_str)150		return 0;151 152	rc = sscanf(event_str, "event=%x", &event_nr);153	if (rc == 1 && event_nr == data->wanted) {154		data->result = strdup(info->name);155		return 1; /* Terminate the search. */156	}157	return 0;158}159 160/* Scan the PMU and extract the logical name of a counter from the event. Input161 * is the counter set and counter number with in the set. Construct the event162 * number and use this as key. If they match return the name of this counter.163 * If no match is found a NULL pointer is returned.164 */165static char *get_counter_name(int set, int nr, struct perf_pmu *pmu)166{167	struct get_counter_name_data data = {168		.wanted = get_counterset_start(set) + nr,169		.result = NULL,170	};171 172	if (!pmu)173		return NULL;174 175	perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/ true,176				 &data, get_counter_name_callback);177	return data.result;178}179 180static void s390_cpumcfdg_dump(struct perf_pmu *pmu, struct perf_sample *sample)181{182	size_t i, len = sample->raw_size, offset = 0;183	unsigned char *buf = sample->raw_data;184	const char *color = PERF_COLOR_BLUE;185	struct cf_ctrset_entry *cep, ce;186	u64 *p;187 188	while (offset < len) {189		cep = (struct cf_ctrset_entry *)(buf + offset);190 191		ce.def = be16_to_cpu(cep->def);192		ce.set = be16_to_cpu(cep->set);193		ce.ctr = be16_to_cpu(cep->ctr);194		ce.res1 = be16_to_cpu(cep->res1);195 196		if (!ctrset_valid(&ce)) {	/* Print trailer */197			s390_cpumcfdg_dumptrail(color, offset,198						(struct cf_trailer_entry *)cep);199			return;200		}201 202		color_fprintf(stdout, color, "    [%#08zx] Counterset:%d"203			      " Counters:%d\n", offset, ce.set, ce.ctr);204		for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {205			char *ev_name = get_counter_name(ce.set, i, pmu);206 207			color_fprintf(stdout, color,208				      "\tCounter:%03d %s Value:%#018lx\n", i,209				      ev_name ?: "<unknown>", be64_to_cpu(*p));210			free(ev_name);211		}212		offset += ctrset_size(&ce);213	}214}215 216#pragma GCC diagnostic push217#pragma GCC diagnostic ignored "-Wpacked"218#pragma GCC diagnostic ignored "-Wattributes"219/*220 * Check for consistency of PAI_CRYPTO/PAI_NNPA raw data.221 */222struct pai_data {		/* Event number and value */223	u16 event_nr;224	u64 event_val;225} __packed;226 227#pragma GCC diagnostic pop228 229/*230 * Test for valid raw data. At least one PAI event should be in the raw231 * data section.232 */233static bool s390_pai_all_test(struct perf_sample *sample)234{235	size_t len = sample->raw_size;236 237	if (len < 0xa)238		return false;239	return true;240}241 242static void s390_pai_all_dump(struct evsel *evsel, struct perf_sample *sample)243{244	size_t len = sample->raw_size, offset = 0;245	unsigned char *p = sample->raw_data;246	const char *color = PERF_COLOR_BLUE;247	struct pai_data pai_data;248	char *ev_name;249 250	while (offset < len) {251		memcpy(&pai_data.event_nr, p, sizeof(pai_data.event_nr));252		pai_data.event_nr = be16_to_cpu(pai_data.event_nr);253		p += sizeof(pai_data.event_nr);254		offset += sizeof(pai_data.event_nr);255 256		memcpy(&pai_data.event_val, p, sizeof(pai_data.event_val));257		pai_data.event_val = be64_to_cpu(pai_data.event_val);258		p += sizeof(pai_data.event_val);259		offset += sizeof(pai_data.event_val);260 261		ev_name = get_counter_name(evsel->core.attr.config,262					   pai_data.event_nr, evsel->pmu);263		color_fprintf(stdout, color, "\tCounter:%03d %s Value:%#018lx\n",264			      pai_data.event_nr, ev_name ?: "<unknown>",265			      pai_data.event_val);266		free(ev_name);267 268		if (offset + 0xa > len)269			break;270	}271	color_fprintf(stdout, color, "\n");272}273 274/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events275 * and if the event was triggered by a276 * - counter set diagnostic event277 * - processor activity assist (PAI) crypto counter event278 * - processor activity assist (PAI) neural network processor assist (NNPA)279 *   counter event280 * display its raw data.281 * The function is only invoked when the dump flag -D is set.282 *283 * Function evlist__s390_sample_raw() is defined as call back after it has284 * been verified that the perf.data file was created on s390 platform.285 */286void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event,287			     struct perf_sample *sample)288{289	const char *pai_name;290	struct evsel *evsel;291 292	if (event->header.type != PERF_RECORD_SAMPLE)293		return;294 295	evsel = evlist__event2evsel(evlist, event);296	if (!evsel)297		return;298 299	/* Check for raw data in sample */300	if (!sample->raw_size || !sample->raw_data)301		return;302 303	/* Display raw data on screen */304	if (evsel->core.attr.config == PERF_EVENT_CPUM_CF_DIAG) {305		if (!evsel->pmu)306			evsel->pmu = perf_pmus__find("cpum_cf");307		if (!s390_cpumcfdg_testctr(sample))308			pr_err("Invalid counter set data encountered\n");309		else310			s390_cpumcfdg_dump(evsel->pmu, sample);311		return;312	}313 314	switch (evsel->core.attr.config) {315	case PERF_EVENT_PAI_NNPA_ALL:316		pai_name = "NNPA_ALL";317		break;318	case PERF_EVENT_PAI_CRYPTO_ALL:319		pai_name = "CRYPTO_ALL";320		break;321	default:322		return;323	}324 325	if (!s390_pai_all_test(sample)) {326		pr_err("Invalid %s raw data encountered\n", pai_name);327	} else {328		if (!evsel->pmu)329			evsel->pmu = perf_pmus__find_by_type(evsel->core.attr.type);330		s390_pai_all_dump(evsel, sample);331	}332}333