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" 30c4ac7f75SIan Rogers #include "util/pmu.h" 319823147dSArnaldo Carvalho de Melo #include "util/sample.h" 3293115d32SThomas Richter 3393115d32SThomas Richter static size_t ctrset_size(struct cf_ctrset_entry *set) 3493115d32SThomas Richter { 3593115d32SThomas Richter return sizeof(*set) + set->ctr * sizeof(u64); 3693115d32SThomas Richter } 3793115d32SThomas Richter 3893115d32SThomas Richter static bool ctrset_valid(struct cf_ctrset_entry *set) 3993115d32SThomas Richter { 4093115d32SThomas Richter return set->def == S390_CPUMCF_DIAG_DEF; 4193115d32SThomas Richter } 4293115d32SThomas Richter 4393115d32SThomas Richter /* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte 4493115d32SThomas Richter * aligned and might have trailing padding bytes. 4593115d32SThomas Richter * Display the raw data on screen. 4693115d32SThomas Richter */ 4793115d32SThomas Richter static bool s390_cpumcfdg_testctr(struct perf_sample *sample) 4893115d32SThomas Richter { 4993115d32SThomas Richter size_t len = sample->raw_size, offset = 0; 5093115d32SThomas Richter unsigned char *buf = sample->raw_data; 5193115d32SThomas Richter struct cf_trailer_entry *te; 5293115d32SThomas Richter struct cf_ctrset_entry *cep, ce; 5393115d32SThomas Richter 5493115d32SThomas Richter if (!len) 5593115d32SThomas Richter return false; 5693115d32SThomas Richter while (offset < len) { 5793115d32SThomas Richter cep = (struct cf_ctrset_entry *)(buf + offset); 5893115d32SThomas Richter ce.def = be16_to_cpu(cep->def); 5993115d32SThomas Richter ce.set = be16_to_cpu(cep->set); 6093115d32SThomas Richter ce.ctr = be16_to_cpu(cep->ctr); 6193115d32SThomas Richter ce.res1 = be16_to_cpu(cep->res1); 6293115d32SThomas Richter 6393115d32SThomas Richter if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) { 6493115d32SThomas Richter /* Raw data for counter sets are always multiple of 8 6593115d32SThomas Richter * bytes. Prepending a 4 bytes size field to the 6693115d32SThomas Richter * raw data block in the sample causes the perf tool 6793115d32SThomas Richter * to append 4 padding bytes to make the raw data part 6893115d32SThomas Richter * of the sample a multiple of eight bytes again. 6993115d32SThomas Richter * 7093115d32SThomas Richter * If the last entry (trailer) is 4 bytes off the raw 7193115d32SThomas Richter * area data end, all is good. 7293115d32SThomas Richter */ 7393115d32SThomas Richter if (len - offset - sizeof(*te) == 4) 7493115d32SThomas Richter break; 7593115d32SThomas Richter pr_err("Invalid counter set entry at %zd\n", offset); 7693115d32SThomas Richter return false; 7793115d32SThomas Richter } 7893115d32SThomas Richter offset += ctrset_size(&ce); 7993115d32SThomas Richter } 8093115d32SThomas Richter return true; 8193115d32SThomas Richter } 8293115d32SThomas Richter 8393115d32SThomas Richter /* Dump event bc000 on screen, already tested on correctness. */ 8493115d32SThomas Richter static void s390_cpumcfdg_dumptrail(const char *color, size_t offset, 8593115d32SThomas Richter struct cf_trailer_entry *tep) 8693115d32SThomas Richter { 8793115d32SThomas Richter struct cf_trailer_entry te; 8893115d32SThomas Richter 8993115d32SThomas Richter te.flags = be64_to_cpu(tep->flags); 9093115d32SThomas Richter te.cfvn = be16_to_cpu(tep->cfvn); 9193115d32SThomas Richter te.csvn = be16_to_cpu(tep->csvn); 9293115d32SThomas Richter te.cpu_speed = be32_to_cpu(tep->cpu_speed); 9393115d32SThomas Richter te.timestamp = be64_to_cpu(tep->timestamp); 9493115d32SThomas Richter te.progusage1 = be64_to_cpu(tep->progusage1); 9593115d32SThomas Richter te.progusage2 = be64_to_cpu(tep->progusage2); 9693115d32SThomas Richter te.progusage3 = be64_to_cpu(tep->progusage3); 9793115d32SThomas Richter te.tod_base = be64_to_cpu(tep->tod_base); 9893115d32SThomas Richter te.mach_type = be16_to_cpu(tep->mach_type); 9993115d32SThomas Richter te.res1 = be16_to_cpu(tep->res1); 10093115d32SThomas Richter te.res2 = be32_to_cpu(tep->res2); 10193115d32SThomas Richter 10293115d32SThomas Richter color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c" 10393115d32SThomas Richter " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n", 10493115d32SThomas Richter offset, te.clock_base ? 'T' : ' ', 10593115d32SThomas Richter te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ', 10693115d32SThomas Richter te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ', 10793115d32SThomas Richter te.cfvn, te.csvn, te.cpu_speed, te.timestamp); 10893115d32SThomas Richter color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx" 10993115d32SThomas Richter " Type:%x\n\n", 11093115d32SThomas Richter te.progusage1, te.progusage2, te.progusage3, 11193115d32SThomas Richter te.tod_base, te.mach_type); 11293115d32SThomas Richter } 11393115d32SThomas Richter 1143e4a1c53SThomas Richter /* Return starting number of a counter set */ 1153e4a1c53SThomas Richter static int get_counterset_start(int setnr) 1163e4a1c53SThomas Richter { 1173e4a1c53SThomas Richter switch (setnr) { 1183e4a1c53SThomas Richter case CPUMF_CTR_SET_BASIC: /* Basic counter set */ 1193e4a1c53SThomas Richter return 0; 1203e4a1c53SThomas Richter case CPUMF_CTR_SET_USER: /* Problem state counter set */ 1213e4a1c53SThomas Richter return 32; 1223e4a1c53SThomas Richter case CPUMF_CTR_SET_CRYPTO: /* Crypto counter set */ 1233e4a1c53SThomas Richter return 64; 1243e4a1c53SThomas Richter case CPUMF_CTR_SET_EXT: /* Extended counter set */ 1253e4a1c53SThomas Richter return 128; 1263e4a1c53SThomas Richter case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */ 1273e4a1c53SThomas Richter return 448; 1283e4a1c53SThomas Richter default: 1293e4a1c53SThomas Richter return -1; 1303e4a1c53SThomas Richter } 1313e4a1c53SThomas Richter } 1323e4a1c53SThomas Richter 133660842e4SIan Rogers struct get_counter_name_data { 134660842e4SIan Rogers int wanted; 135c4ac7f75SIan Rogers char *result; 136660842e4SIan Rogers }; 137660842e4SIan Rogers 138c4ac7f75SIan Rogers static int get_counter_name_callback(void *vdata, struct pmu_event_info *info) 139660842e4SIan Rogers { 140660842e4SIan Rogers struct get_counter_name_data *data = vdata; 141660842e4SIan Rogers int rc, event_nr; 142c4ac7f75SIan Rogers const char *event_str; 143660842e4SIan Rogers 144c4ac7f75SIan Rogers if (info->str == NULL) 145660842e4SIan Rogers return 0; 146c4ac7f75SIan Rogers 147c4ac7f75SIan Rogers event_str = strstr(info->str, "event="); 148c4ac7f75SIan Rogers if (!event_str) 149c4ac7f75SIan Rogers return 0; 150c4ac7f75SIan Rogers 151c4ac7f75SIan Rogers rc = sscanf(event_str, "event=%x", &event_nr); 152660842e4SIan Rogers if (rc == 1 && event_nr == data->wanted) { 153c4ac7f75SIan Rogers data->result = strdup(info->name); 154660842e4SIan Rogers return 1; /* Terminate the search. */ 155660842e4SIan Rogers } 156660842e4SIan Rogers return 0; 157660842e4SIan Rogers } 158660842e4SIan Rogers 159c4ac7f75SIan Rogers /* Scan the PMU and extract the logical name of a counter from the event. Input 160c4ac7f75SIan Rogers * is the counter set and counter number with in the set. Construct the event 161c4ac7f75SIan Rogers * number and use this as key. If they match return the name of this counter. 1623e4a1c53SThomas Richter * If no match is found a NULL pointer is returned. 1633e4a1c53SThomas Richter */ 164c4ac7f75SIan Rogers static char *get_counter_name(int set, int nr, struct perf_pmu *pmu) 1653e4a1c53SThomas Richter { 166660842e4SIan Rogers struct get_counter_name_data data = { 167660842e4SIan Rogers .wanted = get_counterset_start(set) + nr, 168660842e4SIan Rogers .result = NULL, 169660842e4SIan Rogers }; 1703e4a1c53SThomas Richter 171c4ac7f75SIan Rogers if (!pmu) 1723e4a1c53SThomas Richter return NULL; 173660842e4SIan Rogers 174*cd4e1efbSIan Rogers perf_pmu__for_each_event(pmu, /*skip_duplicate_pmus=*/ true, 175*cd4e1efbSIan Rogers &data, get_counter_name_callback); 176660842e4SIan Rogers return data.result; 1773e4a1c53SThomas Richter } 1783e4a1c53SThomas Richter 179c4ac7f75SIan Rogers static void s390_cpumcfdg_dump(struct perf_pmu *pmu, struct perf_sample *sample) 18093115d32SThomas Richter { 18193115d32SThomas Richter size_t i, len = sample->raw_size, offset = 0; 18293115d32SThomas Richter unsigned char *buf = sample->raw_data; 18393115d32SThomas Richter const char *color = PERF_COLOR_BLUE; 18493115d32SThomas Richter struct cf_ctrset_entry *cep, ce; 18593115d32SThomas Richter u64 *p; 18693115d32SThomas Richter 18793115d32SThomas Richter while (offset < len) { 18893115d32SThomas Richter cep = (struct cf_ctrset_entry *)(buf + offset); 18993115d32SThomas Richter 19093115d32SThomas Richter ce.def = be16_to_cpu(cep->def); 19193115d32SThomas Richter ce.set = be16_to_cpu(cep->set); 19293115d32SThomas Richter ce.ctr = be16_to_cpu(cep->ctr); 19393115d32SThomas Richter ce.res1 = be16_to_cpu(cep->res1); 19493115d32SThomas Richter 19593115d32SThomas Richter if (!ctrset_valid(&ce)) { /* Print trailer */ 19693115d32SThomas Richter s390_cpumcfdg_dumptrail(color, offset, 19793115d32SThomas Richter (struct cf_trailer_entry *)cep); 19893115d32SThomas Richter return; 19993115d32SThomas Richter } 20093115d32SThomas Richter 20193115d32SThomas Richter color_fprintf(stdout, color, " [%#08zx] Counterset:%d" 20293115d32SThomas Richter " Counters:%d\n", offset, ce.set, ce.ctr); 2033e4a1c53SThomas Richter for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) { 204c4ac7f75SIan Rogers char *ev_name = get_counter_name(ce.set, i, pmu); 2053e4a1c53SThomas Richter 20693115d32SThomas Richter color_fprintf(stdout, color, 2073e4a1c53SThomas Richter "\tCounter:%03d %s Value:%#018lx\n", i, 2083e4a1c53SThomas Richter ev_name ?: "<unknown>", be64_to_cpu(*p)); 209c4ac7f75SIan Rogers free(ev_name); 2103e4a1c53SThomas Richter } 21193115d32SThomas Richter offset += ctrset_size(&ce); 21293115d32SThomas Richter } 21393115d32SThomas Richter } 21493115d32SThomas Richter 21593115d32SThomas Richter /* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events 21693115d32SThomas Richter * and if the event was triggered by a counter set diagnostic event display 21793115d32SThomas Richter * its raw data. 21893115d32SThomas Richter * The function is only invoked when the dump flag -D is set. 21993115d32SThomas Richter */ 22044d2a557SArnaldo Carvalho de Melo void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) 22193115d32SThomas Richter { 222c4ac7f75SIan Rogers struct evsel *evsel; 22393115d32SThomas Richter 22493115d32SThomas Richter if (event->header.type != PERF_RECORD_SAMPLE) 22593115d32SThomas Richter return; 22693115d32SThomas Richter 227c4ac7f75SIan Rogers evsel = evlist__event2evsel(evlist, event); 228c4ac7f75SIan Rogers if (evsel == NULL || 229c4ac7f75SIan Rogers evsel->core.attr.config != PERF_EVENT_CPUM_CF_DIAG) 23093115d32SThomas Richter return; 23193115d32SThomas Richter 23293115d32SThomas Richter /* Display raw data on screen */ 23393115d32SThomas Richter if (!s390_cpumcfdg_testctr(sample)) { 23493115d32SThomas Richter pr_err("Invalid counter set data encountered\n"); 23593115d32SThomas Richter return; 23693115d32SThomas Richter } 237c4ac7f75SIan Rogers s390_cpumcfdg_dump(evsel->pmu, sample); 23893115d32SThomas Richter } 239