summaryrefslogtreecommitdiff
path: root/simpleperf/event_table_generator.py
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/event_table_generator.py')
-rwxr-xr-xsimpleperf/event_table_generator.py253
1 files changed, 253 insertions, 0 deletions
diff --git a/simpleperf/event_table_generator.py b/simpleperf/event_table_generator.py
new file mode 100755
index 00000000..d7a3e1b5
--- /dev/null
+++ b/simpleperf/event_table_generator.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import dataclasses
+from dataclasses import dataclass
+import json
+import sys
+
+
+def gen_event_type_entry_str(event_type_name, event_type, event_config, description='',
+ limited_arch=''):
+ return '{"%s", %s, %s, "%s", "%s"},\n' % (
+ event_type_name, event_type, event_config, description, limited_arch)
+
+
+def gen_hardware_events():
+ hardware_configs = ["cpu-cycles",
+ "instructions",
+ "cache-references",
+ "cache-misses",
+ "branch-instructions",
+ "branch-misses",
+ "bus-cycles",
+ "stalled-cycles-frontend",
+ "stalled-cycles-backend",
+ ]
+ generated_str = ""
+ for config in hardware_configs:
+ event_type_name = config
+ event_config = "PERF_COUNT_HW_" + config.replace('-', '_').upper()
+
+ generated_str += gen_event_type_entry_str(
+ event_type_name, "PERF_TYPE_HARDWARE", event_config)
+
+ return generated_str
+
+
+def gen_software_events():
+ software_configs = ["cpu-clock",
+ "task-clock",
+ "page-faults",
+ "context-switches",
+ "cpu-migrations",
+ ["minor-faults", "PERF_COUNT_SW_PAGE_FAULTS_MIN"],
+ ["major-faults", "PERF_COUNT_SW_PAGE_FAULTS_MAJ"],
+ "alignment-faults",
+ "emulation-faults",
+ ]
+ generated_str = ""
+ for config in software_configs:
+ if isinstance(config, list):
+ event_type_name = config[0]
+ event_config = config[1]
+ else:
+ event_type_name = config
+ event_config = "PERF_COUNT_SW_" + config.replace('-', '_').upper()
+
+ generated_str += gen_event_type_entry_str(
+ event_type_name, "PERF_TYPE_SOFTWARE", event_config)
+
+ return generated_str
+
+
+def gen_hw_cache_events():
+ hw_cache_types = [["L1-dcache", "PERF_COUNT_HW_CACHE_L1D"],
+ ["L1-icache", "PERF_COUNT_HW_CACHE_L1I"],
+ ["LLC", "PERF_COUNT_HW_CACHE_LL"],
+ ["dTLB", "PERF_COUNT_HW_CACHE_DTLB"],
+ ["iTLB", "PERF_COUNT_HW_CACHE_ITLB"],
+ ["branch", "PERF_COUNT_HW_CACHE_BPU"],
+ ["node", "PERF_COUNT_HW_CACHE_NODE"],
+ ]
+ hw_cache_ops = [["loads", "load", "PERF_COUNT_HW_CACHE_OP_READ"],
+ ["stores", "store", "PERF_COUNT_HW_CACHE_OP_WRITE"],
+ ["prefetches", "prefetch",
+ "PERF_COUNT_HW_CACHE_OP_PREFETCH"],
+ ]
+ hw_cache_op_results = [["accesses", "PERF_COUNT_HW_CACHE_RESULT_ACCESS"],
+ ["misses", "PERF_COUNT_HW_CACHE_RESULT_MISS"],
+ ]
+ generated_str = ""
+ for (type_name, type_config) in hw_cache_types:
+ for (op_name_access, op_name_miss, op_config) in hw_cache_ops:
+ for (result_name, result_config) in hw_cache_op_results:
+ if result_name == "accesses":
+ event_type_name = type_name + '-' + op_name_access
+ else:
+ event_type_name = type_name + '-' + \
+ op_name_miss + '-' + result_name
+ event_config = "((%s) | (%s << 8) | (%s << 16))" % (
+ type_config, op_config, result_config)
+ generated_str += gen_event_type_entry_str(
+ event_type_name, "PERF_TYPE_HW_CACHE", event_config)
+
+ return generated_str
+
+
+@dataclass
+class RawEvent:
+ number: int
+ name: str
+ desc: str
+ limited_arch: str
+
+
+@dataclass
+class CpuModel:
+ name: str
+ implementer: int
+ partnum: int
+ supported_raw_events: list[int] = dataclasses.field(default_factory=list)
+
+
+class ArchData:
+ def __init__(self, arch: str):
+ self.arch = arch
+ self.events: List[RawEvent] = []
+ self.cpus: List[CpuModel] = []
+
+ def load_from_json_data(self, data) -> None:
+ # Load common events
+ for event in data['events']:
+ number = int(event[0], 16)
+ name = 'raw-' + event[1].lower().replace('_', '-')
+ desc = event[2]
+ self.events.append(RawEvent(number, name, desc, self.arch))
+ for cpu in data['cpus']:
+ cpu_name = cpu['name'].lower().replace('_', '-')
+ cpu_model = CpuModel(cpu['name'], int(cpu['implementer'], 16),
+ int(cpu['partnum'], 16), [])
+ cpu_index = len(self.cpus)
+ self.cpus.append(cpu_model)
+ # Load common events supported in this cpu model.
+ for number in cpu['common_events']:
+ number = int(number, 16)
+ event = self.get_event(number)
+ cpu_model.supported_raw_events.append(number)
+
+ # Load cpu specific events supported in this cpu model.
+ if 'implementation_defined_events' in cpu:
+ for event in cpu['implementation_defined_events']:
+ number = int(event[0], 16)
+ name = ('raw-' + cpu_name + '-' + event[1]).lower().replace('_', '-')
+ desc = event[2]
+ limited_arch = self.arch + ':' + cpu['name']
+ self.events.append(RawEvent(number, name, desc, limited_arch))
+ cpu_model.supported_raw_events.append(number)
+
+ def get_event(self, event_number: int) -> RawEvent:
+ for event in self.events:
+ if event.number == event_number:
+ return event
+ raise Exception(f'no event for event number {event_number}')
+
+
+class RawEventGenerator:
+ def __init__(self, event_table_file: str):
+ with open(event_table_file, 'r') as fh:
+ event_table = json.load(fh)
+ self.arm64_data = ArchData('arm64')
+ self.arm64_data.load_from_json_data(event_table['arm64'])
+
+ def generate_raw_events(self) -> str:
+ lines = []
+ for event in self.arm64_data.events:
+ lines.append(gen_event_type_entry_str(event.name, 'PERF_TYPE_RAW', '0x%x' %
+ event.number, event.desc, event.limited_arch))
+ return self.add_arm_guard(''.join(lines))
+
+ def generate_cpu_support_events(self) -> str:
+ text = """
+ // Map from cpu model to raw events supported on that cpu.',
+ std::unordered_map<std::string, std::unordered_set<int>> cpu_supported_raw_events = {
+ """
+
+ lines = []
+ for cpu in self.arm64_data.cpus:
+ event_list = ', '.join('0x%x' % number for number in cpu.supported_raw_events)
+ lines.append('{"%s", {%s}},' % (cpu.name, event_list))
+ text += self.add_arm_guard('\n'.join(lines))
+ text += '};\n'
+ return text
+
+ def generate_cpu_models(self) -> str:
+ text = """
+ std::unordered_map<uint64_t, std::string> arm64_cpuid_to_name = {
+ """
+ lines = []
+ for cpu in self.arm64_data.cpus:
+ cpu_id = (cpu.implementer << 32) | cpu.partnum
+ lines.append('{0x%xull, "%s"},' % (cpu_id, cpu.name))
+ text += '\n'.join(lines)
+ text += '};\n'
+ return self.add_arm_guard(text)
+
+ def add_arm_guard(self, data: str) -> str:
+ return f'#if defined(__aarch64__) || defined(__arm__)\n{data}\n#endif\n'
+
+
+def gen_events(event_table_file: str):
+ generated_str = """
+ #include <unordered_map>
+ #include <unordered_set>
+
+ #include "event_type.h"
+
+ namespace simpleperf {
+
+ std::set<EventType> builtin_event_types = {
+ """
+ generated_str += gen_hardware_events() + '\n'
+ generated_str += gen_software_events() + '\n'
+ generated_str += gen_hw_cache_events() + '\n'
+ raw_event_generator = RawEventGenerator(event_table_file)
+ generated_str += raw_event_generator.generate_raw_events() + '\n'
+ generated_str += """
+ };
+
+
+ """
+ generated_str += raw_event_generator.generate_cpu_support_events()
+ generated_str += raw_event_generator.generate_cpu_models()
+
+ generated_str += """
+ } // namespace simpleperf
+ """
+ return generated_str
+
+
+def main():
+ event_table_file = sys.argv[1]
+ output_file = sys.argv[2]
+ generated_str = gen_events(event_table_file)
+ with open(output_file, 'w') as fh:
+ fh.write(generated_str)
+
+
+if __name__ == '__main__':
+ main()