193115d32SThomas Richter // SPDX-License-Identifier: GPL-2.0 293115d32SThomas Richter /* 393115d32SThomas Richter * Copyright IBM Corp. 2019 493115d32SThomas Richter * Author(s): Thomas Richter <tmricht@linux.ibm.com> 593115d32SThomas Richter * 693115d32SThomas Richter * This program is free software; you can redistribute it and/or modify 793115d32SThomas Richter * it under the terms of the GNU General Public License (version 2 only) 893115d32SThomas Richter * as published by the Free Software Foundation. 993115d32SThomas Richter * 1093115d32SThomas Richter * Architecture specific trace_event function. Save event's bc000 raw data 1193115d32SThomas Richter * to file. File name is aux.ctr.## where ## stands for the CPU number the 1293115d32SThomas Richter * sample was taken from. 1393115d32SThomas Richter */ 1493115d32SThomas Richter 1593115d32SThomas Richter #include <unistd.h> 1693115d32SThomas Richter #include <stdio.h> 1793115d32SThomas Richter #include <string.h> 1893115d32SThomas Richter #include <inttypes.h> 1993115d32SThomas Richter 2093115d32SThomas Richter #include <sys/stat.h> 2193115d32SThomas Richter #include <linux/compiler.h> 2293115d32SThomas Richter #include <asm/byteorder.h> 2393115d32SThomas Richter 2493115d32SThomas Richter #include "debug.h" 2593115d32SThomas Richter #include "session.h" 2693115d32SThomas Richter #include "evlist.h" 2793115d32SThomas Richter #include "color.h" 2893115d32SThomas Richter #include "sample-raw.h" 2993115d32SThomas Richter #include "s390-cpumcf-kernel.h" 303e4a1c53SThomas Richter #include "pmu-events/pmu-events.h" 3193115d32SThomas Richter 3293115d32SThomas Richter static size_t ctrset_size(struct cf_ctrset_entry *set) 3393115d32SThomas Richter { 3493115d32SThomas Richter return sizeof(*set) + set->ctr * sizeof(u64); 3593115d32SThomas Richter } 3693115d32SThomas Richter 3793115d32SThomas Richter static bool ctrset_valid(struct cf_ctrset_entry *set) 3893115d32SThomas Richter { 3993115d32SThomas Richter return set->def == S390_CPUMCF_DIAG_DEF; 4093115d32SThomas Richter } 4193115d32SThomas Richter 4293115d32SThomas Richter /* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte 4393115d32SThomas Richter * aligned and might have trailing padding bytes. 4493115d32SThomas Richter * Display the raw data on screen. 4593115d32SThomas Richter */ 4693115d32SThomas Richter static bool s390_cpumcfdg_testctr(struct perf_sample *sample) 4793115d32SThomas Richter { 4893115d32SThomas Richter size_t len = sample->raw_size, offset = 0; 4993115d32SThomas Richter unsigned char *buf = sample->raw_data; 5093115d32SThomas Richter struct cf_trailer_entry *te; 5193115d32SThomas Richter struct cf_ctrset_entry *cep, ce; 5293115d32SThomas Richter 5393115d32SThomas Richter if (!len) 5493115d32SThomas Richter return false; 5593115d32SThomas Richter while (offset < len) { 5693115d32SThomas Richter cep = (struct cf_ctrset_entry *)(buf + offset); 5793115d32SThomas Richter ce.def = be16_to_cpu(cep->def); 5893115d32SThomas Richter ce.set = be16_to_cpu(cep->set); 5993115d32SThomas Richter ce.ctr = be16_to_cpu(cep->ctr); 6093115d32SThomas Richter ce.res1 = be16_to_cpu(cep->res1); 6193115d32SThomas Richter 6293115d32SThomas Richter if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) { 6393115d32SThomas Richter /* Raw data for counter sets are always multiple of 8 6493115d32SThomas Richter * bytes. Prepending a 4 bytes size field to the 6593115d32SThomas Richter * raw data block in the sample causes the perf tool 6693115d32SThomas Richter * to append 4 padding bytes to make the raw data part 6793115d32SThomas Richter * of the sample a multiple of eight bytes again. 6893115d32SThomas Richter * 6993115d32SThomas Richter * If the last entry (trailer) is 4 bytes off the raw 7093115d32SThomas Richter * area data end, all is good. 7193115d32SThomas Richter */ 7293115d32SThomas Richter if (len - offset - sizeof(*te) == 4) 7393115d32SThomas Richter break; 7493115d32SThomas Richter pr_err("Invalid counter set entry at %zd\n", offset); 7593115d32SThomas Richter return false; 7693115d32SThomas Richter } 7793115d32SThomas Richter offset += ctrset_size(&ce); 7893115d32SThomas Richter } 7993115d32SThomas Richter return true; 8093115d32SThomas Richter } 8193115d32SThomas Richter 8293115d32SThomas Richter /* Dump event bc000 on screen, already tested on correctness. */ 8393115d32SThomas Richter static void s390_cpumcfdg_dumptrail(const char *color, size_t offset, 8493115d32SThomas Richter struct cf_trailer_entry *tep) 8593115d32SThomas Richter { 8693115d32SThomas Richter struct cf_trailer_entry te; 8793115d32SThomas Richter 8893115d32SThomas Richter te.flags = be64_to_cpu(tep->flags); 8993115d32SThomas Richter te.cfvn = be16_to_cpu(tep->cfvn); 9093115d32SThomas Richter te.csvn = be16_to_cpu(tep->csvn); 9193115d32SThomas Richter te.cpu_speed = be32_to_cpu(tep->cpu_speed); 9293115d32SThomas Richter te.timestamp = be64_to_cpu(tep->timestamp); 9393115d32SThomas Richter te.progusage1 = be64_to_cpu(tep->progusage1); 9493115d32SThomas Richter te.progusage2 = be64_to_cpu(tep->progusage2); 9593115d32SThomas Richter te.progusage3 = be64_to_cpu(tep->progusage3); 9693115d32SThomas Richter te.tod_base = be64_to_cpu(tep->tod_base); 9793115d32SThomas Richter te.mach_type = be16_to_cpu(tep->mach_type); 9893115d32SThomas Richter te.res1 = be16_to_cpu(tep->res1); 9993115d32SThomas Richter te.res2 = be32_to_cpu(tep->res2); 10093115d32SThomas Richter 10193115d32SThomas Richter color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c" 10293115d32SThomas Richter " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n", 10393115d32SThomas Richter offset, te.clock_base ? 'T' : ' ', 10493115d32SThomas Richter te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ', 10593115d32SThomas Richter te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ', 10693115d32SThomas Richter te.cfvn, te.csvn, te.cpu_speed, te.timestamp); 10793115d32SThomas Richter color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx" 10893115d32SThomas Richter " Type:%x\n\n", 10993115d32SThomas Richter te.progusage1, te.progusage2, te.progusage3, 11093115d32SThomas Richter te.tod_base, te.mach_type); 11193115d32SThomas Richter } 11293115d32SThomas Richter 1133e4a1c53SThomas Richter /* Return starting number of a counter set */ 1143e4a1c53SThomas Richter static int get_counterset_start(int setnr) 1153e4a1c53SThomas Richter { 1163e4a1c53SThomas Richter switch (setnr) { 1173e4a1c53SThomas Richter case CPUMF_CTR_SET_BASIC: /* Basic counter set */ 1183e4a1c53SThomas Richter return 0; 1193e4a1c53SThomas Richter case CPUMF_CTR_SET_USER: /* Problem state counter set */ 1203e4a1c53SThomas Richter return 32; 1213e4a1c53SThomas Richter case CPUMF_CTR_SET_CRYPTO: /* Crypto counter set */ 1223e4a1c53SThomas Richter return 64; 1233e4a1c53SThomas Richter case CPUMF_CTR_SET_EXT: /* Extended counter set */ 1243e4a1c53SThomas Richter return 128; 1253e4a1c53SThomas Richter case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */ 1263e4a1c53SThomas Richter return 448; 1273e4a1c53SThomas Richter default: 1283e4a1c53SThomas Richter return -1; 1293e4a1c53SThomas Richter } 1303e4a1c53SThomas Richter } 1313e4a1c53SThomas Richter 1323e4a1c53SThomas Richter /* Scan the PMU table and extract the logical name of a counter from the 1333e4a1c53SThomas Richter * PMU events table. Input is the counter set and counter number with in the 1343e4a1c53SThomas Richter * set. Construct the event number and use this as key. If they match return 1353e4a1c53SThomas Richter * the name of this counter. 1363e4a1c53SThomas Richter * If no match is found a NULL pointer is returned. 1373e4a1c53SThomas Richter */ 1383e4a1c53SThomas Richter static const char *get_counter_name(int set, int nr, struct pmu_events_map *map) 1393e4a1c53SThomas Richter { 1403e4a1c53SThomas Richter int rc, event_nr, wanted = get_counterset_start(set) + nr; 1413e4a1c53SThomas Richter 1423e4a1c53SThomas Richter if (map) { 1433e4a1c53SThomas Richter struct pmu_event *evp = map->table; 1443e4a1c53SThomas Richter 1453e4a1c53SThomas Richter for (; evp->name || evp->event || evp->desc; ++evp) { 1463e4a1c53SThomas Richter if (evp->name == NULL || evp->event == NULL) 1473e4a1c53SThomas Richter continue; 1483e4a1c53SThomas Richter rc = sscanf(evp->event, "event=%x", &event_nr); 1493e4a1c53SThomas Richter if (rc == 1 && event_nr == wanted) 1503e4a1c53SThomas Richter return evp->name; 1513e4a1c53SThomas Richter } 1523e4a1c53SThomas Richter } 1533e4a1c53SThomas Richter return NULL; 1543e4a1c53SThomas Richter } 1553e4a1c53SThomas Richter 15693115d32SThomas Richter static void s390_cpumcfdg_dump(struct perf_sample *sample) 15793115d32SThomas Richter { 15893115d32SThomas Richter size_t i, len = sample->raw_size, offset = 0; 15993115d32SThomas Richter unsigned char *buf = sample->raw_data; 16093115d32SThomas Richter const char *color = PERF_COLOR_BLUE; 16193115d32SThomas Richter struct cf_ctrset_entry *cep, ce; 1623e4a1c53SThomas Richter struct pmu_events_map *map; 1633e4a1c53SThomas Richter struct perf_pmu pmu; 16493115d32SThomas Richter u64 *p; 16593115d32SThomas Richter 1663e4a1c53SThomas Richter memset(&pmu, 0, sizeof(pmu)); 1673e4a1c53SThomas Richter map = perf_pmu__find_map(&pmu); 16893115d32SThomas Richter while (offset < len) { 16993115d32SThomas Richter cep = (struct cf_ctrset_entry *)(buf + offset); 17093115d32SThomas Richter 17193115d32SThomas Richter ce.def = be16_to_cpu(cep->def); 17293115d32SThomas Richter ce.set = be16_to_cpu(cep->set); 17393115d32SThomas Richter ce.ctr = be16_to_cpu(cep->ctr); 17493115d32SThomas Richter ce.res1 = be16_to_cpu(cep->res1); 17593115d32SThomas Richter 17693115d32SThomas Richter if (!ctrset_valid(&ce)) { /* Print trailer */ 17793115d32SThomas Richter s390_cpumcfdg_dumptrail(color, offset, 17893115d32SThomas Richter (struct cf_trailer_entry *)cep); 17993115d32SThomas Richter return; 18093115d32SThomas Richter } 18193115d32SThomas Richter 18293115d32SThomas Richter color_fprintf(stdout, color, " [%#08zx] Counterset:%d" 18393115d32SThomas Richter " Counters:%d\n", offset, ce.set, ce.ctr); 1843e4a1c53SThomas Richter for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) { 1853e4a1c53SThomas Richter const char *ev_name = get_counter_name(ce.set, i, map); 1863e4a1c53SThomas Richter 18793115d32SThomas Richter color_fprintf(stdout, color, 1883e4a1c53SThomas Richter "\tCounter:%03d %s Value:%#018lx\n", i, 1893e4a1c53SThomas Richter ev_name ?: "<unknown>", be64_to_cpu(*p)); 1903e4a1c53SThomas Richter } 19193115d32SThomas Richter offset += ctrset_size(&ce); 19293115d32SThomas Richter } 19393115d32SThomas Richter } 19493115d32SThomas Richter 19593115d32SThomas Richter /* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events 19693115d32SThomas Richter * and if the event was triggered by a counter set diagnostic event display 19793115d32SThomas Richter * its raw data. 19893115d32SThomas Richter * The function is only invoked when the dump flag -D is set. 19993115d32SThomas Richter */ 200*44d2a557SArnaldo Carvalho de Melo void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) 20193115d32SThomas Richter { 20232dcd021SJiri Olsa struct evsel *ev_bc000; 20393115d32SThomas Richter 20493115d32SThomas Richter if (event->header.type != PERF_RECORD_SAMPLE) 20593115d32SThomas Richter return; 20693115d32SThomas Richter 2073ccf8a7bSArnaldo Carvalho de Melo ev_bc000 = evlist__event2evsel(evlist, event); 20893115d32SThomas Richter if (ev_bc000 == NULL || 2091fc632ceSJiri Olsa ev_bc000->core.attr.config != PERF_EVENT_CPUM_CF_DIAG) 21093115d32SThomas Richter return; 21193115d32SThomas Richter 21293115d32SThomas Richter /* Display raw data on screen */ 21393115d32SThomas Richter if (!s390_cpumcfdg_testctr(sample)) { 21493115d32SThomas Richter pr_err("Invalid counter set data encountered\n"); 21593115d32SThomas Richter return; 21693115d32SThomas Richter } 21793115d32SThomas Richter s390_cpumcfdg_dump(sample); 21893115d32SThomas Richter } 219