| /* |
| * validate.c - validate event tables + encodings |
| * |
| * Copyright (c) 2010 Google, Inc |
| * Contributed by Stephane Eranian <eranian@gmail.com> |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in all |
| * copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, |
| * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A |
| * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE |
| * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * This file is part of libpfm, a performance monitoring support library for |
| * applications on Linux. |
| */ |
| #include <sys/types.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <inttypes.h> |
| #include <stdarg.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <perfmon/err.h> |
| |
| #include <perfmon/pfmlib.h> |
| #ifdef __linux__ |
| #include <perfmon/pfmlib_perf_event.h> |
| #endif |
| |
| #define __weak_func __attribute__((weak)) |
| |
| #ifdef PFMLIB_WINDOWS |
| int set_env_var(const char *var, const char *value, int ov) |
| { |
| size_t len; |
| char *str; |
| int ret; |
| |
| len = strlen(var) + 1 + strlen(value) + 1; |
| |
| str = malloc(len); |
| if (!str) |
| return PFM_ERR_NOMEM; |
| |
| sprintf(str, "%s=%s", var, value); |
| |
| ret = putenv(str); |
| |
| free(str); |
| |
| return ret ? PFM_ERR_INVAL : PFM_SUCCESS; |
| } |
| #else |
| static inline int |
| set_env_var(const char *var, const char *value, int ov) |
| { |
| return setenv(var, value, ov); |
| } |
| #endif |
| |
| __weak_func int validate_arch(FILE *fp) |
| { |
| return 0; |
| } |
| |
| static struct { |
| int valid_intern; |
| int valid_arch; |
| } options; |
| |
| static void |
| usage(void) |
| { |
| printf("validate [-c] [-a] [-A]\n" |
| "-c\trun the library validate events\n" |
| "-a\trun architecture specific event tests\n" |
| "-A\trun all tests\n" |
| "-h\tget help\n"); |
| } |
| |
| static int |
| validate_event_tables(void) |
| { |
| pfm_pmu_info_t pinfo; |
| int i, ret, errors = 0; |
| |
| memset(&pinfo, 0, sizeof(pinfo)); |
| |
| pinfo.size = sizeof(pinfo); |
| |
| pfm_for_all_pmus(i) { |
| ret = pfm_get_pmu_info(i, &pinfo); |
| if (ret != PFM_SUCCESS) |
| continue; |
| |
| printf("\tchecking %s (%d events): ", pinfo.name, pinfo.nevents); |
| fflush(stdout); |
| |
| ret = pfm_pmu_validate(i, stdout); |
| if (ret != PFM_SUCCESS && ret != PFM_ERR_NOTSUPP) { |
| printf("Failed\n"); |
| errors++; |
| } else if (ret == PFM_ERR_NOTSUPP) { |
| printf("N/A\n"); |
| } else { |
| printf("Passed\n"); |
| } |
| } |
| return errors; |
| } |
| |
| #if __WORDSIZE == 64 |
| #define STRUCT_MULT 8 |
| #else |
| #define STRUCT_MULT 4 |
| #endif |
| |
| #define MAX_FIELDS 32 |
| typedef struct { |
| const char *name; |
| size_t sz; |
| } field_desc_t; |
| |
| typedef struct { |
| const char *name; |
| size_t sz; |
| size_t bitfield_sz; |
| size_t abi_sz; |
| field_desc_t fields[MAX_FIELDS]; |
| } struct_desc_t; |
| |
| #define LAST_STRUCT { .name = NULL, } |
| |
| #define FIELD(n, st) \ |
| { .name = #n, \ |
| .sz = sizeof(((st *)(0))->n), \ |
| } |
| #define LAST_FIELD { .name = NULL, } |
| |
| static const struct_desc_t pfmlib_structs[]={ |
| { |
| .name = "pfm_pmu_info_t", |
| .sz = sizeof(pfm_pmu_info_t), |
| .bitfield_sz = 4, |
| .abi_sz = PFM_PMU_INFO_ABI0, |
| .fields= { |
| FIELD(name, pfm_pmu_info_t), |
| FIELD(desc, pfm_pmu_info_t), |
| FIELD(size, pfm_pmu_info_t), |
| FIELD(pmu, pfm_pmu_info_t), |
| FIELD(type, pfm_pmu_info_t), |
| FIELD(nevents, pfm_pmu_info_t), |
| FIELD(first_event, pfm_pmu_info_t), |
| FIELD(max_encoding, pfm_pmu_info_t), |
| FIELD(num_cntrs, pfm_pmu_info_t), |
| FIELD(num_fixed_cntrs, pfm_pmu_info_t), |
| LAST_FIELD |
| }, |
| }, |
| { |
| .name = "pfm_event_info_t", |
| .sz = sizeof(pfm_event_info_t), |
| .bitfield_sz = 4, |
| .abi_sz = PFM_EVENT_INFO_ABI0, |
| .fields= { |
| FIELD(name, pfm_event_info_t), |
| FIELD(desc, pfm_event_info_t), |
| FIELD(equiv, pfm_event_info_t), |
| FIELD(size, pfm_event_info_t), |
| FIELD(code, pfm_event_info_t), |
| FIELD(pmu, pfm_event_info_t), |
| FIELD(dtype, pfm_event_info_t), |
| FIELD(idx, pfm_event_info_t), |
| FIELD(nattrs, pfm_event_info_t), |
| FIELD(reserved, pfm_event_info_t), |
| LAST_FIELD |
| }, |
| }, |
| { |
| .name = "pfm_event_attr_info_t", |
| .sz = sizeof(pfm_event_attr_info_t), |
| .bitfield_sz = 4+8, |
| .abi_sz = PFM_ATTR_INFO_ABI0, |
| .fields= { |
| FIELD(name, pfm_event_attr_info_t), |
| FIELD(desc, pfm_event_attr_info_t), |
| FIELD(equiv, pfm_event_attr_info_t), |
| FIELD(size, pfm_event_attr_info_t), |
| FIELD(code, pfm_event_attr_info_t), |
| FIELD(type, pfm_event_attr_info_t), |
| FIELD(idx, pfm_event_attr_info_t), |
| FIELD(ctrl, pfm_event_attr_info_t), |
| LAST_FIELD |
| }, |
| }, |
| { |
| .name = "pfm_pmu_encode_arg_t", |
| .sz = sizeof(pfm_pmu_encode_arg_t), |
| .abi_sz = PFM_RAW_ENCODE_ABI0, |
| .fields= { |
| FIELD(codes, pfm_pmu_encode_arg_t), |
| FIELD(fstr, pfm_pmu_encode_arg_t), |
| FIELD(size, pfm_pmu_encode_arg_t), |
| FIELD(count, pfm_pmu_encode_arg_t), |
| FIELD(idx, pfm_pmu_encode_arg_t), |
| LAST_FIELD |
| }, |
| }, |
| #ifdef __linux__ |
| { |
| .name = "pfm_perf_encode_arg_t", |
| .sz = sizeof(pfm_perf_encode_arg_t), |
| .bitfield_sz = 0, |
| .abi_sz = PFM_PERF_ENCODE_ABI0, |
| .fields= { |
| FIELD(attr, pfm_perf_encode_arg_t), |
| FIELD(fstr, pfm_perf_encode_arg_t), |
| FIELD(size, pfm_perf_encode_arg_t), |
| FIELD(idx, pfm_perf_encode_arg_t), |
| FIELD(cpu, pfm_perf_encode_arg_t), |
| FIELD(flags, pfm_perf_encode_arg_t), |
| FIELD(pad0, pfm_perf_encode_arg_t), |
| LAST_FIELD |
| }, |
| }, |
| #endif |
| LAST_STRUCT |
| }; |
| |
| static int |
| validate_structs(void) |
| { |
| |
| const struct_desc_t *d; |
| const field_desc_t *f; |
| size_t sz; |
| int errors = 0; |
| int abi = LIBPFM_ABI_VERSION; |
| |
| printf("\tlibpfm ABI version : %d\n", abi); |
| for (d = pfmlib_structs; d->name; d++) { |
| |
| printf("\t%s : ", d->name); |
| |
| if (d->abi_sz != d->sz) { |
| printf("struct size does not correspond to ABI size %zu vs. %zu)\n", d->abi_sz, d->sz); |
| errors++; |
| } |
| |
| if (d->sz % STRUCT_MULT) { |
| printf("Failed (wrong mult size=%zu)\n", d->sz); |
| errors++; |
| } |
| |
| sz = d->bitfield_sz; |
| for (f = d->fields; f->name; f++) { |
| sz += f->sz; |
| } |
| |
| if (sz != d->sz) { |
| printf("Failed (invisible padding of %zu bytes)\n", d->sz - sz); |
| errors++; |
| continue; |
| } |
| printf("Passed\n"); |
| |
| } |
| return errors; |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| int ret, c, errors = 0; |
| |
| |
| while ((c=getopt(argc, argv,"hcaA")) != -1) { |
| switch(c) { |
| case 'c': |
| options.valid_intern = 1; |
| break; |
| case 'a': |
| options.valid_arch = 1; |
| break; |
| case 'A': |
| options.valid_arch = 1; |
| options.valid_intern = 1; |
| break; |
| case 'h': |
| usage(); |
| exit(0); |
| default: |
| errx(1, "unknown option error"); |
| } |
| } |
| /* to allow encoding of events from non detected PMU models */ |
| ret = set_env_var("LIBPFM_ENCODE_INACTIVE", "1", 1); |
| if (ret != PFM_SUCCESS) |
| errx(1, "cannot force inactive encoding"); |
| |
| ret = pfm_initialize(); |
| if (ret != PFM_SUCCESS) |
| errx(1, "cannot initialize libpfm: %s", pfm_strerror(ret)); |
| |
| /* run everything by default */ |
| if (!(options.valid_intern || options.valid_arch)) { |
| options.valid_intern = 1; |
| options.valid_arch = 1; |
| } |
| |
| printf("Libpfm structure tests:\n"); |
| errors += validate_structs(); |
| |
| if (options.valid_intern) { |
| printf("Libpfm internal table tests:\n"); |
| errors += validate_event_tables(); |
| } |
| |
| if (options.valid_arch) { |
| printf("Architecture specific tests:\n"); |
| errors += validate_arch(stderr); |
| } |
| |
| pfm_terminate(); |
| |
| if (errors) |
| printf("Total %d errors\n", errors); |
| else |
| printf("All tests passed\n"); |
| |
| return errors; |
| } |