aboutsummaryrefslogtreecommitdiffstats
path: root/misc
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2024-02-14 09:09:14 -0800
committerGitHub <noreply@github.com>2024-02-14 09:09:14 -0800
commit7177731282bea651385818076d4fa6b9bdf717c0 (patch)
tree9eeb8c2f612148486d8fd79d360a233eb5cbefff /misc
parentee3b4bec0ead8cef949a992df46ef8b237ed4a26 (diff)
downloadruby-7177731282bea651385818076d4fa6b9bdf717c0.tar.gz
YJIT: Add --yjit-perf=codegen option (#9957)
Diffstat (limited to 'misc')
-rw-r--r--misc/yjit_perf.py96
1 files changed, 96 insertions, 0 deletions
diff --git a/misc/yjit_perf.py b/misc/yjit_perf.py
new file mode 100644
index 0000000000..44c232254e
--- /dev/null
+++ b/misc/yjit_perf.py
@@ -0,0 +1,96 @@
+import os
+import sys
+from collections import Counter, defaultdict
+import os.path
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+from perf_trace_context import *
+from EventClass import *
+
+# Aggregating cycles per symbol and dso
+total_cycles = 0
+category_cycles = Counter()
+detailed_category_cycles = defaultdict(Counter)
+categories = set()
+
+def truncate_symbol(symbol, max_length=50):
+ """ Truncate the symbol name to a maximum length """
+ return symbol if len(symbol) <= max_length else symbol[:max_length-3] + '...'
+
+def categorize_symbol(dso, symbol):
+ """ Categorize the symbol based on the defined criteria """
+ if dso == 'sqlite3_native.so':
+ return '[sqlite3]'
+ elif 'SHA256' in symbol:
+ return '[sha256]'
+ elif symbol.startswith('[JIT] gen_send'):
+ return '[JIT send]'
+ elif symbol.startswith('[JIT]'):
+ return '[JIT code]'
+ elif '::' in symbol or symbol.startswith('yjit::') or symbol.startswith('_ZN4yjit'):
+ return '[YJIT compile]'
+ elif symbol.startswith('rb_vm_') or symbol.startswith('vm_') or symbol in {
+ "rb_call0", "callable_method_entry_or_negative", "invoke_block_from_c_bh",
+ "rb_funcallv_scope", "setup_parameters_complex", "rb_yield"}:
+ return '[interpreter]'
+ elif symbol.startswith('rb_hash_') or symbol.startswith('hash_'):
+ return '[rb_hash_*]'
+ elif symbol.startswith('rb_ary_') or symbol.startswith('ary_'):
+ return '[rb_ary_*]'
+ elif symbol.startswith('rb_str_') or symbol.startswith('str_'):
+ return '[rb_str_*]'
+ elif symbol.startswith('rb_sym') or symbol.startswith('sym_'):
+ return '[rb_sym_*]'
+ elif symbol.startswith('rb_st_') or symbol.startswith('st_'):
+ return '[rb_st_*]'
+ elif symbol.startswith('rb_ivar_') or 'shape' in symbol:
+ return '[ivars]'
+ elif 'match' in symbol or symbol.startswith('rb_reg') or symbol.startswith('onig'):
+ return '[regexp]'
+ elif 'alloc' in symbol or 'free' in symbol or 'gc' in symbol:
+ return '[GC]'
+ elif 'pthread' in symbol and 'lock' in symbol:
+ return '[pthread lock]'
+ else:
+ return symbol # Return the symbol itself for uncategorized symbols
+
+def process_event(event):
+ global total_cycles, category_cycles, detailed_category_cycles, categories
+
+ sample = event["sample"]
+ full_dso = event.get("dso", "Unknown_dso")
+ dso = os.path.basename(full_dso)
+ symbol = event.get("symbol", "[unknown]")
+ cycles = sample["period"]
+ total_cycles += cycles
+
+ category = categorize_symbol(dso, symbol)
+ category_cycles[category] += cycles
+ detailed_category_cycles[category][(dso, symbol)] += cycles
+
+ if category.startswith('[') and category.endswith(']'):
+ categories.add(category)
+
+def trace_end():
+ if total_cycles == 0:
+ return
+
+ print("Aggregated Event Data:")
+ print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol or category]", "[top-most cycle ratio]", "[num cycles]"))
+
+ for category, cycles in category_cycles.most_common():
+ ratio = (cycles / total_cycles) * 100
+ dsos = {dso for dso, _ in detailed_category_cycles[category]}
+ dso_display = next(iter(dsos)) if len(dsos) == 1 else "Multiple DSOs"
+ print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso_display, truncate_symbol(category), ratio, cycles))
+
+ # Category breakdown
+ for category in categories:
+ symbols = detailed_category_cycles[category]
+ category_total = sum(symbols.values())
+ category_ratio = (category_total / total_cycles) * 100
+ print(f"\nCategory: {category} ({category_ratio:.2f}%)")
+ print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol]", "[top-most cycle ratio]", "[num cycles]"))
+ for (dso, symbol), cycles in symbols.most_common():
+ symbol_ratio = (cycles / category_total) * 100
+ print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso, truncate_symbol(symbol), symbol_ratio, cycles))