From e19d2715064a214220dcafa28d9cb8d101312c88 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 9 Sep 2026 20:15:18 +0000 Subject: [PATCH 1/5] ze: one table from struct to the stypes that tag it The switch that decodes a pNext chain named every enumerator it did not trace, so three of them sat in the generator as literal cases: zes's BASE_STATE and DEVICE_UUID, and each namespace's FORCE_UINT32. `default:` covers all of them, and covers the value a driver newer than our headers sends, which enumeration never could. Runtime behaviour is unchanged -- an stype with no case fell out of the switch before and breaks out of it now. The other hardcoded case was ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES_1_2, a second tag for a struct that already had one. structure_type_name derived a single enumerator from a struct's name, so the second could only be appended as a duplicate block at the bottom of the switch. Turning STRUCT_TYPE_CONVERSION_TABLE around -- from a correction to the derived name into a struct's list of stypes -- makes that a row rather than a branch: the two labels now fall through to one tracepoint, the way the itt size switch already groups its metadata types. A struct with a third stype is a longer row. Every (stype -> tracepoint) pair is unchanged, 175 of them. Co-Authored-By: Claude Opus 5 (1M context) --- backends/ze/gen_ze.rb | 26 +++++--------- backends/ze/ze_model.rb | 78 +++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/backends/ze/gen_ze.rb b/backends/ze/gen_ze.rb index ee7c24bc0..6f8cc8137 100644 --- a/backends/ze/gen_ze.rb +++ b/backends/ze/gen_ze.rb @@ -48,29 +48,21 @@ def gen_struct_printer(namespace, types) #{namespace}_structure_type_t stype = (#{namespace}_structure_type_t)((ze_base_desc_t *)p)->stype; switch (stype) { EOF - types.reject { |t| STRUCT_TYPE_REJECT.include?(t.to_s) }.each do |t| + types.each do |t| + stypes = traced_structure_type_names(t.to_s) + next if stypes.empty? + + puts stypes.map { |stype| " case #{stype}:\n" }.join puts < 'ZE_STRUCTURE_TYPE_IMAGE_MEMORY_EXP_PROPERTIES', - 'ZE_STRUCTURE_TYPE_IMAGE_PITCHED_EXP_DESC' => 'ZE_STRUCTURE_TYPE_PITCHED_IMAGE_EXP_DESC', - 'ZE_STRUCTURE_TYPE_IMAGE_BINDLESS_EXP_DESC' => 'ZE_STRUCTURE_TYPE_BINDLESS_IMAGE_EXP_DESC', - 'ZE_STRUCTURE_TYPE_DEVICE_PITCHED_ALLOC_EXP_PROPERTIES' => 'ZE_STRUCTURE_TYPE_PITCHED_ALLOC_DEVICE_EXP_PROPERTIES', - 'ZE_STRUCTURE_TYPE_CONTEXT_POWER_SAVING_HINT_EXP_DESC' => 'ZE_STRUCTURE_TYPE_POWER_SAVING_HINT_EXP_DESC', - 'ZE_STRUCTURE_TYPE_EVENT_POOL_COUNTER_BASED_EXP_DESC' => 'ZE_STRUCTURE_TYPE_COUNTER_BASED_EVENT_POOL_EXP_DESC', - 'ZE_STRUCTURE_TYPE_KERNEL_MAX_GROUP_SIZE_PROPERTIES_EXT' => 'ZE_STRUCTURE_TYPE_KERNEL_MAX_GROUP_SIZE_EXT_PROPERTIES', - 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32_HANDLE' => 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32', - 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_WIN32_HANDLE' => 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_WIN32', - 'ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_LAUNCH_KERNEL_PARAM_COOPERATIVE_DESC' => 'ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_PARAM_COOPERATIVE_DESC', - 'ZE_STRUCTURE_TYPE_DEVICE_CACHE_LINE_SIZE_EXT' => 'ZE_STRUCTURE_TYPE_DEVICE_CACHELINE_SIZE_EXT', - 'ZE_STRUCTURE_TYPE_KERNEL_ALLOCATION_EXP_PROPERTIES' => 'ZE_STRUCTURE_TYPE_KERNEL_ALLOCATION_PROPERTIES', - 'ZET_STRUCTURE_TYPE_EXPORT_DMA_BUF_EXP_PROPERTIES' => 'ZET_STRUCTURE_TYPE_EXPORT_DMA_EXP_PROPERTIES', - 'ZES_STRUCTURE_TYPE_MEM_PAGE_OFFLINE_STATE_EXP' => 'ZES_STRUCTURE_TYPE_MEMORY_PAGE_OFFLINE_STATE_EXP', -} +# The stypes of a struct whose name does not spell them. Every entry replaces +# the derived name outright, so a struct the spec renamed has one row and a +# struct the spec gave a second stype lists both. +STRUCT_TYPES = { + 'ze_image_memory_properties_exp_t' => %w[ZE_STRUCTURE_TYPE_IMAGE_MEMORY_EXP_PROPERTIES], + 'ze_image_pitched_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_PITCHED_IMAGE_EXP_DESC], + 'ze_image_bindless_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_BINDLESS_IMAGE_EXP_DESC], + 'ze_device_pitched_alloc_exp_properties_t' => %w[ZE_STRUCTURE_TYPE_PITCHED_ALLOC_DEVICE_EXP_PROPERTIES], + 'ze_context_power_saving_hint_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_POWER_SAVING_HINT_EXP_DESC], + 'ze_event_pool_counter_based_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_COUNTER_BASED_EVENT_POOL_EXP_DESC], + 'ze_kernel_max_group_size_properties_ext_t' => %w[ZE_STRUCTURE_TYPE_KERNEL_MAX_GROUP_SIZE_EXT_PROPERTIES], + 'ze_external_memory_import_win32_handle_t' => %w[ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32], + 'ze_external_memory_export_win32_handle_t' => %w[ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_WIN32], + 'ze_command_list_append_launch_kernel_param_cooperative_desc_t' => + %w[ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_PARAM_COOPERATIVE_DESC], + 'ze_device_cache_line_size_ext_t' => %w[ZE_STRUCTURE_TYPE_DEVICE_CACHELINE_SIZE_EXT], + 'ze_kernel_allocation_exp_properties_t' => %w[ZE_STRUCTURE_TYPE_KERNEL_ALLOCATION_PROPERTIES], + 'ze_device_properties_t' => %w[ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES + ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES_1_2], + 'zet_export_dma_buf_exp_properties_t' => %w[ZET_STRUCTURE_TYPE_EXPORT_DMA_EXP_PROPERTIES], + 'zes_mem_page_offline_state_exp_t' => %w[ZES_STRUCTURE_TYPE_MEMORY_PAGE_OFFLINE_STATE_EXP], +}.freeze -# Structs whose stype tag is not a member of ze_structure_type_t. -# -# - zex tags structures with a uint32_t alias (level_zero/ze_stypes.h) rather -# than an enum, we don't handle that. -# - zet_metric_source_id_exp_t's tag is simply absent from the spec. -STRUCT_TYPE_REJECT = Set.new(%w[zet_metric_source_id_exp_t - zex_device_module_register_file_exp_t]) - -# The ze_structure_type_t enumerator that tags `name`, a struct typedef such as -# ze_device_properties_t -> ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES. +# Every enumerator name the traced namespaces declare. +ENUMERATORS = APIS.values.flat_map(&:enums).flat_map(&:members).map(&:name).to_set + +# The stypes that tag `name` and that the spec really declares: what the tracer +# dispatches on, and what a Ruby class stamps into its initializer. # -# The tracer switches on this to pick a tracepoint, and the Ruby bindings stamp -# it into the struct's initializer; the two have to name the same enumerator or -# a struct is traced under a tag its class never sets. So it is derived here -# once, from the struct name, rather than recomputed on each side. +# A struct usually spells its own single stype. STRUCT_TYPES holds the ones it +# does not, and a name the spec never declares drops out -- the _base_ +# headers are tagged by nothing, and zex tags its structs with a uint32_t. # -# A handful of enumerators do not follow the rule -- the spec renamed them after -# the struct was named -- and the table has the last word. -def structure_type_name(name) +# >> traced_structure_type_names('ze_context_desc_t') +# => ["ZE_STRUCTURE_TYPE_CONTEXT_DESC"] +# >> traced_structure_type_names('ze_image_pitched_exp_desc_t') # spec renamed it +# => ["ZE_STRUCTURE_TYPE_PITCHED_IMAGE_EXP_DESC"] +# >> traced_structure_type_names('ze_device_properties_t') # two stypes +# => ["ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES", "ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES_1_2"] +# >> traced_structure_type_names('ze_base_desc_t') +# => [] +# >> traced_structure_type_names('zex_device_module_register_file_exp_t') +# => [] +def traced_structure_type_names(name) namespace = name[/\A[a-z]+/] - tag = "#{namespace}_STRUCTURE_TYPE_#{name.delete_prefix("#{namespace}_").delete_suffix('_t')}".upcase - STRUCT_TYPE_CONVERSION_TABLE.fetch(tag, tag) + derived = "#{namespace}_STRUCTURE_TYPE_#{name.delete_prefix("#{namespace}_").delete_suffix('_t')}".upcase + STRUCT_TYPES.fetch(name, [derived]).select { |stype| ENUMERATORS.include?(stype) } end # Each namespace declares its meta-parameters in its own file, so the list From c0f02f8190b17c707ff3f76f4bb8a451e7258c20 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 9 Sep 2026 20:15:30 +0000 Subject: [PATCH 2/5] ze: stamp an stype only where the spec declares one ZE::ZEBaseDesc.new raised `ArgumentError: invalid enum value, :ZE_STRUCTURE_TYPE_BASE_DESC`, and so did eight sibling classes. The generated initializer stamps the stype derived from the struct's name into every struct whose first member is `stype`, without checking the spec declares that enumerator. The _base_ headers have the member but no tag of their own -- they are what the concrete descriptors are built on -- so FFI rejected the symbol and the class could not be constructed at all. The hand-written STRUCT_TYPE_REJECT was meant to hold these. It named two structs where eleven qualify, and the nine it missed are exactly the nine that raised. Asking traced_structure_type_names, which answers from the enum, replaces the list and closes the gap it left. Affected: ZEBaseCbParams, ZEBaseProperties, ZEBaseDesc, ZETBaseProperties, ZETBaseDesc, ZESBaseProperties, ZESBaseDesc, ZESBaseConfig, ZESBaseCapability. Each constructs now; none carries a tag, which is right, since nothing tags them. ze_library.rb loses those nine initializers and nothing else. Co-Authored-By: Claude Opus 5 (1M context) --- backends/ze/gen_ze_library.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/ze/gen_ze_library.rb b/backends/ze/gen_ze_library.rb index 6d52cb2b6..eaad2a925 100644 --- a/backends/ze/gen_ze_library.rb +++ b/backends/ze/gen_ze_library.rb @@ -213,7 +213,7 @@ def print_struct(name, struct) prepends << 'Handle' end - if struct.to_ffi(NAMING).first[0] == ':stype' && !STRUCT_TYPE_REJECT.include?(name) + if struct.to_ffi(NAMING).first[0] == ':stype' && !traced_structure_type_names(name).empty? initializer = < Date: Wed, 9 Sep 2026 20:15:45 +0000 Subject: [PATCH 3/5] xprof: trace the chained structs on --tracing-mode full The tracer walks a call's pNext chain only when LTTNG_UST_ZE_CHAINED_STRUCTS is set, and the events it fires there belong to the lttng_ust__structs providers, which no tracing mode enabled. Between them that put the chain out of iprof's reach entirely: the extension structs a program passes were traced by tracer_ze.sh --structs and by nothing else. `full` now sets the variable and enables the five providers. minimal and default are untouched, so the per-struct tracepoint cost stays opt-in. The tally is unaffected: a struct event matches no tally rule, and the function set and call counts are identical in both modes. Co-Authored-By: Claude Opus 5 (1M context) --- xprof/xprof.rb.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xprof/xprof.rb.in b/xprof/xprof.rb.in index 48d5acfab..62d19453a 100755 --- a/xprof/xprof.rb.in +++ b/xprof/xprof.rb.in @@ -542,6 +542,12 @@ def enable_events_ze(channel_name, tracing_mode: 'default', profiling: true) exec("#{lttng_enable} lttng_ust_zer:*") exec("#{lttng_enable} lttng_ust_zet:*") exec("#{lttng_enable} lttng_ust_zex:*") + # The structs carried on a call's pNext chain. zer has no struct provider. + exec("#{lttng_enable} lttng_ust_ze_structs:*") + exec("#{lttng_enable} lttng_ust_zes_structs:*") + exec("#{lttng_enable} lttng_ust_zet_structs:*") + exec("#{lttng_enable} lttng_ust_zel_structs:*") + exec("#{lttng_enable} lttng_ust_zex_structs:*") when 'default' # Wildcard using the * character are supported at the end of tracepoint names. # https://lttng.org/man/1/lttng-enable-event/v2.8/#doc-_understanding_event_rule_conditions @@ -923,6 +929,8 @@ def all_env_tracers(usr_binary) # Customization if OPTIONS[:'backend-names'].include?('ze') h['LTTNG_UST_ZE_PARANOID_DRIFT'] = 1 if OPTIONS[:profile] + # Walk pNext only on full. + h['LTTNG_UST_ZE_CHAINED_STRUCTS'] = 1 if OPTIONS[:'tracing-mode'] == 'full' if SamplingDaemon.active? # The current only reliable way to use zes api # is to call zesInit and set ZES_ENABLE_SYSMAN to 0 From af2e467e4a7561ecd1540f20310a94e6d3c46e3b Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 9 Sep 2026 20:31:37 +0000 Subject: [PATCH 4/5] ze: point the header-update guide at the table that replaced two Both names the README tells a maintainer to edit are gone: $struct_type_reject, and struct_type_conversion_table which is now STRUCT_TYPES keyed the other way round. The zex step went with the first of those. A struct tagged by a ZEX_STRUCTURE_* macro used to need a reject entry or gen_ze_library raised; traced_structure_type_names now keeps only the stypes the spec declares, so such a struct drops out on its own and there is nothing to write down -- verified against zex_device_module_register_file_exp_t, which has a Ruby class, no stype stamped in it, and no case in the tracer's switch. That leaves one manual change when transcribing zex, not two. The naming-inconsistency section gains the other thing that table now answers: a struct the spec tags with two enumerators lists both. Co-Authored-By: Claude Opus 5 (1M context) --- backends/ze/README.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/backends/ze/README.md b/backends/ze/README.md index 7b6240447..02266fdf2 100644 --- a/backends/ze/README.md +++ b/backends/ze/README.md @@ -103,17 +103,11 @@ $ diff <(grep -ho 'zex[A-Za-z]*(' /usr/include/level_zero/driver_experimental/*. <(grep -o 'zex[A-Za-z]*(' include/zex_api.h | tr -d '(' | sort -u) ``` -- Two manual changes when transcribing: - - - Spell `zex_command_list_handle_t` / `zex_event_handle_t` as their `ze_` - originals (they are plain typedefs of them). One type must have one name: - metababel dispatches on field name plus type, and a field such as - `hSignalEvent` carrying both spellings is a conflicting signature. - - - zex tags its structs with `ZEX_STRUCTURE_*` macros, not with members of - `ze_structure_type_t`. The generated bindings can only name an enum member, - so such a struct goes in `$struct_type_reject` in `ze_model.rb`; otherwise - `gen_ze_library.rb` raises `Unrecognized namespace`. +- One manual change when transcribing: spell `zex_command_list_handle_t` / + `zex_event_handle_t` as their `ze_` originals (they are plain typedefs of + them). One type must have one name: metababel dispatches on field name plus + type, and a field such as `hSignalEvent` carrying both spellings is a + conflicting signature. ## Now Try to Compile: @@ -169,7 +163,11 @@ tracer_ze.c:197:8: error: use of undeclared identifier 'ZE_STRUCTURE_TYPE_DEVICE | ZE_STRUCTURE_TYPE_DEVICE_CACHELINE_SIZE_EXT ``` -Due to Intel's lack of naming consistency, you may need to update the `struct_type_conversion_table` in `ze_model.rb`. +Due to Intel's lack of naming consistency, you may need to add a row to +`STRUCT_TYPES` in `ze_model.rb`, which maps a struct to the stypes that tag it. +The same table is where a struct tagged by *two* enumerators goes -- list both, +and the switch gives them one case each falling through to one tracepoint (see +`ze_device_properties_t`). ## 2 From 915259b5d42b87c429732baaad064082d7a17c77 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 9 Sep 2026 23:25:15 +0000 Subject: [PATCH 5/5] ze: emit a struct tracepoint only where an stype can select it The tracer reaches a struct tracepoint one way: it casts the void * to ze_base_desc_t *, reads ->stype, and switches on it. So a struct that no declared enumerator tags can never be selected, whatever is emitted for it. Three consumers disagreed about which structs count. The .tp emitters took every tagged struct (186), the babeltrace model rejected `_base_` by name (176), and the switch kept only what an stype names (174). The name check was a convention standing in for that last fact, and it was wrong about zes_base_state_t: the spec does declare ZES_STRUCTURE_TYPE_BASE_STATE, which is why the generator carried a hand-written empty case for it. traced_structs now asks the question the tracer asks, and all three agree on 175. Eleven tracepoints go: nine `_base_` chain headers, which are the stype field rather than a thing it selects, plus zet_metric_source_id_exp_t (the spec omits its tag) and zex_device_module_register_file_exp_t (zex tags with a uint32_t alias). That is -132 lines across four .tp files and two event classes out of btx_ze_model.yaml. zes_base_state_t goes the other way: it is traced now instead of dispatched to an empty case, +3 lines in tracer_ze.c and one event class back. Function tracepoints are untouched -- 468 in ze_tracepoints.tp before and after. Checked on a Max 1550: tracer_ze.sh --structs emits the same 46 events with the same 2 struct payloads before and after, and the ze suite passes 9/9. Co-Authored-By: Claude Opus 5 (1M context) --- backends/ze/gen_babeltrace_ze_model.rb | 2 +- backends/ze/gen_ze.rb | 15 ++++----- backends/ze/gen_ze_structs_tracepoints.rb | 2 +- backends/ze/gen_zel_structs_tracepoints.rb | 2 +- backends/ze/gen_zer_structs_tracepoints.rb | 2 +- backends/ze/gen_zes_structs_tracepoints.rb | 2 +- backends/ze/gen_zet_structs_tracepoints.rb | 2 +- backends/ze/gen_zex_structs_tracepoints.rb | 2 +- backends/ze/ze_model.rb | 37 +++++++++++----------- 9 files changed, 32 insertions(+), 34 deletions(-) diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index 7576ad86b..61eaf0a7e 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -20,7 +20,7 @@ def gen_struct_event_bt_model(registry, provider, struct) # struct's bytes; no other backend has these. def struct_event_classes(registry) APIS.collect do |ns, api| - concrete_tagged_structs(ns, api).collect do |struct| + traced_structs(api).collect do |struct| gen_struct_event_bt_model(registry, :"lttng_ust_#{ns}_structs", struct) end end.flatten diff --git a/backends/ze/gen_ze.rb b/backends/ze/gen_ze.rb index 6f8cc8137..e220669dd 100644 --- a/backends/ze/gen_ze.rb +++ b/backends/ze/gen_ze.rb @@ -49,18 +49,17 @@ def gen_struct_printer(namespace, types) switch (stype) { EOF types.each do |t| - stypes = traced_structure_type_names(t.to_s) - next if stypes.empty? - - puts stypes.map { |stype| " case #{stype}:\n" }.join + puts traced_structure_type_names(t.to_s).map { |stype| " case #{stype}:\n" }.join puts <_STRUCTURE_TYPE_FORCE_UINT32), an abstract base, a value from a driver + # newer than our headers, or a tag whose struct cannot be decoded from a + # `void *` at all -- ZES_STRUCTURE_TYPE_DEVICE_UUID names zes_uuid_t, which + # is a bare byte array with no stype member to have been read here. puts <<~EOF default: break; @@ -78,7 +77,7 @@ def gen_struct_printer(namespace, types) EOF end -struct_types = APIS.to_h { |ns, api| [ns, concrete_tagged_structs(ns, api)] } +struct_types = APIS.to_h { |ns, api| [ns, traced_structs(api)] } gen_struct_printer(:ze, struct_types[:ze]) gen_struct_printer(:zet, struct_types[:zet]) diff --git a/backends/ze/gen_ze_structs_tracepoints.rb b/backends/ze/gen_ze_structs_tracepoints.rb index 5316a8334..98d670fbf 100644 --- a/backends/ze/gen_ze_structs_tracepoints.rb +++ b/backends/ze/gen_ze_structs_tracepoints.rb @@ -1,5 +1,5 @@ require_relative 'ze_model' require_relative '../../utils/gen_probe_base' -print_struct_tracepoint_provider(:lttng_ust_ze_structs, tagged_structs(APIS[:ze]), +print_struct_tracepoint_provider(:lttng_ust_ze_structs, traced_structs(APIS[:ze]), include: '#include "ze.h.include"') diff --git a/backends/ze/gen_zel_structs_tracepoints.rb b/backends/ze/gen_zel_structs_tracepoints.rb index 00d50ce19..2b817cc5c 100644 --- a/backends/ze/gen_zel_structs_tracepoints.rb +++ b/backends/ze/gen_zel_structs_tracepoints.rb @@ -1,5 +1,5 @@ require_relative 'ze_model' require_relative '../../utils/gen_probe_base' -print_struct_tracepoint_provider(:lttng_ust_zel_structs, tagged_structs(APIS[:zel]), +print_struct_tracepoint_provider(:lttng_ust_zel_structs, traced_structs(APIS[:zel]), include: '#include "ze.h.include"') diff --git a/backends/ze/gen_zer_structs_tracepoints.rb b/backends/ze/gen_zer_structs_tracepoints.rb index 8d8dd58bb..6248ad4d1 100644 --- a/backends/ze/gen_zer_structs_tracepoints.rb +++ b/backends/ze/gen_zer_structs_tracepoints.rb @@ -1,5 +1,5 @@ require_relative 'ze_model' require_relative '../../utils/gen_probe_base' -print_struct_tracepoint_provider(:lttng_ust_zer_structs, tagged_structs(APIS[:zer]), +print_struct_tracepoint_provider(:lttng_ust_zer_structs, traced_structs(APIS[:zer]), include: '#include "ze.h.include"') diff --git a/backends/ze/gen_zes_structs_tracepoints.rb b/backends/ze/gen_zes_structs_tracepoints.rb index 28bee1889..0d9fc34a3 100644 --- a/backends/ze/gen_zes_structs_tracepoints.rb +++ b/backends/ze/gen_zes_structs_tracepoints.rb @@ -1,5 +1,5 @@ require_relative 'ze_model' require_relative '../../utils/gen_probe_base' -print_struct_tracepoint_provider(:lttng_ust_zes_structs, tagged_structs(APIS[:zes]), +print_struct_tracepoint_provider(:lttng_ust_zes_structs, traced_structs(APIS[:zes]), include: '#include "ze.h.include"') diff --git a/backends/ze/gen_zet_structs_tracepoints.rb b/backends/ze/gen_zet_structs_tracepoints.rb index 722a5e563..18a4077f5 100644 --- a/backends/ze/gen_zet_structs_tracepoints.rb +++ b/backends/ze/gen_zet_structs_tracepoints.rb @@ -1,5 +1,5 @@ require_relative 'ze_model' require_relative '../../utils/gen_probe_base' -print_struct_tracepoint_provider(:lttng_ust_zet_structs, tagged_structs(APIS[:zet]), +print_struct_tracepoint_provider(:lttng_ust_zet_structs, traced_structs(APIS[:zet]), include: '#include "ze.h.include"') diff --git a/backends/ze/gen_zex_structs_tracepoints.rb b/backends/ze/gen_zex_structs_tracepoints.rb index b2a13c546..6482b32b8 100644 --- a/backends/ze/gen_zex_structs_tracepoints.rb +++ b/backends/ze/gen_zex_structs_tracepoints.rb @@ -1,5 +1,5 @@ require_relative 'ze_model' require_relative '../../utils/gen_probe_base' -print_struct_tracepoint_provider(:lttng_ust_zex_structs, tagged_structs(APIS[:zex]), +print_struct_tracepoint_provider(:lttng_ust_zex_structs, traced_structs(APIS[:zex]), include: '#include "ze.h.include"') diff --git a/backends/ze/ze_model.rb b/backends/ze/ze_model.rb index ed15e5d71..f40f3a6cf 100644 --- a/backends/ze/ze_model.rb +++ b/backends/ze/ze_model.rb @@ -13,25 +13,6 @@ zex: ApiModel.load_file('zex_api.yaml'), }.freeze -# A struct tagged with its own type is one the tracer can decode from a -# `void *` at runtime, which is what makes it worth its own tracepoint. -STRUCT_TYPE_TAG = 'stype' - -def tagged_structs(api) - api.types.select do |t| - t.type.is_a?(YAMLCAst::Struct) && - (struct = api.struct_named(t.type.name)) && - struct.members.first.name == STRUCT_TYPE_TAG - end.map(&:name) -end - -# Those a caller can be handed. The `_base_` types are the tag's own base -# classes: a tracepoint exists for each, but no API call ever passes one, so -# nothing dispatches on them. -def concrete_tagged_structs(namespace, api) - tagged_structs(api).reject { |n| n.start_with?("#{namespace}_base_") }.to_set -end - # Every namespace as one API, the same thing `API` names in every other # backend. The derivations have to see all of them at once: a zet typedef # routinely names a ze struct. @@ -93,6 +74,24 @@ def traced_structure_type_names(name) STRUCT_TYPES.fetch(name, [derived]).select { |stype| ENUMERATORS.include?(stype) } end +# The member every chained struct leads with, naming its own type. It is what +# lets the tracer decode one from a `void *` at runtime. +STRUCT_TYPE_TAG = 'stype' + +# The structs a namespace traces: the ones that carry the stype tag, and that +# a declared stype actually names. The tracer only ever reaches a tracepoint by +# switching on the stype it read, so a struct no enumerator names could never +# fire -- the `_base_` chain headers, which are the tag rather than a thing +# it selects, and the two the spec tags with nothing we can switch on. +def traced_structs(api) + api.types.select do |t| + t.type.is_a?(YAMLCAst::Struct) && + (struct = api.struct_named(t.type.name)) && + struct.members.first.name == STRUCT_TYPE_TAG && + !traced_structure_type_names(t.name).empty? + end.map(&:name).to_set +end + # Each namespace declares its meta-parameters in its own file, so the list # follows APIS rather than restating it. zer's file exists but stays out until # zer has a generated api.yaml to match it against.