162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * perf iostat 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020, Intel Corporation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: Alexander Antonov <alexander.antonov@linux.intel.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <api/fs/fs.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/zalloc.h> 1462306a36Sopenharmony_ci#include <limits.h> 1562306a36Sopenharmony_ci#include <stdio.h> 1662306a36Sopenharmony_ci#include <string.h> 1762306a36Sopenharmony_ci#include <errno.h> 1862306a36Sopenharmony_ci#include <sys/types.h> 1962306a36Sopenharmony_ci#include <sys/stat.h> 2062306a36Sopenharmony_ci#include <fcntl.h> 2162306a36Sopenharmony_ci#include <dirent.h> 2262306a36Sopenharmony_ci#include <unistd.h> 2362306a36Sopenharmony_ci#include <stdlib.h> 2462306a36Sopenharmony_ci#include <regex.h> 2562306a36Sopenharmony_ci#include "util/cpumap.h" 2662306a36Sopenharmony_ci#include "util/debug.h" 2762306a36Sopenharmony_ci#include "util/iostat.h" 2862306a36Sopenharmony_ci#include "util/counts.h" 2962306a36Sopenharmony_ci#include "path.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#ifndef MAX_PATH 3262306a36Sopenharmony_ci#define MAX_PATH 1024 3362306a36Sopenharmony_ci#endif 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define UNCORE_IIO_PMU_PATH "devices/uncore_iio_%d" 3662306a36Sopenharmony_ci#define SYSFS_UNCORE_PMU_PATH "%s/"UNCORE_IIO_PMU_PATH 3762306a36Sopenharmony_ci#define PLATFORM_MAPPING_PATH UNCORE_IIO_PMU_PATH"/die%d" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Each metric requiries one IIO event which increments at every 4B transfer 4162306a36Sopenharmony_ci * in corresponding direction. The formulas to compute metrics are generic: 4262306a36Sopenharmony_ci * #EventCount * 4B / (1024 * 1024) 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic const char * const iostat_metrics[] = { 4562306a36Sopenharmony_ci "Inbound Read(MB)", 4662306a36Sopenharmony_ci "Inbound Write(MB)", 4762306a36Sopenharmony_ci "Outbound Read(MB)", 4862306a36Sopenharmony_ci "Outbound Write(MB)", 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic inline int iostat_metrics_count(void) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci return sizeof(iostat_metrics) / sizeof(char *); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic const char *iostat_metric_by_idx(int idx) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci return *(iostat_metrics + idx % iostat_metrics_count()); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct iio_root_port { 6262306a36Sopenharmony_ci u32 domain; 6362306a36Sopenharmony_ci u8 bus; 6462306a36Sopenharmony_ci u8 die; 6562306a36Sopenharmony_ci u8 pmu_idx; 6662306a36Sopenharmony_ci int idx; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistruct iio_root_ports_list { 7062306a36Sopenharmony_ci struct iio_root_port **rps; 7162306a36Sopenharmony_ci int nr_entries; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct iio_root_ports_list *root_ports; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic void iio_root_port_show(FILE *output, 7762306a36Sopenharmony_ci const struct iio_root_port * const rp) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci if (output && rp) 8062306a36Sopenharmony_ci fprintf(output, "S%d-uncore_iio_%d<%04x:%02x>\n", 8162306a36Sopenharmony_ci rp->die, rp->pmu_idx, rp->domain, rp->bus); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic struct iio_root_port *iio_root_port_new(u32 domain, u8 bus, 8562306a36Sopenharmony_ci u8 die, u8 pmu_idx) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct iio_root_port *p = calloc(1, sizeof(*p)); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (p) { 9062306a36Sopenharmony_ci p->domain = domain; 9162306a36Sopenharmony_ci p->bus = bus; 9262306a36Sopenharmony_ci p->die = die; 9362306a36Sopenharmony_ci p->pmu_idx = pmu_idx; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci return p; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void iio_root_ports_list_free(struct iio_root_ports_list *list) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int idx; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (list) { 10362306a36Sopenharmony_ci for (idx = 0; idx < list->nr_entries; idx++) 10462306a36Sopenharmony_ci zfree(&list->rps[idx]); 10562306a36Sopenharmony_ci zfree(&list->rps); 10662306a36Sopenharmony_ci free(list); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct iio_root_port *iio_root_port_find_by_notation( 11162306a36Sopenharmony_ci const struct iio_root_ports_list * const list, u32 domain, u8 bus) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int idx; 11462306a36Sopenharmony_ci struct iio_root_port *rp; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (list) { 11762306a36Sopenharmony_ci for (idx = 0; idx < list->nr_entries; idx++) { 11862306a36Sopenharmony_ci rp = list->rps[idx]; 11962306a36Sopenharmony_ci if (rp && rp->domain == domain && rp->bus == bus) 12062306a36Sopenharmony_ci return rp; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci return NULL; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int iio_root_ports_list_insert(struct iio_root_ports_list *list, 12762306a36Sopenharmony_ci struct iio_root_port * const rp) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct iio_root_port **tmp_buf; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (list && rp) { 13262306a36Sopenharmony_ci rp->idx = list->nr_entries++; 13362306a36Sopenharmony_ci tmp_buf = realloc(list->rps, 13462306a36Sopenharmony_ci list->nr_entries * sizeof(*list->rps)); 13562306a36Sopenharmony_ci if (!tmp_buf) { 13662306a36Sopenharmony_ci pr_err("Failed to realloc memory\n"); 13762306a36Sopenharmony_ci return -ENOMEM; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci tmp_buf[rp->idx] = rp; 14062306a36Sopenharmony_ci list->rps = tmp_buf; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int iio_mapping(u8 pmu_idx, struct iio_root_ports_list * const list) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci char *buf; 14862306a36Sopenharmony_ci char path[MAX_PATH]; 14962306a36Sopenharmony_ci u32 domain; 15062306a36Sopenharmony_ci u8 bus; 15162306a36Sopenharmony_ci struct iio_root_port *rp; 15262306a36Sopenharmony_ci size_t size; 15362306a36Sopenharmony_ci int ret; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci for (int die = 0; die < cpu__max_node(); die++) { 15662306a36Sopenharmony_ci scnprintf(path, MAX_PATH, PLATFORM_MAPPING_PATH, pmu_idx, die); 15762306a36Sopenharmony_ci if (sysfs__read_str(path, &buf, &size) < 0) { 15862306a36Sopenharmony_ci if (pmu_idx) 15962306a36Sopenharmony_ci goto out; 16062306a36Sopenharmony_ci pr_err("Mode iostat is not supported\n"); 16162306a36Sopenharmony_ci return -1; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci ret = sscanf(buf, "%04x:%02hhx", &domain, &bus); 16462306a36Sopenharmony_ci free(buf); 16562306a36Sopenharmony_ci if (ret != 2) { 16662306a36Sopenharmony_ci pr_err("Invalid mapping data: iio_%d; die%d\n", 16762306a36Sopenharmony_ci pmu_idx, die); 16862306a36Sopenharmony_ci return -1; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci rp = iio_root_port_new(domain, bus, die, pmu_idx); 17162306a36Sopenharmony_ci if (!rp || iio_root_ports_list_insert(list, rp)) { 17262306a36Sopenharmony_ci free(rp); 17362306a36Sopenharmony_ci return -ENOMEM; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ciout: 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic u8 iio_pmu_count(void) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci u8 pmu_idx = 0; 18362306a36Sopenharmony_ci char path[MAX_PATH]; 18462306a36Sopenharmony_ci const char *sysfs = sysfs__mountpoint(); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (sysfs) { 18762306a36Sopenharmony_ci for (;; pmu_idx++) { 18862306a36Sopenharmony_ci snprintf(path, sizeof(path), SYSFS_UNCORE_PMU_PATH, 18962306a36Sopenharmony_ci sysfs, pmu_idx); 19062306a36Sopenharmony_ci if (access(path, F_OK) != 0) 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci return pmu_idx; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int iio_root_ports_scan(struct iio_root_ports_list **list) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci int ret = -ENOMEM; 20062306a36Sopenharmony_ci struct iio_root_ports_list *tmp_list; 20162306a36Sopenharmony_ci u8 pmu_count = iio_pmu_count(); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (!pmu_count) { 20462306a36Sopenharmony_ci pr_err("Unsupported uncore pmu configuration\n"); 20562306a36Sopenharmony_ci return -1; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci tmp_list = calloc(1, sizeof(*tmp_list)); 20962306a36Sopenharmony_ci if (!tmp_list) 21062306a36Sopenharmony_ci goto err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (u8 pmu_idx = 0; pmu_idx < pmu_count; pmu_idx++) { 21362306a36Sopenharmony_ci ret = iio_mapping(pmu_idx, tmp_list); 21462306a36Sopenharmony_ci if (ret) 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_cierr: 21862306a36Sopenharmony_ci if (!ret) 21962306a36Sopenharmony_ci *list = tmp_list; 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci iio_root_ports_list_free(tmp_list); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return ret; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int iio_root_port_parse_str(u32 *domain, u8 *bus, char *str) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int ret; 22962306a36Sopenharmony_ci regex_t regex; 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * Expected format domain:bus: 23262306a36Sopenharmony_ci * Valid domain range [0:ffff] 23362306a36Sopenharmony_ci * Valid bus range [0:ff] 23462306a36Sopenharmony_ci * Example: 0000:af, 0:3d, 01:7 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci regcomp(®ex, "^([a-f0-9A-F]{1,}):([a-f0-9A-F]{1,2})", REG_EXTENDED); 23762306a36Sopenharmony_ci ret = regexec(®ex, str, 0, NULL, 0); 23862306a36Sopenharmony_ci if (ret || sscanf(str, "%08x:%02hhx", domain, bus) != 2) 23962306a36Sopenharmony_ci pr_warning("Unrecognized root port format: %s\n" 24062306a36Sopenharmony_ci "Please use the following format:\n" 24162306a36Sopenharmony_ci "\t [domain]:[bus]\n" 24262306a36Sopenharmony_ci "\t for example: 0000:3d\n", str); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci regfree(®ex); 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int iio_root_ports_list_filter(struct iio_root_ports_list **list, 24962306a36Sopenharmony_ci const char *filter) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci char *tok, *tmp, *filter_copy = NULL; 25262306a36Sopenharmony_ci struct iio_root_port *rp; 25362306a36Sopenharmony_ci u32 domain; 25462306a36Sopenharmony_ci u8 bus; 25562306a36Sopenharmony_ci int ret = -ENOMEM; 25662306a36Sopenharmony_ci struct iio_root_ports_list *tmp_list = calloc(1, sizeof(*tmp_list)); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!tmp_list) 25962306a36Sopenharmony_ci goto err; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci filter_copy = strdup(filter); 26262306a36Sopenharmony_ci if (!filter_copy) 26362306a36Sopenharmony_ci goto err; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci for (tok = strtok_r(filter_copy, ",", &tmp); tok; 26662306a36Sopenharmony_ci tok = strtok_r(NULL, ",", &tmp)) { 26762306a36Sopenharmony_ci if (!iio_root_port_parse_str(&domain, &bus, tok)) { 26862306a36Sopenharmony_ci rp = iio_root_port_find_by_notation(*list, domain, bus); 26962306a36Sopenharmony_ci if (rp) { 27062306a36Sopenharmony_ci (*list)->rps[rp->idx] = NULL; 27162306a36Sopenharmony_ci ret = iio_root_ports_list_insert(tmp_list, rp); 27262306a36Sopenharmony_ci if (ret) { 27362306a36Sopenharmony_ci free(rp); 27462306a36Sopenharmony_ci goto err; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } else if (!iio_root_port_find_by_notation(tmp_list, 27762306a36Sopenharmony_ci domain, bus)) 27862306a36Sopenharmony_ci pr_warning("Root port %04x:%02x were not found\n", 27962306a36Sopenharmony_ci domain, bus); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (tmp_list->nr_entries == 0) { 28462306a36Sopenharmony_ci pr_err("Requested root ports were not found\n"); 28562306a36Sopenharmony_ci ret = -EINVAL; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_cierr: 28862306a36Sopenharmony_ci iio_root_ports_list_free(*list); 28962306a36Sopenharmony_ci if (ret) 29062306a36Sopenharmony_ci iio_root_ports_list_free(tmp_list); 29162306a36Sopenharmony_ci else 29262306a36Sopenharmony_ci *list = tmp_list; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci free(filter_copy); 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int iostat_event_group(struct evlist *evl, 29962306a36Sopenharmony_ci struct iio_root_ports_list *list) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci int ret; 30262306a36Sopenharmony_ci int idx; 30362306a36Sopenharmony_ci const char *iostat_cmd_template = 30462306a36Sopenharmony_ci "{uncore_iio_%x/event=0x83,umask=0x04,ch_mask=0xF,fc_mask=0x07/,\ 30562306a36Sopenharmony_ci uncore_iio_%x/event=0x83,umask=0x01,ch_mask=0xF,fc_mask=0x07/,\ 30662306a36Sopenharmony_ci uncore_iio_%x/event=0xc0,umask=0x04,ch_mask=0xF,fc_mask=0x07/,\ 30762306a36Sopenharmony_ci uncore_iio_%x/event=0xc0,umask=0x01,ch_mask=0xF,fc_mask=0x07/}"; 30862306a36Sopenharmony_ci const int len_template = strlen(iostat_cmd_template) + 1; 30962306a36Sopenharmony_ci struct evsel *evsel = NULL; 31062306a36Sopenharmony_ci int metrics_count = iostat_metrics_count(); 31162306a36Sopenharmony_ci char *iostat_cmd = calloc(len_template, 1); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (!iostat_cmd) 31462306a36Sopenharmony_ci return -ENOMEM; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci for (idx = 0; idx < list->nr_entries; idx++) { 31762306a36Sopenharmony_ci sprintf(iostat_cmd, iostat_cmd_template, 31862306a36Sopenharmony_ci list->rps[idx]->pmu_idx, list->rps[idx]->pmu_idx, 31962306a36Sopenharmony_ci list->rps[idx]->pmu_idx, list->rps[idx]->pmu_idx); 32062306a36Sopenharmony_ci ret = parse_event(evl, iostat_cmd); 32162306a36Sopenharmony_ci if (ret) 32262306a36Sopenharmony_ci goto err; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci evlist__for_each_entry(evl, evsel) { 32662306a36Sopenharmony_ci evsel->priv = list->rps[evsel->core.idx / metrics_count]; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci list->nr_entries = 0; 32962306a36Sopenharmony_cierr: 33062306a36Sopenharmony_ci iio_root_ports_list_free(list); 33162306a36Sopenharmony_ci free(iostat_cmd); 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciint iostat_prepare(struct evlist *evlist, struct perf_stat_config *config) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci if (evlist->core.nr_entries > 0) { 33862306a36Sopenharmony_ci pr_warning("The -e and -M options are not supported." 33962306a36Sopenharmony_ci "All chosen events/metrics will be dropped\n"); 34062306a36Sopenharmony_ci evlist__delete(evlist); 34162306a36Sopenharmony_ci evlist = evlist__new(); 34262306a36Sopenharmony_ci if (!evlist) 34362306a36Sopenharmony_ci return -ENOMEM; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci config->metric_only = true; 34762306a36Sopenharmony_ci config->aggr_mode = AGGR_GLOBAL; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return iostat_event_group(evlist, root_ports); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciint iostat_parse(const struct option *opt, const char *str, 35362306a36Sopenharmony_ci int unset __maybe_unused) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci int ret; 35662306a36Sopenharmony_ci struct perf_stat_config *config = (struct perf_stat_config *)opt->data; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ret = iio_root_ports_scan(&root_ports); 35962306a36Sopenharmony_ci if (!ret) { 36062306a36Sopenharmony_ci config->iostat_run = true; 36162306a36Sopenharmony_ci if (!str) 36262306a36Sopenharmony_ci iostat_mode = IOSTAT_RUN; 36362306a36Sopenharmony_ci else if (!strcmp(str, "list")) 36462306a36Sopenharmony_ci iostat_mode = IOSTAT_LIST; 36562306a36Sopenharmony_ci else { 36662306a36Sopenharmony_ci iostat_mode = IOSTAT_RUN; 36762306a36Sopenharmony_ci ret = iio_root_ports_list_filter(&root_ports, str); 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci return ret; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_civoid iostat_list(struct evlist *evlist, struct perf_stat_config *config) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct evsel *evsel; 37662306a36Sopenharmony_ci struct iio_root_port *rp = NULL; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 37962306a36Sopenharmony_ci if (rp != evsel->priv) { 38062306a36Sopenharmony_ci rp = evsel->priv; 38162306a36Sopenharmony_ci iio_root_port_show(config->output, rp); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_civoid iostat_release(struct evlist *evlist) 38762306a36Sopenharmony_ci{ 38862306a36Sopenharmony_ci struct evsel *evsel; 38962306a36Sopenharmony_ci struct iio_root_port *rp = NULL; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 39262306a36Sopenharmony_ci if (rp != evsel->priv) { 39362306a36Sopenharmony_ci rp = evsel->priv; 39462306a36Sopenharmony_ci zfree(&evsel->priv); 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_civoid iostat_prefix(struct evlist *evlist, 40062306a36Sopenharmony_ci struct perf_stat_config *config, 40162306a36Sopenharmony_ci char *prefix, struct timespec *ts) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct iio_root_port *rp = evlist->selected->priv; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (rp) { 40662306a36Sopenharmony_ci if (ts) 40762306a36Sopenharmony_ci sprintf(prefix, "%6lu.%09lu%s%04x:%02x%s", 40862306a36Sopenharmony_ci ts->tv_sec, ts->tv_nsec, 40962306a36Sopenharmony_ci config->csv_sep, rp->domain, rp->bus, 41062306a36Sopenharmony_ci config->csv_sep); 41162306a36Sopenharmony_ci else 41262306a36Sopenharmony_ci sprintf(prefix, "%04x:%02x%s", rp->domain, rp->bus, 41362306a36Sopenharmony_ci config->csv_sep); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_civoid iostat_print_header_prefix(struct perf_stat_config *config) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci if (config->csv_output) 42062306a36Sopenharmony_ci fputs("port,", config->output); 42162306a36Sopenharmony_ci else if (config->interval) 42262306a36Sopenharmony_ci fprintf(config->output, "# time port "); 42362306a36Sopenharmony_ci else 42462306a36Sopenharmony_ci fprintf(config->output, " port "); 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_civoid iostat_print_metric(struct perf_stat_config *config, struct evsel *evsel, 42862306a36Sopenharmony_ci struct perf_stat_output_ctx *out) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci double iostat_value = 0; 43162306a36Sopenharmony_ci u64 prev_count_val = 0; 43262306a36Sopenharmony_ci const char *iostat_metric = iostat_metric_by_idx(evsel->core.idx); 43362306a36Sopenharmony_ci u8 die = ((struct iio_root_port *)evsel->priv)->die; 43462306a36Sopenharmony_ci struct perf_counts_values *count = perf_counts(evsel->counts, die, 0); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (count && count->run && count->ena) { 43762306a36Sopenharmony_ci if (evsel->prev_raw_counts && !out->force_header) { 43862306a36Sopenharmony_ci struct perf_counts_values *prev_count = 43962306a36Sopenharmony_ci perf_counts(evsel->prev_raw_counts, die, 0); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci prev_count_val = prev_count->val; 44262306a36Sopenharmony_ci prev_count->val = count->val; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci iostat_value = (count->val - prev_count_val) / 44562306a36Sopenharmony_ci ((double) count->run / count->ena); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci out->print_metric(config, out->ctx, NULL, "%8.0f", iostat_metric, 44862306a36Sopenharmony_ci iostat_value / (256 * 1024)); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_civoid iostat_print_counters(struct evlist *evlist, 45262306a36Sopenharmony_ci struct perf_stat_config *config, struct timespec *ts, 45362306a36Sopenharmony_ci char *prefix, iostat_print_counter_t print_cnt_cb, void *arg) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci void *perf_device = NULL; 45662306a36Sopenharmony_ci struct evsel *counter = evlist__first(evlist); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci evlist__set_selected(evlist, counter); 45962306a36Sopenharmony_ci iostat_prefix(evlist, config, prefix, ts); 46062306a36Sopenharmony_ci fprintf(config->output, "%s", prefix); 46162306a36Sopenharmony_ci evlist__for_each_entry(evlist, counter) { 46262306a36Sopenharmony_ci perf_device = evlist->selected->priv; 46362306a36Sopenharmony_ci if (perf_device && perf_device != counter->priv) { 46462306a36Sopenharmony_ci evlist__set_selected(evlist, counter); 46562306a36Sopenharmony_ci iostat_prefix(evlist, config, prefix, ts); 46662306a36Sopenharmony_ci fprintf(config->output, "\n%s", prefix); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci print_cnt_cb(config, counter, arg); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci fputc('\n', config->output); 47162306a36Sopenharmony_ci} 472