Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/perf/{hv-gpci, hv-common}: generate requests with counters annotated

This adds (in req-gen/) a framework for defining gpci counter requests.
It uses macro magic similar to ftrace.

Also convert the existing hv-gpci request structures and enum values to
use the new framework (and adjust old users of the structs and enum
values to cope with changes in naming).

In exchange for this macro disaster, we get autogenerated event listing
for GPCI in sysfs, build time field offset checking, and zero
duplication of information about GPCI requests.

Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com>
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Cody P Schafer and committed by
Michael Ellerman
9e9f6010 5c5cd7b5

+316 -30
+5 -5
arch/powerpc/perf/hv-common.c
··· 9 9 unsigned long r; 10 10 struct p { 11 11 struct hv_get_perf_counter_info_params params; 12 - struct cv_system_performance_capabilities caps; 12 + struct hv_gpci_system_performance_capabilities caps; 13 13 } __packed __aligned(sizeof(uint64_t)); 14 14 15 15 struct p arg = { 16 16 .params = { 17 17 .counter_request = cpu_to_be32( 18 - CIR_SYSTEM_PERFORMANCE_CAPABILITIES), 18 + HV_GPCI_system_performance_capabilities), 19 19 .starting_index = cpu_to_be32(-1), 20 20 .counter_info_version_in = 0, 21 21 } ··· 31 31 32 32 caps->version = arg.params.counter_info_version_out; 33 33 caps->collect_privileged = !!arg.caps.perf_collect_privileged; 34 - caps->ga = !!(arg.caps.capability_mask & CV_CM_GA); 35 - caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED); 36 - caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB); 34 + caps->ga = !!(arg.caps.capability_mask & HV_GPCI_CM_GA); 35 + caps->expanded = !!(arg.caps.capability_mask & HV_GPCI_CM_EXPANDED); 36 + caps->lab = !!(arg.caps.capability_mask & HV_GPCI_CM_LAB); 37 37 38 38 return r; 39 39 }
+76
arch/powerpc/perf/hv-gpci-requests.h
··· 1 + 2 + #include "req-gen/_begin.h" 3 + 4 + /* 5 + * Based on the document "getPerfCountInfo v1.07" 6 + */ 7 + 8 + /* 9 + * #define REQUEST_NAME counter_request_name 10 + * #define REQUEST_NUM r_num 11 + * #define REQUEST_IDX_KIND starting_index_kind 12 + * #include I(REQUEST_BEGIN) 13 + * REQUEST( 14 + * __field(...) 15 + * __field(...) 16 + * __array(...) 17 + * __count(...) 18 + * ) 19 + * #include I(REQUEST_END) 20 + * 21 + * - starting_index_kind is one of the following, depending on the event: 22 + * 23 + * chip_id: hardware chip id or -1 for current hw chip 24 + * phys_processor_idx: 25 + * 0xffffffffffffffff: or -1, which means it is irrelavant for the event 26 + * 27 + * __count(offset, bytes, name): 28 + * a counter that should be exposed via perf 29 + * __field(offset, bytes, name) 30 + * a normal field 31 + * __array(offset, bytes, name) 32 + * an array of bytes 33 + * 34 + * 35 + * @bytes for __count, and __field _must_ be a numeral token 36 + * in decimal, not an expression and not in hex. 37 + * 38 + * 39 + * TODO: 40 + * - expose secondary index (if any counter ever uses it, only 0xA0 41 + * appears to use it right now, and it doesn't have any counters) 42 + * - embed versioning info 43 + * - include counter descriptions 44 + */ 45 + #define REQUEST_NAME dispatch_timebase_by_processor 46 + #define REQUEST_NUM 0x10 47 + #define REQUEST_IDX_KIND "phys_processor_idx=?" 48 + #include I(REQUEST_BEGIN) 49 + REQUEST(__count(0, 8, processor_time_in_timebase_cycles) 50 + __field(0x8, 4, hw_processor_id) 51 + __field(0xC, 2, owning_part_id) 52 + __field(0xE, 1, processor_state) 53 + __field(0xF, 1, version) 54 + __field(0x10, 4, hw_chip_id) 55 + __field(0x14, 4, phys_module_id) 56 + __field(0x18, 4, primary_affinity_domain_idx) 57 + __field(0x1C, 4, secondary_affinity_domain_idx) 58 + __field(0x20, 4, processor_version) 59 + __field(0x24, 2, logical_processor_idx) 60 + __field(0x26, 2, reserved) 61 + __field(0x28, 4, processor_id_register) 62 + __field(0x2C, 4, phys_processor_idx) 63 + ) 64 + #include I(REQUEST_END) 65 + 66 + #define REQUEST_NAME system_performance_capabilities 67 + #define REQUEST_NUM 0x40 68 + #define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff" 69 + #include I(REQUEST_BEGIN) 70 + REQUEST(__field(0, 1, perf_collect_privileged) 71 + __field(0x1, 1, capability_mask) 72 + __array(0x2, 0xE, reserved) 73 + ) 74 + #include I(REQUEST_END) 75 + 76 + #include "req-gen/_end.h"
+23
arch/powerpc/perf/hv-gpci.c
··· 31 31 /* u32 */ 32 32 EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31); 33 33 /* u32 */ 34 + /* 35 + * Note that starting_index, phys_processor_idx, sibling_part_id, 36 + * hw_chip_id, partition_id all refer to the same bit range. They 37 + * are basically aliases for the starting_index. The specific alias 38 + * used depends on the event. See REQUEST_IDX_KIND in hv-gpci-requests.h 39 + */ 34 40 EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63); 41 + EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx, config, 32, 63); 42 + EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id, config, 32, 63); 43 + EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id, config, 32, 63); 44 + EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id, config, 32, 63); 45 + 35 46 /* u16 */ 36 47 EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15); 37 48 /* u8 */ ··· 55 44 static struct attribute *format_attrs[] = { 56 45 &format_attr_request.attr, 57 46 &format_attr_starting_index.attr, 47 + &format_attr_phys_processor_idx.attr, 48 + &format_attr_sibling_part_id.attr, 49 + &format_attr_hw_chip_id.attr, 50 + &format_attr_partition_id.attr, 58 51 &format_attr_secondary_index.attr, 59 52 &format_attr_counter_info_version.attr, 60 53 ··· 70 55 static struct attribute_group format_group = { 71 56 .name = "format", 72 57 .attrs = format_attrs, 58 + }; 59 + 60 + static struct attribute_group event_group = { 61 + .name = "events", 62 + .attrs = hv_gpci_event_attrs, 73 63 }; 74 64 75 65 #define HV_CAPS_ATTR(_name, _format) \ ··· 122 102 123 103 static const struct attribute_group *attr_groups[] = { 124 104 &format_group, 105 + &event_group, 125 106 &interface_group, 126 107 NULL, 127 108 }; ··· 285 264 int r; 286 265 unsigned long hret; 287 266 struct hv_perf_caps caps; 267 + 268 + hv_gpci_assert_offsets_correct(); 288 269 289 270 if (!firmware_has_feature(FW_FEATURE_LPAR)) { 290 271 pr_debug("not a virtualized system, not enabling\n");
+12 -25
arch/powerpc/perf/hv-gpci.h
··· 42 42 */ 43 43 #define COUNTER_INFO_VERSION_CURRENT 0x8 44 44 45 - /* 46 - * These determine the counter_value[] layout and the meaning of starting_index 47 - * and secondary_index. 48 - * 49 - * Unless otherwise noted, @secondary_index is unused and ignored. 50 - */ 51 - enum counter_info_requests { 52 - 53 - /* GENERAL */ 54 - 55 - /* @starting_index: must be -1 (to refer to the current partition) 56 - */ 57 - CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40, 45 + /* capability mask masks. */ 46 + enum { 47 + HV_GPCI_CM_GA = (1 << 7), 48 + HV_GPCI_CM_EXPANDED = (1 << 6), 49 + HV_GPCI_CM_LAB = (1 << 5) 58 50 }; 59 51 60 - struct cv_system_performance_capabilities { 61 - /* If != 0, allowed to collect data from other partitions */ 62 - __u8 perf_collect_privileged; 63 - 64 - /* These following are only valid if counter_info_version >= 0x3 */ 65 - #define CV_CM_GA (1 << 7) 66 - #define CV_CM_EXPANDED (1 << 6) 67 - #define CV_CM_LAB (1 << 5) 68 - /* remaining bits are reserved */ 69 - __u8 capability_mask; 70 - __u8 reserved[0xE]; 71 - } __packed; 52 + #define REQUEST_FILE "../hv-gpci-requests.h" 53 + #define NAME_LOWER hv_gpci 54 + #define NAME_UPPER HV_GPCI 55 + #include "req-gen/perf.h" 56 + #undef REQUEST_FILE 57 + #undef NAME_LOWER 58 + #undef NAME_UPPER 72 59 73 60 #endif
+13
arch/powerpc/perf/req-gen/_begin.h
··· 1 + /* Include paths to be used in interface defining headers */ 2 + #ifndef POWERPC_PERF_REQ_GEN_H_ 3 + #define POWERPC_PERF_REQ_GEN_H_ 4 + 5 + #define CAT2_STR_(t, s) __stringify(t/s) 6 + #define CAT2_STR(t, s) CAT2_STR_(t, s) 7 + #define I(...) __VA_ARGS__ 8 + 9 + #endif 10 + 11 + #define REQ_GEN_PREFIX req-gen 12 + #define REQUEST_BEGIN CAT2_STR(REQ_GEN_PREFIX, _request-begin.h) 13 + #define REQUEST_END CAT2_STR(REQ_GEN_PREFIX, _request-end.h)
+5
arch/powerpc/perf/req-gen/_clear.h
··· 1 + 2 + #undef __field_ 3 + #undef __count_ 4 + #undef __array_ 5 + #undef REQUEST_
+4
arch/powerpc/perf/req-gen/_end.h
··· 1 + 2 + #undef REQ_GEN_PREFIX 3 + #undef REQUEST_BEGIN 4 + #undef REQUEST_END
+15
arch/powerpc/perf/req-gen/_request-begin.h
··· 1 + 2 + #define REQUEST(r_contents) \ 3 + REQUEST_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, I(r_contents)) 4 + 5 + #define __field(f_offset, f_bytes, f_name) \ 6 + __field_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \ 7 + f_offset, f_bytes, f_name) 8 + 9 + #define __array(f_offset, f_bytes, f_name) \ 10 + __array_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \ 11 + f_offset, f_bytes, f_name) 12 + 13 + #define __count(f_offset, f_bytes, f_name) \ 14 + __count_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \ 15 + f_offset, f_bytes, f_name)
+8
arch/powerpc/perf/req-gen/_request-end.h
··· 1 + #undef REQUEST 2 + #undef __field 3 + #undef __array 4 + #undef __count 5 + 6 + #undef REQUEST_NAME 7 + #undef REQUEST_NUM 8 + #undef REQUEST_IDX_KIND
+155
arch/powerpc/perf/req-gen/perf.h
··· 1 + #ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_ 2 + #define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_ 3 + 4 + #include <linux/perf_event.h> 5 + 6 + #ifndef REQUEST_FILE 7 + #error "REQUEST_FILE must be defined before including" 8 + #endif 9 + 10 + #ifndef NAME_LOWER 11 + #error "NAME_LOWER must be defined before including" 12 + #endif 13 + 14 + #ifndef NAME_UPPER 15 + #error "NAME_UPPER must be defined before including" 16 + #endif 17 + 18 + #define BE_TYPE_b1 __u8 19 + #define BE_TYPE_b2 __be16 20 + #define BE_TYPE_b4 __be32 21 + #define BE_TYPE_b8 __be64 22 + 23 + #define BYTES_TO_BE_TYPE(bytes) \ 24 + BE_TYPE_b##bytes 25 + 26 + #define CAT2_(a, b) a ## b 27 + #define CAT2(a, b) CAT2_(a, b) 28 + #define CAT3_(a, b, c) a ## b ## c 29 + #define CAT3(a, b, c) CAT3_(a, b, c) 30 + 31 + /* 32 + * enumerate the request values as 33 + * <NAME_UPPER>_<request name> = <request value> 34 + */ 35 + #define REQUEST_VALUE__(name_upper, r_name) name_upper ## _ ## r_name 36 + #define REQUEST_VALUE_(name_upper, r_name) REQUEST_VALUE__(name_upper, r_name) 37 + #define REQUEST_VALUE(r_name) REQUEST_VALUE_(NAME_UPPER, r_name) 38 + 39 + #include "_clear.h" 40 + #define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ 41 + REQUEST_VALUE(r_name) = r_value, 42 + enum CAT2(NAME_LOWER, _requests) { 43 + #include REQUEST_FILE 44 + }; 45 + 46 + /* 47 + * For each request: 48 + * struct <NAME_LOWER>_<request name> { 49 + * r_fields 50 + * }; 51 + */ 52 + #include "_clear.h" 53 + #define STRUCT_NAME__(name_lower, r_name) name_lower ## _ ## r_name 54 + #define STRUCT_NAME_(name_lower, r_name) STRUCT_NAME__(name_lower, r_name) 55 + #define STRUCT_NAME(r_name) STRUCT_NAME_(NAME_LOWER, r_name) 56 + #define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ 57 + struct STRUCT_NAME(r_name) { \ 58 + r_fields \ 59 + }; 60 + #define __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \ 61 + BYTES_TO_BE_TYPE(f_bytes) f_name; 62 + #define __count_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \ 63 + __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) 64 + #define __array_(r_name, r_value, r_idx_1, a_offset, a_bytes, a_name) \ 65 + __u8 a_name[a_bytes]; 66 + 67 + #include REQUEST_FILE 68 + 69 + /* 70 + * Generate a check of the field offsets 71 + * <NAME_LOWER>_assert_offsets_correct() 72 + */ 73 + #include "_clear.h" 74 + #define REQUEST_(r_name, r_value, index, r_fields) \ 75 + r_fields 76 + #define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) \ 77 + BUILD_BUG_ON(offsetof(struct STRUCT_NAME(r_name), f_name) != f_offset); 78 + #define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \ 79 + __field_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) 80 + #define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) \ 81 + __field_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) 82 + 83 + static inline void CAT2(NAME_LOWER, _assert_offsets_correct)(void) 84 + { 85 + #include REQUEST_FILE 86 + } 87 + 88 + /* 89 + * Generate event attributes: 90 + * PMU_EVENT_ATTR_STRING(<request name>_<field name>, 91 + * <NAME_LOWER>_event_attr_<request name>_<field name>, 92 + * "request=<request value>" 93 + * "starting_index=<starting index type>" 94 + * "counter_info_version=CURRENT_COUNTER_INFO_VERSION" 95 + * "length=<f_size>" 96 + * "offset=<f_offset>") 97 + * 98 + * TODO: counter_info_version may need to vary, we should interperate the 99 + * value to some extent 100 + */ 101 + #define EVENT_ATTR_NAME__(name, r_name, c_name) \ 102 + name ## _event_attr_ ## r_name ## _ ## c_name 103 + #define EVENT_ATTR_NAME_(name, r_name, c_name) \ 104 + EVENT_ATTR_NAME__(name, r_name, c_name) 105 + #define EVENT_ATTR_NAME(r_name, c_name) \ 106 + EVENT_ATTR_NAME_(NAME_LOWER, r_name, c_name) 107 + 108 + #include "_clear.h" 109 + #define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) 110 + #define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) 111 + #define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \ 112 + PMU_EVENT_ATTR_STRING( \ 113 + CAT3(r_name, _, c_name), \ 114 + EVENT_ATTR_NAME(r_name, c_name), \ 115 + "request=" __stringify(r_value) "," \ 116 + r_idx_1 "," \ 117 + "counter_info_version=" \ 118 + __stringify(COUNTER_INFO_VERSION_CURRENT) "," \ 119 + "length=" #c_size "," \ 120 + "offset=" #c_offset) 121 + #define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ 122 + r_fields 123 + 124 + #include REQUEST_FILE 125 + 126 + /* 127 + * Define event attribute array 128 + * static struct attribute *hv_gpci_event_attrs[] = { 129 + * &<NAME_LOWER>_event_attr_<request name>_<field name>.attr, 130 + * }; 131 + */ 132 + #include "_clear.h" 133 + #define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) 134 + #define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \ 135 + &EVENT_ATTR_NAME(r_name, c_name).attr.attr, 136 + #define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) 137 + #define REQUEST_(r_name, r_value, r_idx_1, r_fields) \ 138 + r_fields 139 + 140 + static __maybe_unused struct attribute *hv_gpci_event_attrs[] = { 141 + #include REQUEST_FILE 142 + NULL 143 + }; 144 + 145 + /* cleanup */ 146 + #include "_clear.h" 147 + #undef EVENT_ATTR_NAME 148 + #undef EVENT_ATTR_NAME_ 149 + #undef BIT_NAME 150 + #undef BIT_NAME_ 151 + #undef STRUCT_NAME 152 + #undef REQUEST_VALUE 153 + #undef REQUEST_VALUE_ 154 + 155 + #endif