Commit 9e9f6010 authored by Cody P Schafer's avatar Cody P Schafer Committed by Michael Ellerman

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: default avatarCody P Schafer <cody@linux.vnet.ibm.com>
Signed-off-by: default avatarSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 5c5cd7b5
...@@ -9,13 +9,13 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps) ...@@ -9,13 +9,13 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
unsigned long r; unsigned long r;
struct p { struct p {
struct hv_get_perf_counter_info_params params; struct hv_get_perf_counter_info_params params;
struct cv_system_performance_capabilities caps; struct hv_gpci_system_performance_capabilities caps;
} __packed __aligned(sizeof(uint64_t)); } __packed __aligned(sizeof(uint64_t));
struct p arg = { struct p arg = {
.params = { .params = {
.counter_request = cpu_to_be32( .counter_request = cpu_to_be32(
CIR_SYSTEM_PERFORMANCE_CAPABILITIES), HV_GPCI_system_performance_capabilities),
.starting_index = cpu_to_be32(-1), .starting_index = cpu_to_be32(-1),
.counter_info_version_in = 0, .counter_info_version_in = 0,
} }
...@@ -31,9 +31,9 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps) ...@@ -31,9 +31,9 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
caps->version = arg.params.counter_info_version_out; caps->version = arg.params.counter_info_version_out;
caps->collect_privileged = !!arg.caps.perf_collect_privileged; caps->collect_privileged = !!arg.caps.perf_collect_privileged;
caps->ga = !!(arg.caps.capability_mask & CV_CM_GA); caps->ga = !!(arg.caps.capability_mask & HV_GPCI_CM_GA);
caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED); caps->expanded = !!(arg.caps.capability_mask & HV_GPCI_CM_EXPANDED);
caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB); caps->lab = !!(arg.caps.capability_mask & HV_GPCI_CM_LAB);
return r; return r;
} }
#include "req-gen/_begin.h"
/*
* Based on the document "getPerfCountInfo v1.07"
*/
/*
* #define REQUEST_NAME counter_request_name
* #define REQUEST_NUM r_num
* #define REQUEST_IDX_KIND starting_index_kind
* #include I(REQUEST_BEGIN)
* REQUEST(
* __field(...)
* __field(...)
* __array(...)
* __count(...)
* )
* #include I(REQUEST_END)
*
* - starting_index_kind is one of the following, depending on the event:
*
* chip_id: hardware chip id or -1 for current hw chip
* phys_processor_idx:
* 0xffffffffffffffff: or -1, which means it is irrelavant for the event
*
* __count(offset, bytes, name):
* a counter that should be exposed via perf
* __field(offset, bytes, name)
* a normal field
* __array(offset, bytes, name)
* an array of bytes
*
*
* @bytes for __count, and __field _must_ be a numeral token
* in decimal, not an expression and not in hex.
*
*
* TODO:
* - expose secondary index (if any counter ever uses it, only 0xA0
* appears to use it right now, and it doesn't have any counters)
* - embed versioning info
* - include counter descriptions
*/
#define REQUEST_NAME dispatch_timebase_by_processor
#define REQUEST_NUM 0x10
#define REQUEST_IDX_KIND "phys_processor_idx=?"
#include I(REQUEST_BEGIN)
REQUEST(__count(0, 8, processor_time_in_timebase_cycles)
__field(0x8, 4, hw_processor_id)
__field(0xC, 2, owning_part_id)
__field(0xE, 1, processor_state)
__field(0xF, 1, version)
__field(0x10, 4, hw_chip_id)
__field(0x14, 4, phys_module_id)
__field(0x18, 4, primary_affinity_domain_idx)
__field(0x1C, 4, secondary_affinity_domain_idx)
__field(0x20, 4, processor_version)
__field(0x24, 2, logical_processor_idx)
__field(0x26, 2, reserved)
__field(0x28, 4, processor_id_register)
__field(0x2C, 4, phys_processor_idx)
)
#include I(REQUEST_END)
#define REQUEST_NAME system_performance_capabilities
#define REQUEST_NUM 0x40
#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
#include I(REQUEST_BEGIN)
REQUEST(__field(0, 1, perf_collect_privileged)
__field(0x1, 1, capability_mask)
__array(0x2, 0xE, reserved)
)
#include I(REQUEST_END)
#include "req-gen/_end.h"
...@@ -31,7 +31,18 @@ ...@@ -31,7 +31,18 @@
/* u32 */ /* u32 */
EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31); EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31);
/* u32 */ /* u32 */
/*
* Note that starting_index, phys_processor_idx, sibling_part_id,
* hw_chip_id, partition_id all refer to the same bit range. They
* are basically aliases for the starting_index. The specific alias
* used depends on the event. See REQUEST_IDX_KIND in hv-gpci-requests.h
*/
EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63); EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63);
EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx, config, 32, 63);
EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id, config, 32, 63);
EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id, config, 32, 63);
EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id, config, 32, 63);
/* u16 */ /* u16 */
EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15); EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15);
/* u8 */ /* u8 */
...@@ -44,6 +55,10 @@ EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63); ...@@ -44,6 +55,10 @@ EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
static struct attribute *format_attrs[] = { static struct attribute *format_attrs[] = {
&format_attr_request.attr, &format_attr_request.attr,
&format_attr_starting_index.attr, &format_attr_starting_index.attr,
&format_attr_phys_processor_idx.attr,
&format_attr_sibling_part_id.attr,
&format_attr_hw_chip_id.attr,
&format_attr_partition_id.attr,
&format_attr_secondary_index.attr, &format_attr_secondary_index.attr,
&format_attr_counter_info_version.attr, &format_attr_counter_info_version.attr,
...@@ -57,6 +72,11 @@ static struct attribute_group format_group = { ...@@ -57,6 +72,11 @@ static struct attribute_group format_group = {
.attrs = format_attrs, .attrs = format_attrs,
}; };
static struct attribute_group event_group = {
.name = "events",
.attrs = hv_gpci_event_attrs,
};
#define HV_CAPS_ATTR(_name, _format) \ #define HV_CAPS_ATTR(_name, _format) \
static ssize_t _name##_show(struct device *dev, \ static ssize_t _name##_show(struct device *dev, \
struct device_attribute *attr, \ struct device_attribute *attr, \
...@@ -102,6 +122,7 @@ static struct attribute_group interface_group = { ...@@ -102,6 +122,7 @@ static struct attribute_group interface_group = {
static const struct attribute_group *attr_groups[] = { static const struct attribute_group *attr_groups[] = {
&format_group, &format_group,
&event_group,
&interface_group, &interface_group,
NULL, NULL,
}; };
...@@ -265,6 +286,8 @@ static int hv_gpci_init(void) ...@@ -265,6 +286,8 @@ static int hv_gpci_init(void)
unsigned long hret; unsigned long hret;
struct hv_perf_caps caps; struct hv_perf_caps caps;
hv_gpci_assert_offsets_correct();
if (!firmware_has_feature(FW_FEATURE_LPAR)) { if (!firmware_has_feature(FW_FEATURE_LPAR)) {
pr_debug("not a virtualized system, not enabling\n"); pr_debug("not a virtualized system, not enabling\n");
return -ENODEV; return -ENODEV;
......
...@@ -42,32 +42,19 @@ struct hv_get_perf_counter_info_params { ...@@ -42,32 +42,19 @@ struct hv_get_perf_counter_info_params {
*/ */
#define COUNTER_INFO_VERSION_CURRENT 0x8 #define COUNTER_INFO_VERSION_CURRENT 0x8
/* /* capability mask masks. */
* These determine the counter_value[] layout and the meaning of starting_index enum {
* and secondary_index. HV_GPCI_CM_GA = (1 << 7),
* HV_GPCI_CM_EXPANDED = (1 << 6),
* Unless otherwise noted, @secondary_index is unused and ignored. HV_GPCI_CM_LAB = (1 << 5)
*/
enum counter_info_requests {
/* GENERAL */
/* @starting_index: must be -1 (to refer to the current partition)
*/
CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40,
}; };
struct cv_system_performance_capabilities { #define REQUEST_FILE "../hv-gpci-requests.h"
/* If != 0, allowed to collect data from other partitions */ #define NAME_LOWER hv_gpci
__u8 perf_collect_privileged; #define NAME_UPPER HV_GPCI
#include "req-gen/perf.h"
/* These following are only valid if counter_info_version >= 0x3 */ #undef REQUEST_FILE
#define CV_CM_GA (1 << 7) #undef NAME_LOWER
#define CV_CM_EXPANDED (1 << 6) #undef NAME_UPPER
#define CV_CM_LAB (1 << 5)
/* remaining bits are reserved */
__u8 capability_mask;
__u8 reserved[0xE];
} __packed;
#endif #endif
/* Include paths to be used in interface defining headers */
#ifndef POWERPC_PERF_REQ_GEN_H_
#define POWERPC_PERF_REQ_GEN_H_
#define CAT2_STR_(t, s) __stringify(t/s)
#define CAT2_STR(t, s) CAT2_STR_(t, s)
#define I(...) __VA_ARGS__
#endif
#define REQ_GEN_PREFIX req-gen
#define REQUEST_BEGIN CAT2_STR(REQ_GEN_PREFIX, _request-begin.h)
#define REQUEST_END CAT2_STR(REQ_GEN_PREFIX, _request-end.h)
#undef __field_
#undef __count_
#undef __array_
#undef REQUEST_
#undef REQ_GEN_PREFIX
#undef REQUEST_BEGIN
#undef REQUEST_END
#define REQUEST(r_contents) \
REQUEST_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, I(r_contents))
#define __field(f_offset, f_bytes, f_name) \
__field_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \
f_offset, f_bytes, f_name)
#define __array(f_offset, f_bytes, f_name) \
__array_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \
f_offset, f_bytes, f_name)
#define __count(f_offset, f_bytes, f_name) \
__count_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \
f_offset, f_bytes, f_name)
#undef REQUEST
#undef __field
#undef __array
#undef __count
#undef REQUEST_NAME
#undef REQUEST_NUM
#undef REQUEST_IDX_KIND
#ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
#define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
#include <linux/perf_event.h>
#ifndef REQUEST_FILE
#error "REQUEST_FILE must be defined before including"
#endif
#ifndef NAME_LOWER
#error "NAME_LOWER must be defined before including"
#endif
#ifndef NAME_UPPER
#error "NAME_UPPER must be defined before including"
#endif
#define BE_TYPE_b1 __u8
#define BE_TYPE_b2 __be16
#define BE_TYPE_b4 __be32
#define BE_TYPE_b8 __be64
#define BYTES_TO_BE_TYPE(bytes) \
BE_TYPE_b##bytes
#define CAT2_(a, b) a ## b
#define CAT2(a, b) CAT2_(a, b)
#define CAT3_(a, b, c) a ## b ## c
#define CAT3(a, b, c) CAT3_(a, b, c)
/*
* enumerate the request values as
* <NAME_UPPER>_<request name> = <request value>
*/
#define REQUEST_VALUE__(name_upper, r_name) name_upper ## _ ## r_name
#define REQUEST_VALUE_(name_upper, r_name) REQUEST_VALUE__(name_upper, r_name)
#define REQUEST_VALUE(r_name) REQUEST_VALUE_(NAME_UPPER, r_name)
#include "_clear.h"
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
REQUEST_VALUE(r_name) = r_value,
enum CAT2(NAME_LOWER, _requests) {
#include REQUEST_FILE
};
/*
* For each request:
* struct <NAME_LOWER>_<request name> {
* r_fields
* };
*/
#include "_clear.h"
#define STRUCT_NAME__(name_lower, r_name) name_lower ## _ ## r_name
#define STRUCT_NAME_(name_lower, r_name) STRUCT_NAME__(name_lower, r_name)
#define STRUCT_NAME(r_name) STRUCT_NAME_(NAME_LOWER, r_name)
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
struct STRUCT_NAME(r_name) { \
r_fields \
};
#define __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
BYTES_TO_BE_TYPE(f_bytes) f_name;
#define __count_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
__field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name)
#define __array_(r_name, r_value, r_idx_1, a_offset, a_bytes, a_name) \
__u8 a_name[a_bytes];
#include REQUEST_FILE
/*
* Generate a check of the field offsets
* <NAME_LOWER>_assert_offsets_correct()
*/
#include "_clear.h"
#define REQUEST_(r_name, r_value, index, r_fields) \
r_fields
#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) \
BUILD_BUG_ON(offsetof(struct STRUCT_NAME(r_name), f_name) != f_offset);
#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
__field_(r_name, r_value, r_idx_1, c_offset, c_size, c_name)
#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) \
__field_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
static inline void CAT2(NAME_LOWER, _assert_offsets_correct)(void)
{
#include REQUEST_FILE
}
/*
* Generate event attributes:
* PMU_EVENT_ATTR_STRING(<request name>_<field name>,
* <NAME_LOWER>_event_attr_<request name>_<field name>,
* "request=<request value>"
* "starting_index=<starting index type>"
* "counter_info_version=CURRENT_COUNTER_INFO_VERSION"
* "length=<f_size>"
* "offset=<f_offset>")
*
* TODO: counter_info_version may need to vary, we should interperate the
* value to some extent
*/
#define EVENT_ATTR_NAME__(name, r_name, c_name) \
name ## _event_attr_ ## r_name ## _ ## c_name
#define EVENT_ATTR_NAME_(name, r_name, c_name) \
EVENT_ATTR_NAME__(name, r_name, c_name)
#define EVENT_ATTR_NAME(r_name, c_name) \
EVENT_ATTR_NAME_(NAME_LOWER, r_name, c_name)
#include "_clear.h"
#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
PMU_EVENT_ATTR_STRING( \
CAT3(r_name, _, c_name), \
EVENT_ATTR_NAME(r_name, c_name), \
"request=" __stringify(r_value) "," \
r_idx_1 "," \
"counter_info_version=" \
__stringify(COUNTER_INFO_VERSION_CURRENT) "," \
"length=" #c_size "," \
"offset=" #c_offset)
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
r_fields
#include REQUEST_FILE
/*
* Define event attribute array
* static struct attribute *hv_gpci_event_attrs[] = {
* &<NAME_LOWER>_event_attr_<request name>_<field name>.attr,
* };
*/
#include "_clear.h"
#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
&EVENT_ATTR_NAME(r_name, c_name).attr.attr,
#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
r_fields
static __maybe_unused struct attribute *hv_gpci_event_attrs[] = {
#include REQUEST_FILE
NULL
};
/* cleanup */
#include "_clear.h"
#undef EVENT_ATTR_NAME
#undef EVENT_ATTR_NAME_
#undef BIT_NAME
#undef BIT_NAME_
#undef STRUCT_NAME
#undef REQUEST_VALUE
#undef REQUEST_VALUE_
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment