From 80a40261210da48c841fb0a8f13b551a6060f0af Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 29 Jul 2026 18:42:13 +0000 Subject: [PATCH 01/26] opencl: unify tracepoint printing with shared utils/LTTng.rb opencl_tracepoints.rb defined its own class LTTng with duplicate print_tracepoint/print_enum logic, parallel to the shared utils/LTTng.rb module used by every other (AST-driven) backend. Since a bare `class LTTng` cannot coexist with utils/LTTng.rb's `module LTTng` (Ruby raises TypeError: LTTng is not a class), rename opencl's local tuple-parsing helper to `module LTTngFieldTuple` and drop its now-redundant print_tracepoint/print_enum, routing gen_opencl_probes.rb's two call sites through the shared LTTng.print_tracepoint instead. Also drop opencl_model.rb's duplicate MEMBER_SEPARATOR constant now that utils/LTTng.rb (required transitively via opencl_tracepoints.rb) defines the same value, eliminating a "already initialized constant" warning. Verified byte-identical against devel for opencl_tracepoints.tp, opencl_profiling.tp, opencl_model.yaml, btx_cl_model.yaml, and the remaining opencl_*.tp files, via direct diff and via utils/test_compare_generated_file.py (THAPI_FILTER=opencl). gen_babeltrace_cl_model.rb's parse_field was left unmerged with utils/gen_babeltrace_model_helper.rb's gen_bt_field_model: the latter depends on $types_by_name/$all_enum_names/$all_bitfield_names/ $all_struct_names/$integer_sizes/$integer_signed, all populated only by each AST backend's gen_*_library_base.rb from a parsed C AST. Opencl has no such AST pass (it parses cl.xml into OPENCL_MODEL instead), so building an equivalent global-population pipeline just to reuse gen_bt_field_model would be a large, unverifiable-by-byte-diff architectural addition. Left as documented partial unification (the existing shared gen_yaml call is retained). Co-Authored-By: Claude Opus 4.8 --- backends/opencl/gen_opencl_model.rb | 22 ++++----- backends/opencl/gen_opencl_probes.rb | 4 +- backends/opencl/opencl_model.rb | 3 +- backends/opencl/opencl_tracepoints.rb | 67 ++++++--------------------- 4 files changed, 27 insertions(+), 69 deletions(-) diff --git a/backends/opencl/gen_opencl_model.rb b/backends/opencl/gen_opencl_model.rb index d691bd97f..85910f444 100644 --- a/backends/opencl/gen_opencl_model.rb +++ b/backends/opencl/gen_opencl_model.rb @@ -66,7 +66,7 @@ c.parameters.select { |p| p.lttng_in_type }.each do |p| field = {} lttng = p.lttng_in_type - fname = LTTng.name(*lttng) + fname = LTTngFieldTuple.name(*lttng) field.merge!(params[fname]) field['lttng'] = lttng[0] fields[fname] = field @@ -74,21 +74,21 @@ c.meta_parameters.select { |p| p.lttng_in_type }.each do |p| meta_field = {} lttng = p.lttng_in_type - fname = LTTng.name(*lttng) + fname = LTTngFieldTuple.name(*lttng) if fname == 'errcode_ret_val' meta_field['type'] = 'cl_errcode' elsif fname.match(/_val\z/) pname = fname.gsub(/_val\z/, '') meta_field['type'] = params[pname]['type'] else - meta_field['type'] = params[LTTng.expression(*lttng)]['type'] + meta_field['type'] = params[LTTngFieldTuple.expression(*lttng)]['type'] end if meta_field['type'].match(/\*\z/) meta_field['type'] = meta_field['type'].sub(/\*\z/, '') meta_field['pointer'] = true end - meta_field['array'] = true if LTTng.array?(*lttng) - meta_field['string'] = true if LTTng.string?(*lttng) + meta_field['array'] = true if LTTngFieldTuple.array?(*lttng) + meta_field['string'] = true if LTTngFieldTuple.string?(*lttng) meta_field['lttng'] = lttng[0] meta_field['length'] = lttng[4] if meta_field['lttng'].match('ctf_array') if meta_field['array'] && @@ -105,14 +105,14 @@ field['type'] = c.prototype.return_type lttng = c.prototype.lttng_return_type field['lttng'] = lttng[0] - fname = LTTng.name(*lttng) + fname = LTTngFieldTuple.name(*lttng) field['type'] = 'cl_errcode' if fname == 'errcode_ret_val' fields[fname] = field end - c.meta_parameters.select { |p| p.lttng_out_type && LTTng.name(*p.lttng_out_type) != '_param_name' }.each do |p| + c.meta_parameters.select { |p| p.lttng_out_type && LTTngFieldTuple.name(*p.lttng_out_type) != '_param_name' }.each do |p| meta_field = {} lttng = p.lttng_out_type - fname = LTTng.name(*lttng) + fname = LTTngFieldTuple.name(*lttng) if fname == 'errcode_ret_val' meta_field['type'] = 'cl_errcode' elsif fname.match(/_val\z/) @@ -120,7 +120,7 @@ meta_field['type'] = params[pname]['type'] else begin - meta_field['type'] = params[LTTng.expression(*lttng)]['type'] + meta_field['type'] = params[LTTngFieldTuple.expression(*lttng)]['type'] rescue StandardError warn name, lttng.inspect end @@ -129,8 +129,8 @@ meta_field['type'] = meta_field['type'].gsub(/\*\z/, '') meta_field['pointer'] = true end - meta_field['array'] = true if LTTng.array?(*lttng) - meta_field['string'] = true if LTTng.string?(*lttng) + meta_field['array'] = true if LTTngFieldTuple.array?(*lttng) + meta_field['string'] = true if LTTngFieldTuple.string?(*lttng) meta_field['lttng'] = lttng[0] meta_field['length'] = lttng[4] if meta_field['lttng'].match('ctf_array') if meta_field['array'] && diff --git a/backends/opencl/gen_opencl_probes.rb b/backends/opencl/gen_opencl_probes.rb index 4fdd608ef..fd3cd26f6 100644 --- a/backends/opencl/gen_opencl_probes.rb +++ b/backends/opencl/gen_opencl_probes.rb @@ -82,7 +82,7 @@ end event[dir] = fields - print_tracepoint('lttng_ust_opencl', event, dir) + LTTng.print_tracepoint('lttng_ust_opencl', event, dir) } $opencl_commands.each do |c| @@ -105,6 +105,6 @@ callbacks = YAML.load_file(File.join(SRC_DIR, 'opencl_wrapper_events.yaml'))[namespace] callbacks['events'].each do |e| %w[start stop].each do |dir| - print_tracepoint(namespace, e, dir) + LTTng.print_tracepoint(namespace, e, dir) end end diff --git a/backends/opencl/opencl_model.rb b/backends/opencl/opencl_model.rb index 0a6574f4b..a68078349 100644 --- a/backends/opencl/opencl_model.rb +++ b/backends/opencl/opencl_model.rb @@ -1,5 +1,6 @@ require 'nokogiri' require 'yaml' +require_relative '../../utils/LTTng' SRC_DIR = ENV['SRC_DIR'] || '.' @@ -7,8 +8,6 @@ STOP = 'exit' SUFFIXES = { 'start' => START, 'stop' => STOP } -MEMBER_SEPARATOR = '__' - GENERATE_ENUMS_TRACEPOINTS = false HOST_PROFILE = true diff --git a/backends/opencl/opencl_tracepoints.rb b/backends/opencl/opencl_tracepoints.rb index d657b09ca..85e4d3b0d 100644 --- a/backends/opencl/opencl_tracepoints.rb +++ b/backends/opencl/opencl_tracepoints.rb @@ -1,4 +1,11 @@ -class LTTng +require_relative '../../utils/LTTng' + +# Opencl's model is YAML-intermediate-driven (see gen_opencl_model.rb), so its +# tracepoint fields travel as raw [macro, *args] tuples rather than as +# utils/LTTng.rb's TracepointField objects. LTTngFieldTuple provides the same +# kind of accessors (name/array?/string?/enum?/expression) over that tuple +# representation. +module LTTngFieldTuple def self.name(*args) case args[0] when 'ctf_string' @@ -34,64 +41,16 @@ def self.expression(*args) end end -def print_enum(namespace, en) - puts <<~EOF - TRACEPOINT_ENUM( - #{namespace}, - #{en['name']}, - TP_ENUM_VALUES( - EOF - print ' ' - puts en['values'].collect { |(f, sy, *args)| - "#{f}(#{sy.to_s.inspect}, #{args.join(', ')})" - }.join("\n ") - puts <<~EOF - ) - ) - - EOF -end - -def print_tracepoint(namespace, tp, dir = nil) - puts <<~EOF - TRACEPOINT_EVENT( - #{namespace}, - #{tp['name']}#{"_#{SUFFIXES[dir]}" if dir}, - TP_ARGS( - EOF - print ' ' - args = tp['args'] - if args.empty? - puts 'void' - else - puts args.collect { |a| a.join(', ') }.join(",\n ") - end - puts < Date: Wed, 29 Jul 2026 18:42:13 +0000 Subject: [PATCH 02/26] test: add opencl_tracepoints.tp to generated-file comparison oracle utils/test_compare_generated_file.py compared opencl_profiling.tp but not opencl_tracepoints.tp, the main opencl tracepoint output. Add it to the opencl file list so CI's check-same-generated-files job actually covers the file the opencl unification refactor touches. Verified: rerunning pytest with THAPI_FILTER=opencl against a clean devel baseline build and this branch's build still passes (2 passed, empty DeepDiff). Co-Authored-By: Claude Opus 4.8 --- utils/test_compare_generated_file.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/test_compare_generated_file.py b/utils/test_compare_generated_file.py index 02b31f671..0c50749a2 100644 --- a/utils/test_compare_generated_file.py +++ b/utils/test_compare_generated_file.py @@ -69,6 +69,7 @@ ] filenames += [ + "backends/opencl/opencl_tracepoints.tp", "backends/opencl/opencl_profiling.tp", ] From bfa9652829e4040771141a44c2b22ec5b82252a1 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 29 Jul 2026 18:49:17 +0000 Subject: [PATCH 03/26] test: guard all opencl generated files in comparison oracle OpenCL was the outlier with only opencl_tracepoints.tp/opencl_profiling.tp listed. Mirror the other backends (which guard their btx_*_model.yaml plus every *.tp) by adding the remaining opencl generated artifacts: tracer_opencl.c, btx_cl_model.yaml, opencl_model.yaml, and the arguments/build/devices/dump/source tracepoint files. All are byte-identical between devel and the opencl-unify refactor, so this only widens coverage. Co-Authored-By: Claude Opus 4.8 --- utils/test_compare_generated_file.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utils/test_compare_generated_file.py b/utils/test_compare_generated_file.py index 0c50749a2..4ffd26e80 100644 --- a/utils/test_compare_generated_file.py +++ b/utils/test_compare_generated_file.py @@ -69,6 +69,14 @@ ] filenames += [ + "backends/opencl/tracer_opencl.c", + "backends/opencl/btx_cl_model.yaml", + "backends/opencl/opencl_model.yaml", + "backends/opencl/opencl_arguments.tp", + "backends/opencl/opencl_build.tp", + "backends/opencl/opencl_devices.tp", + "backends/opencl/opencl_dump.tp", + "backends/opencl/opencl_source.tp", "backends/opencl/opencl_tracepoints.tp", "backends/opencl/opencl_profiling.tp", ] From 2050fe9ef13f419a4da603685d170d3b72e21700 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 29 Jul 2026 23:10:26 +0000 Subject: [PATCH 04/26] utils: introduce TypeRegistry value object, keep global instance Extract the six type-classification facts gen_bt_field_model reads from loose globals ($types_by_name, $all_enum_names, $all_bitfield_names, $all_struct_names, $integer_sizes, $integer_signed) plus to_scoped_class_name into an immutable TypeRegistry value object with integer_size/integer_signed? methods. A single global $type_registry is populated exactly as before; the top-level integer_size/integer_signed? helpers now delegate to it. No behaviour change: generated files remain byte-identical. New file utils/type_registry.rb wired into utils/Makefile.am EXTRA_DIST (verified via make distcheck). Co-Authored-By: Claude Opus 4.8 --- utils/Makefile.am | 1 + utils/gen_babeltrace_model_helper.rb | 29 ++++++++++------------ utils/type_registry.rb | 37 ++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 utils/type_registry.rb diff --git a/utils/Makefile.am b/utils/Makefile.am index 3c736064d..102bbfe4b 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -73,6 +73,7 @@ EXTRA_DIST = \ yaml_ast.rb \ yaml_ast_lttng.rb \ gen_library_base.rb \ + type_registry.rb \ dump_trace_format.rb \ thapi_metadata_tracepoints.tp \ command.rb \ diff --git a/utils/gen_babeltrace_model_helper.rb b/utils/gen_babeltrace_model_helper.rb index e08e291f1..dd5b12c2e 100644 --- a/utils/gen_babeltrace_model_helper.rb +++ b/utils/gen_babeltrace_model_helper.rb @@ -1,5 +1,6 @@ # Include global variable INT_SIGN_MAP, ScalarMetaParameter, etc require_relative 'yaml_ast' +require_relative 'type_registry' $integer_sizes = INT_SIZE_MAP.transform_values { |v| v * 8 } $integer_signed = INT_SIGN_MAP @@ -13,26 +14,12 @@ end def integer_size(t) - return 64 if t.match(/\*/) - return 64 if t.match(/\[.*\]/) - - r = $integer_sizes[t] - raise "unknown integer type #{t}" if r.nil? - - r + $type_registry.integer_size(t) end def integer_signed?(t) - return false if t.match(/\*/) - return false if t.match(/\[.*\]/) - - r = $integer_signed[t] - raise "unknown integer type #{t}" if r.nil? - - r + $type_registry.integer_signed?(t) end - -# End of global variable use def meta_parameter_types_name(m, dir = nil) lttng = if dir == :start m.lttng_in_type @@ -88,6 +75,16 @@ def get_extra_fields_types_name(event) $types_by_name = $all_types.map { |ty| [ty.name, ty] }.to_h +$type_registry = TypeRegistry.new( + types_by_name: $types_by_name, + enum_names: $all_enum_names, + bitfield_names: $all_bitfield_names, + struct_names: $all_struct_names, + integer_sizes: $integer_sizes, + integer_signed: $integer_signed, + class_namer: ->(name) { to_scoped_class_name(name) }, +) + def gen_bt_field_model(lttng_name, type, name, lttng) member = { name: name } diff --git a/utils/type_registry.rb b/utils/type_registry.rb new file mode 100644 index 000000000..2851932ff --- /dev/null +++ b/utils/type_registry.rb @@ -0,0 +1,37 @@ +# Immutable value object holding the type facts the babeltrace-model generator +# needs to classify a field. Threaded explicitly instead of read from globals. +class TypeRegistry + attr_reader :types_by_name, :enum_names, :bitfield_names, :struct_names, + :integer_sizes, :integer_signed, :class_namer + + def initialize(types_by_name:, enum_names:, bitfield_names:, struct_names:, + integer_sizes:, integer_signed:, class_namer:) + @types_by_name = types_by_name + @enum_names = enum_names + @bitfield_names = bitfield_names + @struct_names = struct_names + @integer_sizes = integer_sizes + @integer_signed = integer_signed + @class_namer = class_namer + end + + def integer_size(t) + return 64 if t.match(/\*/) + return 64 if t.match(/\[.*\]/) + + r = integer_sizes[t] + raise "unknown integer type #{t}" if r.nil? + + r + end + + def integer_signed?(t) + return false if t.match(/\*/) + return false if t.match(/\[.*\]/) + + r = integer_signed[t] + raise "unknown integer type #{t}" if r.nil? + + r + end +end From c6752a57441656852f7e354404e13b594bab94b8 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 29 Jul 2026 23:18:03 +0000 Subject: [PATCH 05/26] utils: gen_bt_field_model(registry, ...) reads from TypeRegistry Change gen_bt_field_model's signature to take a TypeRegistry as its first argument and read types_by_name / enum_names / bitfield_names / struct_names / integer_size / integer_signed? / class_namer from it instead of the loose globals and the top-level integer_size/integer_signed? helpers. The two internal call sites (gen_event_fields_bt_model, gen_extra_event_fields_bt_model) pass the global $type_registry, still the sole instance. No behaviour change: generated files remain byte-identical. Co-Authored-By: Claude Opus 4.8 --- utils/gen_babeltrace_model_helper.rb | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/utils/gen_babeltrace_model_helper.rb b/utils/gen_babeltrace_model_helper.rb index dd5b12c2e..b41366574 100644 --- a/utils/gen_babeltrace_model_helper.rb +++ b/utils/gen_babeltrace_model_helper.rb @@ -85,11 +85,12 @@ def get_extra_fields_types_name(event) class_namer: ->(name) { to_scoped_class_name(name) }, ) -def gen_bt_field_model(lttng_name, type, name, lttng) +def gen_bt_field_model(registry, lttng_name, type, name, lttng) + types_by_name = registry.types_by_name member = { name: name } field = { cast_type: type.gsub(/\[.*\]/, '*') } - if $types_by_name[type].is_a?(YAMLCAst::Declaration) && $types_by_name[type].type.is_a?(YAMLCAst::Function) + if types_by_name[type].is_a?(YAMLCAst::Declaration) && types_by_name[type].type.is_a?(YAMLCAst::Function) field[:cast_type] = "#{type} *" end @@ -98,18 +99,18 @@ def gen_bt_field_model(lttng_name, type, name, lttng) when 'ctf_float' field[:type] = type == 'float' ? 'single' : type when 'ctf_integer', 'ctf_integer_hex' - field[:type] = integer_signed?(type) ? 'integer_signed' : 'integer_unsigned' - field[:field_value_range] = integer_size(type) + field[:type] = registry.integer_signed?(type) ? 'integer_signed' : 'integer_unsigned' + field[:field_value_range] = registry.integer_size(type) field[:preferred_display_base] = 16 if lttng_name.end_with?('_hex') - if $all_enum_names.include?(type) || $all_bitfield_names.include?(type) - member[:metadata] = { be_class: to_scoped_class_name(type) } + if registry.enum_names.include?(type) || registry.bitfield_names.include?(type) + member[:metadata] = { be_class: registry.class_namer.call(type) } end when 'ctf_sequence', 'ctf_sequence_hex' array_type = lttng.type.to_s field[:type] = 'array_dynamic' field[:element_field_class] = - { type: integer_signed?(array_type) ? 'integer_signed' : 'integer_unsigned', - field_value_range: integer_size(array_type) } + { type: registry.integer_signed?(array_type) ? 'integer_signed' : 'integer_unsigned', + field_value_range: registry.integer_size(array_type) } field[:element_field_class][:preferred_display_base] = 16 if lttng_name.end_with?('_hex') @@ -121,8 +122,8 @@ def gen_bt_field_model(lttng_name, type, name, lttng) array_type = lttng.type.to_s field[:type] = 'array_static' field[:element_field_class] = - { type: integer_signed?(array_type) ? 'integer_signed' : 'integer_unsigned', - field_value_range: integer_size(array_type) } + { type: registry.integer_signed?(array_type) ? 'integer_signed' : 'integer_unsigned', + field_value_range: registry.integer_size(array_type) } field[:element_field_class][:preferred_display_base] = 16 if lttng_name.end_with?('_hex') field[:length] = lttng.length when 'ctf_string' @@ -130,13 +131,13 @@ def gen_bt_field_model(lttng_name, type, name, lttng) when 'ctf_sequence_text', 'ctf_array_text' field[:type] = 'string' t = type.sub(' *', '') - while $types_by_name.include?(t) && $types_by_name[t].type.is_a?(YAMLCAst::CustomType) - t = $types_by_name[t].type.name + while types_by_name.include?(t) && types_by_name[t].type.is_a?(YAMLCAst::CustomType) + t = types_by_name[t].type.name end - member[:metadata] = { be_class: to_scoped_class_name(t) } if $all_struct_names.include?(t) + member[:metadata] = { be_class: registry.class_namer.call(t) } if registry.struct_names.include?(t) # Too complicated, not sure why `all_struct_names` is not enough - if !field[:cast_type].end_with?('*') && ($all_struct_names.include?(t) || $types_by_name[t]&.type.is_a?(YAMLCAst::Union) || type.start_with?('struct')) + if !field[:cast_type].end_with?('*') && (registry.struct_names.include?(t) || types_by_name[t]&.type.is_a?(YAMLCAst::Union) || type.start_with?('struct')) field[:cast_type_is_struct] = true end else @@ -171,14 +172,14 @@ def get_fields_types_name(c, dir) def gen_event_fields_bt_model(c, dir) types_name = get_fields_types_name(c, dir) types_name.collect do |lttng_name, type, name, lttng| - gen_bt_field_model(lttng_name, type.sub(/\Aconst /, ''), name, lttng) + gen_bt_field_model($type_registry, lttng_name, type.sub(/\Aconst /, ''), name, lttng) end end def gen_extra_event_fields_bt_model(event) types_name = get_extra_fields_types_name(event) types_name.collect do |lttng_name, type, name, lttng| - gen_bt_field_model(lttng_name, type.sub(/\Aconst /, ''), name, lttng) + gen_bt_field_model($type_registry, lttng_name, type.sub(/\Aconst /, ''), name, lttng) end end From 0c2160d76544e305ea3cc6f8119267b56d455bbd Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 29 Jul 2026 23:43:04 +0000 Subject: [PATCH 06/26] babeltrace-model: thread TypeRegistry explicitly, drop load-time globals (AST backends) Add TypeRegistry.from_ast, which derives the integer-size/-sign lookups and the by-name type index from a backend's parsed AST (the enum/bitfield/struct name lists are still classified per-backend, since their rules differ). Each AST backend's gen_babeltrace__model.rb now constructs its own registry and passes it as the first argument through gen_event_bt_model / gen_extra_event_bt_model / gen_event_fields_bt_model / gen_bt_field_model. This removes ALL load-time side effects from gen_babeltrace_model_helper.rb: the $integer_sizes/$integer_signed/$types_by_name/$type_registry globals and the free integer_size/integer_signed? helpers are gone; requiring the helper now only defines functions. State is produced only by the explicit from_ast call that returns it. Generated files remain byte-identical for all backends. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_babeltrace_cuda_model.rb | 12 ++++-- backends/hip/gen_babeltrace_hip_model.rb | 12 ++++-- backends/itt/gen_babeltrace_itt_model.rb | 10 ++++- backends/mpi/gen_babeltrace_mpi_model.rb | 12 ++++-- backends/omp/gen_babeltrace_omp_model.rb | 8 +++- backends/ze/gen_babeltrace_ze_model.rb | 12 ++++-- utils/gen_babeltrace_model_helper.rb | 48 ++++------------------ utils/type_registry.rb | 19 +++++++++ 8 files changed, 79 insertions(+), 54 deletions(-) diff --git a/backends/cuda/gen_babeltrace_cuda_model.rb b/backends/cuda/gen_babeltrace_cuda_model.rb index c0c1ede72..5a505cc78 100644 --- a/backends/cuda/gen_babeltrace_cuda_model.rb +++ b/backends/cuda/gen_babeltrace_cuda_model.rb @@ -1,19 +1,25 @@ require_relative 'gen_cuda_library_base' require_relative '../../utils/gen_babeltrace_model_helper' +registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), +) + event_classes = [[:lttng_ust_cuda, $cuda_commands], [:lttng_ust_cuda_exports, $cuda_exports_commands]].collect do |provider, commands| commands.collect do |c| - [gen_event_bt_model(provider, c, :start), - gen_event_bt_model(provider, c, :stop)] + [gen_event_bt_model(registry, provider, c, :start), + gen_event_bt_model(registry, provider, c, :stop)] end end.flatten(2) cuda_events = YAML.load_file(File.join(SRC_DIR, 'cuda_events.yaml')) event_classes += cuda_events.collect do |provider, es| es['events'].collect do |event| - gen_extra_event_bt_model(provider, event) + gen_extra_event_bt_model(registry, provider, event) end end.flatten diff --git a/backends/hip/gen_babeltrace_hip_model.rb b/backends/hip/gen_babeltrace_hip_model.rb index a4576c1a2..48ee66879 100644 --- a/backends/hip/gen_babeltrace_hip_model.rb +++ b/backends/hip/gen_babeltrace_hip_model.rb @@ -1,18 +1,24 @@ require_relative 'gen_hip_library_base' require_relative '../../utils/gen_babeltrace_model_helper' +registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), +) + event_classes = [[:lttng_ust_hip, $hip_commands]].collect do |provider, commands| commands.collect do |c| - [gen_event_bt_model(provider, c, :start), - gen_event_bt_model(provider, c, :stop)] + [gen_event_bt_model(registry, provider, c, :start), + gen_event_bt_model(registry, provider, c, :stop)] end end.flatten(2) hip_events = YAML.load_file(File.join(SRC_DIR, 'hip_events.yaml')) event_classes += hip_events.collect do |provider, es| es['events'].collect do |event| - gen_extra_event_bt_model(provider, event) + gen_extra_event_bt_model(registry, provider, event) end end.flatten diff --git a/backends/itt/gen_babeltrace_itt_model.rb b/backends/itt/gen_babeltrace_itt_model.rb index bc4922964..f789e8906 100644 --- a/backends/itt/gen_babeltrace_itt_model.rb +++ b/backends/itt/gen_babeltrace_itt_model.rb @@ -1,17 +1,23 @@ require_relative 'gen_itt_library_base' require_relative '../../utils/gen_babeltrace_model_helper' +registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), +) + event_classes = [[:lttng_ust_itt, $itt_commands]].collect do |provider, commands| commands.collect do |c| - [gen_event_bt_model(provider, c)] + [gen_event_bt_model(registry, provider, c)] end end.flatten(2) itt_events = YAML.load_file(File.join(SRC_DIR, 'itt_events.yaml')) event_classes += itt_events.collect do |provider, es| es['events'].collect do |event| - gen_extra_event_bt_model(provider, event) + gen_extra_event_bt_model(registry, provider, event) end end.flatten diff --git a/backends/mpi/gen_babeltrace_mpi_model.rb b/backends/mpi/gen_babeltrace_mpi_model.rb index de6c42ba1..68705ce87 100644 --- a/backends/mpi/gen_babeltrace_mpi_model.rb +++ b/backends/mpi/gen_babeltrace_mpi_model.rb @@ -1,18 +1,24 @@ require_relative 'gen_mpi_library_base' require_relative '../../utils/gen_babeltrace_model_helper' +registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), +) + event_classes = [[:lttng_ust_mpi, $mpi_commands]].collect do |provider, commands| commands.collect do |c| - [gen_event_bt_model(provider, c, :start), - gen_event_bt_model(provider, c, :stop)] + [gen_event_bt_model(registry, provider, c, :start), + gen_event_bt_model(registry, provider, c, :stop)] end end.flatten(2) mpi_events = YAML.load_file(File.join(SRC_DIR, 'mpi_events.yaml')) event_classes += mpi_events.collect do |provider, es| es['events'].collect do |event| - gen_extra_event_bt_model(provider, event) + gen_extra_event_bt_model(registry, provider, event) end end.flatten diff --git a/backends/omp/gen_babeltrace_omp_model.rb b/backends/omp/gen_babeltrace_omp_model.rb index 01554761d..791124441 100644 --- a/backends/omp/gen_babeltrace_omp_model.rb +++ b/backends/omp/gen_babeltrace_omp_model.rb @@ -1,10 +1,16 @@ require_relative 'gen_omp_library_base' require_relative '../../utils/gen_babeltrace_model_helper' +registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), +) + event_classes = [[:lttng_ust_ompt, $ompt_commands]].collect do |provider, commands| commands.collect do |c| - [gen_event_bt_model(provider, c)] + [gen_event_bt_model(registry, provider, c)] end end.flatten(2) diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index 58393acbe..d169d059b 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -2,6 +2,12 @@ require_relative '../../utils/gen_babeltrace_model_helper' require 'set' +registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), +) + event_classes = [[:lttng_ust_ze, $ze_commands], [:lttng_ust_zet, $zet_commands], @@ -10,15 +16,15 @@ [:lttng_ust_zer, $zer_commands], [:lttng_ust_zex, $zex_commands]].collect do |provider, commands| commands.collect do |c| - [gen_event_bt_model(provider, c, :start), - gen_event_bt_model(provider, c, :stop)] + [gen_event_bt_model(registry, provider, c, :start), + gen_event_bt_model(registry, provider, c, :stop)] end end.flatten(2) ze_events = YAML.load_file(File.join(SRC_DIR, 'ze_events.yaml')) event_classes += ze_events.collect do |provider, es| es['events'].collect do |event| - gen_extra_event_bt_model(provider, event) + gen_extra_event_bt_model(registry, provider, event) end end.flatten diff --git a/utils/gen_babeltrace_model_helper.rb b/utils/gen_babeltrace_model_helper.rb index b41366574..3f6d508cd 100644 --- a/utils/gen_babeltrace_model_helper.rb +++ b/utils/gen_babeltrace_model_helper.rb @@ -1,25 +1,7 @@ -# Include global variable INT_SIGN_MAP, ScalarMetaParameter, etc +# ScalarMetaParameter, YAMLCAst node classes, etc. require_relative 'yaml_ast' require_relative 'type_registry' -$integer_sizes = INT_SIZE_MAP.transform_values { |v| v * 8 } -$integer_signed = INT_SIGN_MAP - -$all_enums.each do |t| - $integer_sizes["enum #{t.name}"] = 32 -end - -$all_enums.each do |t| - $integer_signed["enum #{t.name}"] = true -end - -def integer_size(t) - $type_registry.integer_size(t) -end - -def integer_signed?(t) - $type_registry.integer_signed?(t) -end def meta_parameter_types_name(m, dir = nil) lttng = if dir == :start m.lttng_in_type @@ -73,18 +55,6 @@ def get_extra_fields_types_name(event) end.flatten(1) end -$types_by_name = $all_types.map { |ty| [ty.name, ty] }.to_h - -$type_registry = TypeRegistry.new( - types_by_name: $types_by_name, - enum_names: $all_enum_names, - bitfield_names: $all_bitfield_names, - struct_names: $all_struct_names, - integer_sizes: $integer_sizes, - integer_signed: $integer_signed, - class_namer: ->(name) { to_scoped_class_name(name) }, -) - def gen_bt_field_model(registry, lttng_name, type, name, lttng) types_by_name = registry.types_by_name member = { name: name } @@ -169,21 +139,21 @@ def get_fields_types_name(c, dir) end.flatten(1) end -def gen_event_fields_bt_model(c, dir) +def gen_event_fields_bt_model(registry, c, dir) types_name = get_fields_types_name(c, dir) types_name.collect do |lttng_name, type, name, lttng| - gen_bt_field_model($type_registry, lttng_name, type.sub(/\Aconst /, ''), name, lttng) + gen_bt_field_model(registry, lttng_name, type.sub(/\Aconst /, ''), name, lttng) end end -def gen_extra_event_fields_bt_model(event) +def gen_extra_event_fields_bt_model(registry, event) types_name = get_extra_fields_types_name(event) types_name.collect do |lttng_name, type, name, lttng| - gen_bt_field_model($type_registry, lttng_name, type.sub(/\Aconst /, ''), name, lttng) + gen_bt_field_model(registry, lttng_name, type.sub(/\Aconst /, ''), name, lttng) end end -def gen_event_bt_model(provider, c, dir = nil) +def gen_event_bt_model(registry, provider, c, dir = nil) d = if dir { name: "#{provider}:#{c.name}_#{SUFFIXES[dir]}" } # OMP backend @@ -191,7 +161,7 @@ def gen_event_bt_model(provider, c, dir = nil) { name: "#{provider}:#{c.name.gsub(/_func\z/, '')}" } end - m = gen_event_fields_bt_model(c, dir) + m = gen_event_fields_bt_model(registry, c, dir) unless m.empty? d[:payload_field_class] = @@ -203,9 +173,9 @@ def gen_event_bt_model(provider, c, dir = nil) d end -def gen_extra_event_bt_model(provider, event) +def gen_extra_event_bt_model(registry, provider, event) d = { name: "#{provider}:#{event['name']}" } - m = gen_extra_event_fields_bt_model(event) + m = gen_extra_event_fields_bt_model(registry, event) unless m.empty? d[:payload_field_class] = diff --git a/utils/type_registry.rb b/utils/type_registry.rb index 2851932ff..122ec1ec0 100644 --- a/utils/type_registry.rb +++ b/utils/type_registry.rb @@ -1,9 +1,28 @@ # Immutable value object holding the type facts the babeltrace-model generator # needs to classify a field. Threaded explicitly instead of read from globals. +require_relative 'yaml_ast' + class TypeRegistry attr_reader :types_by_name, :enum_names, :bitfield_names, :struct_names, :integer_sizes, :integer_signed, :class_namer + # Build a registry from an AST backend's parsed model. The enum/bitfield/ + # struct name lists are classified by the backend (their rules differ); this + # only derives the integer-size/-sign lookups (scalar widths plus a 32-bit + # signed entry per enum) and the by-name type index. + def self.from_ast(all_types:, all_enums:, enum_names:, bitfield_names:, struct_names:, class_namer:) + integer_sizes = INT_SIZE_MAP.transform_values { |v| v * 8 } + integer_signed = INT_SIGN_MAP.dup + all_enums.each do |e| + integer_sizes["enum #{e.name}"] = 32 + integer_signed["enum #{e.name}"] = true + end + + new(types_by_name: all_types.map { |t| [t.name, t] }.to_h, + enum_names: enum_names, bitfield_names: bitfield_names, struct_names: struct_names, + integer_sizes: integer_sizes, integer_signed: integer_signed, class_namer: class_namer) + end + def initialize(types_by_name:, enum_names:, bitfield_names:, struct_names:, integer_sizes:, integer_signed:, class_namer:) @types_by_name = types_by_name From cadbe79a05bcc53e4acb8426c45b13f2e6e24f39 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Wed, 29 Jul 2026 23:51:16 +0000 Subject: [PATCH 07/26] opencl: drop fake AST globals that only fed the helper's deleted load-time code gen_babeltrace_cl_model.rb defined empty INT_SIZE_MAP/INT_SIGN_MAP/$all_enums/ $all_types placeholders solely to satisfy gen_babeltrace_model_helper.rb's top-level load-time code (which read those globals to build $integer_sizes / $types_by_name). That load-time code was deleted when the helper moved to an explicitly-threaded TypeRegistry, so the placeholders are now dead. Removing them leaves opencl's generated btx_cl_model.yaml byte-identical. Co-Authored-By: Claude Opus 4.8 --- backends/opencl/gen_babeltrace_cl_model.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/backends/opencl/gen_babeltrace_cl_model.rb b/backends/opencl/gen_babeltrace_cl_model.rb index f6aa1dc6b..dac560b10 100644 --- a/backends/opencl/gen_babeltrace_cl_model.rb +++ b/backends/opencl/gen_babeltrace_cl_model.rb @@ -1,10 +1,5 @@ require 'yaml' -INT_SIZE_MAP = {} -INT_SIGN_MAP = {} -$all_enums = {} -$all_types = {} - require_relative '../../utils/gen_babeltrace_model_helper' OPENCL_MODEL = YAML.load_file('opencl_model.yaml') From b8da260137895120aa66946622423315466c8fce Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 00:55:10 +0000 Subject: [PATCH 08/26] opencl: document why parse_field stays separate from shared helper The babeltrace-model de-globalization unified the six AST backends onto the shared gen_bt_field_model, but opencl's parse_field is deliberately left separate. Its de-globalization goal is already met (side-effect-free, reads OPENCL_MODEL explicitly), and merging it could not stay byte-identical: ctf_enum emits real CTF enumerations (AST backends have no such case), the input shape is a flat hash vs AST + LTTng objects, and pointer/signedness is encoded differently (bare-type signedness + explicit pointer flag vs a `*` in the type string whose rule forces unsigned). Comment records this as a reasoned decision so the next reader does not re-attempt it. Co-Authored-By: Claude Opus 4.8 --- backends/opencl/gen_babeltrace_cl_model.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/backends/opencl/gen_babeltrace_cl_model.rb b/backends/opencl/gen_babeltrace_cl_model.rb index dac560b10..2e34d3f8e 100644 --- a/backends/opencl/gen_babeltrace_cl_model.rb +++ b/backends/opencl/gen_babeltrace_cl_model.rb @@ -40,6 +40,25 @@ def cl_to_class(type) 'CL::' + type.sub(/\Acl_/, '').split('_').collect(&:capitalize).join end +# NOTE: This stays deliberately separate from the shared utils/gen_bt_field_model +# (used by the AST backends) rather than being unified. The de-globalization goal +# is already met here: parse_field is side-effect-free and reads OPENCL_MODEL +# explicitly. Merging it would add opencl-only branches/params to the shared +# function, making both harder, and could not stay byte-identical, because: +# * Input shape differs: this reads a flat hash (field['type']/['pointer']/ +# ['enum_type']); the shared fn reads AST objects + an LTTng object +# (lttng.type/.length). +# * ctf_enum: opencl emits real CTF enumerations with inline mappings from +# OPENCL_MODEL['lttng_enums']; AST backends have no ctf_enum case at all -- +# they model enums as integers + be_class metadata. The two are not +# reconcilable without teaching the shared fn concepts the AST side lacks. +# * Pointer/signedness: opencl derives signedness from the bare type (a +# pointer field like `void *` / `cl_int *` stays integer_signed) and size +# from an explicit `pointer` flag; the shared fn encodes pointer as a `*` in +# the type string, whose /\*/ rule forces BOTH size=64 and unsigned. Routing +# opencl through it would flip ~173 signed pointer fields to unsigned. +# * cast_type is assembled by the caller here, inside the fn there. +# This separation is a reasoned decision, not an unfinished TODO. def parse_field(field) d = {} d[:field_class] = {} From 6511b99b2577a4e97328ea9342d8f74a48497657 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 00:55:22 +0000 Subject: [PATCH 09/26] babeltrace-model: assert per-backend bitfield invariant; note remaining reader Each AST model generator now asserts, right after building its TypeRegistry, whether the backend has bitfield types. Empirically (loading each gen__library_base and inspecting the populated name list) the runtime invariant is: cuda, hip, mpi and itt have zero bitfield types; ze (148) and omp (12) have them. Note itt's .push line exists but sits in a conditional that never fires for its actual types, so itt asserts empty -- the initial non-empty assertion failed the itt build, confirming the real invariant. Also documents the remaining $all_bitfield_names read in gen_babeltrace_lib_helper.rb: it is in the library/bindings path (not the de-globalized model path), runs after the caller has required its gen__library_base, and cannot be dropped while gen_library_base.rb still reads $all_struct_names. All 53 oracle files remain byte-identical. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_babeltrace_cuda_model.rb | 1 + backends/hip/gen_babeltrace_hip_model.rb | 1 + backends/itt/gen_babeltrace_itt_model.rb | 1 + backends/mpi/gen_babeltrace_mpi_model.rb | 1 + backends/omp/gen_babeltrace_omp_model.rb | 1 + backends/ze/gen_babeltrace_ze_model.rb | 1 + utils/gen_babeltrace_lib_helper.rb | 7 +++++++ 7 files changed, 13 insertions(+) diff --git a/backends/cuda/gen_babeltrace_cuda_model.rb b/backends/cuda/gen_babeltrace_cuda_model.rb index 5a505cc78..5ae5361bf 100644 --- a/backends/cuda/gen_babeltrace_cuda_model.rb +++ b/backends/cuda/gen_babeltrace_cuda_model.rb @@ -6,6 +6,7 @@ enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, class_namer: method(:to_scoped_class_name), ) +raise 'cuda: expected no bitfield types' unless registry.bitfield_names.empty? event_classes = [[:lttng_ust_cuda, $cuda_commands], diff --git a/backends/hip/gen_babeltrace_hip_model.rb b/backends/hip/gen_babeltrace_hip_model.rb index 48ee66879..a0c96240b 100644 --- a/backends/hip/gen_babeltrace_hip_model.rb +++ b/backends/hip/gen_babeltrace_hip_model.rb @@ -6,6 +6,7 @@ enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, class_namer: method(:to_scoped_class_name), ) +raise 'hip: expected no bitfield types' unless registry.bitfield_names.empty? event_classes = [[:lttng_ust_hip, $hip_commands]].collect do |provider, commands| diff --git a/backends/itt/gen_babeltrace_itt_model.rb b/backends/itt/gen_babeltrace_itt_model.rb index f789e8906..9dd30749b 100644 --- a/backends/itt/gen_babeltrace_itt_model.rb +++ b/backends/itt/gen_babeltrace_itt_model.rb @@ -6,6 +6,7 @@ enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, class_namer: method(:to_scoped_class_name), ) +raise 'itt: expected no bitfield types' unless registry.bitfield_names.empty? event_classes = [[:lttng_ust_itt, $itt_commands]].collect do |provider, commands| diff --git a/backends/mpi/gen_babeltrace_mpi_model.rb b/backends/mpi/gen_babeltrace_mpi_model.rb index 68705ce87..a2781c3ad 100644 --- a/backends/mpi/gen_babeltrace_mpi_model.rb +++ b/backends/mpi/gen_babeltrace_mpi_model.rb @@ -6,6 +6,7 @@ enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, class_namer: method(:to_scoped_class_name), ) +raise 'mpi: expected no bitfield types' unless registry.bitfield_names.empty? event_classes = [[:lttng_ust_mpi, $mpi_commands]].collect do |provider, commands| diff --git a/backends/omp/gen_babeltrace_omp_model.rb b/backends/omp/gen_babeltrace_omp_model.rb index 791124441..68c97d0ae 100644 --- a/backends/omp/gen_babeltrace_omp_model.rb +++ b/backends/omp/gen_babeltrace_omp_model.rb @@ -6,6 +6,7 @@ enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, class_namer: method(:to_scoped_class_name), ) +raise 'omp: expected bitfield types' if registry.bitfield_names.empty? event_classes = [[:lttng_ust_ompt, $ompt_commands]].collect do |provider, commands| diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index d169d059b..4d00368dd 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -7,6 +7,7 @@ enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, class_namer: method(:to_scoped_class_name), ) +raise 'ze: expected bitfield types' if registry.bitfield_names.empty? event_classes = [[:lttng_ust_ze, $ze_commands], diff --git a/utils/gen_babeltrace_lib_helper.rb b/utils/gen_babeltrace_lib_helper.rb index c058ea3d2..11911f058 100644 --- a/utils/gen_babeltrace_lib_helper.rb +++ b/utils/gen_babeltrace_lib_helper.rb @@ -16,6 +16,13 @@ def add_babeltrace_event_callbacks(file) case fc[:type] when 'integer_signed', 'integer_unsigned' if be_class + # Remaining read of the $all_bitfield_names global. This is + # in the library/bindings path (not the babeltrace-model + # path that was de-globalized): callers require their + # gen__library_base first, which populates the global + # before this call, so there is no load-order hazard. The + # global cannot be dropped while gen_library_base.rb still + # reads $all_struct_names, so it is left explicit here. if $all_bitfield_names.include?(fc[:cast_type]) %{s << "#{name}: [ \#{#{be_class}.from_native(defi["#{name}"], nil).join(", ")} ]"} else From f9cc819fa7fcb83f12e2676d24b6e85db6f9b184 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 02:37:23 +0000 Subject: [PATCH 10/26] gen: delete dead code (unused to_snake_case dups, dead flag, commented scaffolding) Cherry-pick of devel 2614b7a onto opencl-unify-refactor, resolving the opencl_model.rb conflict: this branch keeps MEMBER_SEPARATOR in utils/LTTng.rb rather than inline, so only the dead GENERATE_ENUMS_TRACEPOINTS constant, the enum-tracepoint block it gated, and the dead early-return are removed. Removed content is byte-identical to 2614b7a on all 8 files (164 deletions total). Byte-identical-safe: GENERATE_ENUMS_TRACEPOINTS was permanently false, so the gated blocks never executed and no generated output changes. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_cuda.rb | 95 ---------------------------- backends/hip/gen_hip_library_base.rb | 4 -- backends/itt/gen_itt_library_base.rb | 4 -- backends/mpi/gen_mpi_library_base.rb | 4 -- backends/omp/gen_omp_library_base.rb | 4 -- backends/opencl/gen_opencl_probes.rb | 30 --------- backends/opencl/opencl_model.rb | 22 ------- backends/ze/gen_ze_library_base.rb | 1 - 8 files changed, 164 deletions(-) diff --git a/backends/cuda/gen_cuda.rb b/backends/cuda/gen_cuda.rb index 587507c2a..7db035068 100644 --- a/backends/cuda/gen_cuda.rb +++ b/backends/cuda/gen_cuda.rb @@ -14,9 +14,6 @@ static void _init_tracer(void); EOF -# puts < -# EOF ($cuda_commands + $cuda_exports_commands).each do |c| puts "#define #{CUDA_POINTER_NAMES[c]} #{c.pointer_name}" @@ -65,9 +62,6 @@ #{c.decl_hidden_alias}; static void wrap_#{c.name}(void **pfn); EOF - # puts <c_ptr; - # } else { - # closure = (struct cuda_closure *)malloc(sizeof(struct cuda_closure) + #{c.parameters.size} * sizeof(ffi_type *)); - # if (closure != NULL) { - # closure->types = (ffi_type **)((intptr_t)closure + sizeof(struct cuda_closure)); - # closure->closure = ffi_closure_alloc(sizeof(ffi_closure), &(closure->c_ptr)); - # if (closure->closure != NULL) { - # closure->ptr = *pfn; - # EOF - # c.parameters.each_with_index { |a, i| - # if a.type.kind_of?(YAMLCAst::Pointer) - # ffi_type = "ffi_type_pointer" - # elsif FFI_TYPE_MAP["#{a.type}"] - # ffi_type = FFI_TYPE_MAP["#{a.type}"] - # else - # raise "Unsupported type: #{a.type}" - # end - # str << <types[#{i}] = &#{ffi_type}; - # EOF - # } - # if c.type.kind_of?(YAMLCAst::Void) - # ffi_ret_type = "ffi_type_void" - # elsif c.type.kind_of?(YAMLCAst::Pointer) - # ffi_ret_type = "ffi_type_pointer" - # elsif FFI_TYPE_MAP["#{c.type}"] - # ffi_ret_type = FFI_TYPE_MAP["#{c.type}"] - # else - # raise "Unsupported type: #{c.type}" - # end - # str << <cif), FFI_DEFAULT_ABI, #{c.parameters.size}, &#{ffi_ret_type}, closure->types) == FFI_OK) { - # if (ffi_prep_closure_loc(closure->closure, &(closure->cif), (void (*)(ffi_cif*, void *, void **, void *))#{c.ffi_name}, *pfn, closure->c_ptr) == FFI_OK) { - # pthread_mutex_lock(&cuda_closures_mutex); - # HASH_ADD_PTR(cuda_closures, ptr, closure); - # pthread_mutex_unlock(&cuda_closures_mutex); - # *pfn = closure->c_ptr; - # } else { - # ffi_closure_free(closure->closure); - # free(closure); - # } - # } else { - # ffi_closure_free(closure->closure); - # free(closure); - # } - # } else { - # free(closure); - # } - # } - # } - # EOF - # rescue => e - # str = < START, 'stop' => STOP } -GENERATE_ENUMS_TRACEPOINTS = false - HOST_PROFILE = true WINDOWS = /D3D|DX9/ @@ -177,24 +175,6 @@ def enums Require.new(r) end -if GENERATE_ENUMS_TRACEPOINTS - enums = YAML.load_file(File.join(SRC_DIR, 'supported_enums.yaml')) - - enums.each do |e| - vals = $requires.select do |r| - r.comment && r.comment.match(/#{e['name']}(\z| )/) - end.collect do |r| - r.enums - end.reduce(:+).collect do |v| - [v, $constants[v]] - end.to_h - ENUMS[e['name']] = { 'values' => vals, 'trace_name' => e['trace_name'], 'type_name' => e['type_name'] } - ENUM_PARAM_NAME_MAP[e['trace_name']] = e['type_name'] - ENUM_TYPES.push(e['type_name'] || e['name']) - end - ENUM_TYPES.push 'cl_bool' -end - class Declaration < CLXML attr_reader :type, :name @@ -374,8 +354,6 @@ def lttng_return_type case @return_type when 'cl_int' - return %w[ctf_enum lttng_ust_opencl cl_errcode cl_int errcode_ret_val _retval] if GENERATE_ENUMS_TRACEPOINTS - return %w[ctf_integer cl_int errcode_ret_val _retval] when *CL_OBJECTS diff --git a/backends/ze/gen_ze_library_base.rb b/backends/ze/gen_ze_library_base.rb index 6fb36fd42..2d3b09a5c 100644 --- a/backends/ze/gen_ze_library_base.rb +++ b/backends/ze/gen_ze_library_base.rb @@ -7,7 +7,6 @@ $all_unions = $zet_api['unions'] $all_enums = $ze_api['enums'] + $zet_api['enums'] + $zes_api['enums'] + $zel_api['enums'] $all_funcs = $ze_api['functions'] + $zet_api['functions'] + $zes_api['functions'] + $zel_api['functions'] -$all_types_map = $all_types.collect { |t| [t.name, t.type] }.to_h $all_enum_names = [] $all_bitfield_names = [] From cc77d757d04b357d72d9e446119af4063b9d6706 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 02:54:44 +0000 Subject: [PATCH 11/26] opencl: remove permanently-empty ENUM lookup tables and their dead readers After 2614b7a deleted the GENERATE_ENUMS_TRACEPOINTS block, ENUMS, ENUM_PARAM_NAME_MAP and ENUM_TYPES have no populator and stay empty forever. Remove the three declarations, the always-false `ENUM_TYPES.include?` guard in lttng_in_type, and unwrap both `if ENUM_PARAM_NAME_MAP[name]` branches in In/OutScalar (the enum branch could never be taken; keep the else body). Byte-identical-safe: every removed reader was dead (empty-collection lookups), so no generated output changes. Verified: 53/53 oracle cases identical to the devel baseline. Co-Authored-By: Claude Opus 4.8 --- backends/opencl/opencl_model.rb | 57 ++++++++++++--------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/backends/opencl/opencl_model.rb b/backends/opencl/opencl_model.rb index 59eac7327..56d592d68 100644 --- a/backends/opencl/opencl_model.rb +++ b/backends/opencl/opencl_model.rb @@ -25,10 +25,6 @@ LTTNG_AVAILABLE_PARAMS = 25 LTTNG_USABLE_PARAMS = LTTNG_AVAILABLE_PARAMS - 1 -ENUMS = {} -ENUM_PARAM_NAME_MAP = {} -ENUM_TYPES = [] - # map = Hash::new { |h, k| h[k] = [] } doc = Nokogiri::XML(open('cl.xml.patched')) @@ -271,7 +267,6 @@ def lttng_in_type t = @type t = CL_TYPE_MAP[@type] if CL_TYPE_MAP[@type] - return ['ctf_enum', 'lttng_ust_opencl', @type, t, @name, @name] if ENUM_TYPES.include? @type case t when *CL_OBJECTS, *CL_EXT_OBJECTS @@ -424,24 +419,19 @@ def initialize(command, name, nocheck: false) type = command[name].type.gsub('*', '') type = CL_TYPE_MAP[type] if CL_TYPE_MAP[type] - if ENUM_PARAM_NAME_MAP[name] - @lttng_in_type = ['ctf_enum', 'lttng_ust_opencl', ENUM_PARAM_NAME_MAP[name], type, name + '_val', - nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] + case type + when *CL_OBJECTS, *CL_EXT_OBJECTS, 'void' + @lttng_in_type = ['ctf_integer_hex', 'uintptr_t', name + '_val', + nocheck ? "(uintptr_t)(*#{name})" : "(uintptr_t)(#{name} == NULL ? 0 : *#{name})"] + when *CL_INT_SCALARS + @lttng_in_type = ['ctf_integer', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] + when *CL_FLOAT_SCALARS + @lttng_in_type = ['ctf_float', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] + when *CL_STRUCTS + @lttng_in_type = ['ctf_sequence_text', 'uint8_t', name + '_val', "(uint8_t *)#{name}", 'size_t', + "#{name} == NULL ? 0 : sizeof(#{type})"] else - case type - when *CL_OBJECTS, *CL_EXT_OBJECTS, 'void' - @lttng_in_type = ['ctf_integer_hex', 'uintptr_t', name + '_val', - nocheck ? "(uintptr_t)(*#{name})" : "(uintptr_t)(#{name} == NULL ? 0 : *#{name})"] - when *CL_INT_SCALARS - @lttng_in_type = ['ctf_integer', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] - when *CL_FLOAT_SCALARS - @lttng_in_type = ['ctf_float', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] - when *CL_STRUCTS - @lttng_in_type = ['ctf_sequence_text', 'uint8_t', name + '_val', "(uint8_t *)#{name}", 'size_t', - "#{name} == NULL ? 0 : sizeof(#{type})"] - else - raise "Unknown Type: #{type.inspect}!" - end + raise "Unknown Type: #{type.inspect}!" end end end @@ -453,21 +443,16 @@ def initialize(command, name, nocheck: false) type = command[name].type.gsub('*', '') type = CL_TYPE_MAP[type] if CL_TYPE_MAP[type] - if ENUM_PARAM_NAME_MAP[name] - @lttng_out_type = ['ctf_enum', 'lttng_ust_opencl', ENUM_PARAM_NAME_MAP[name], type, name + '_val', - nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] + case type + when *CL_OBJECTS, *CL_EXT_OBJECTS, 'void' + @lttng_out_type = ['ctf_integer_hex', 'uintptr_t', name + '_val', + nocheck ? "(uintptr_t)(*#{name})" : "(uintptr_t)(#{name} == NULL ? 0 : *#{name})"] + when *CL_INT_SCALARS + @lttng_out_type = ['ctf_integer', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] + when *CL_FLOAT_SCALARS + @lttng_out_type = ['ctf_float', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] else - case type - when *CL_OBJECTS, *CL_EXT_OBJECTS, 'void' - @lttng_out_type = ['ctf_integer_hex', 'uintptr_t', name + '_val', - nocheck ? "(uintptr_t)(*#{name})" : "(uintptr_t)(#{name} == NULL ? 0 : *#{name})"] - when *CL_INT_SCALARS - @lttng_out_type = ['ctf_integer', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] - when *CL_FLOAT_SCALARS - @lttng_out_type = ['ctf_float', type, name + '_val', nocheck ? "*#{name}" : "#{name} == NULL ? 0 : *#{name}"] - else - raise "Unknown Type: #{type.inspect}!" - end + raise "Unknown Type: #{type.inspect}!" end end end From c8d35104f459f3e38c4f2cca76a005220605317f Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 03:06:32 +0000 Subject: [PATCH 12/26] gen: extract shared classify_ast_types, collapse 6 per-backend loops Every AST backend (cuda/hip/mpi/omp/itt/ze) reimplemented the same loop to split typedef'd types into enum/bitfield/struct/union name lists, then derived the `_flags_t` bitfield aliases. Replace all six with one call to a shared classify_ast_types in utils/gen_library_base.rb. Unify the bitfield predicate on name.end_with?('flag_t'). ze previously scanned enum members for a ZE_BIT value expression; this is provably equivalent on the built APIs (ze: 74 bitfields either way, 0 diff in both directions; cuda/hip/mpi/ itt: 0; omp: 6 -> 12 after _flags_t derivation), so no per-backend lambda is needed and the ZE_BIT scan is removed. The now-unused empty-array initializers for the four name-list globals are dropped (classify_ast_types returns them). Also removes the dead `$all_enums.find { ... }` whose result cuda/hip/mpi discarded. Byte-identical: 53/53 oracle cases identical to the devel baseline. Net -71 lines (-115 across backends, +32 shared fn + call sites). Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_cuda_library_base.rb | 17 ++------------ backends/hip/gen_hip_library_base.rb | 17 ++------------ backends/itt/gen_itt_library_base.rb | 26 ++------------------- backends/mpi/gen_mpi_library_base.rb | 17 ++------------ backends/omp/gen_omp_library_base.rb | 25 ++------------------ backends/ze/gen_ze_library_base.rb | 25 ++------------------ utils/gen_library_base.rb | 32 ++++++++++++++++++++++++++ 7 files changed, 44 insertions(+), 115 deletions(-) diff --git a/backends/cuda/gen_cuda_library_base.rb b/backends/cuda/gen_cuda_library_base.rb index 058c72fa4..e1c00100d 100644 --- a/backends/cuda/gen_cuda_library_base.rb +++ b/backends/cuda/gen_cuda_library_base.rb @@ -8,11 +8,6 @@ $all_enums = $cuda_api['enums'] $all_funcs = $cuda_api['functions'] -$all_enum_names = [] -$all_bitfield_names = [] -$all_struct_names = [] -$all_union_names = [] - $objects = $all_types.select do |t| t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) @@ -87,16 +82,8 @@ def to_name_space(name) end end -$all_types.each do |t| - if t.type.is_a? YAMLCAst::Enum - $all_enums.find { |e| t.type.name == e.name } - $all_enum_names.push t.name - elsif t.type.is_a? YAMLCAst::Struct - $all_struct_names.push t.name - elsif t.type.is_a? YAMLCAst::Union - $all_union_names.push t.name - end -end +$all_enum_names, $all_bitfield_names, $all_struct_names, $all_union_names = + classify_ast_types($all_types, $all_enums) FFI_STRUCT = 'FFI::CUDAStruct' FFI_UNION = 'FFI::CUDAUnion' diff --git a/backends/hip/gen_hip_library_base.rb b/backends/hip/gen_hip_library_base.rb index 8ca0f32ba..dd88733d1 100644 --- a/backends/hip/gen_hip_library_base.rb +++ b/backends/hip/gen_hip_library_base.rb @@ -8,11 +8,6 @@ $all_enums = $hip_api['enums'] $all_funcs = $hip_api['functions'] -$all_enum_names = [] -$all_bitfield_names = [] -$all_struct_names = [] -$all_union_names = [] - $objects = $all_types.filter_map do |t| t.name if t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) end @@ -50,16 +45,8 @@ def to_name_space(name) end end -$all_types.each do |t| - if t.type.is_a? YAMLCAst::Enum - $all_enums.find { |e| t.type.name == e.name } - $all_enum_names.push t.name - elsif t.type.is_a? YAMLCAst::Struct - $all_struct_names.push t.name - elsif t.type.is_a? YAMLCAst::Union - $all_union_names.push t.name - end -end +$all_enum_names, $all_bitfield_names, $all_struct_names, $all_union_names = + classify_ast_types($all_types, $all_enums) FFI_STRUCT = 'FFI::HIPStruct' FFI_UNION = 'FFI::HIPUnion' diff --git a/backends/itt/gen_itt_library_base.rb b/backends/itt/gen_itt_library_base.rb index a2da724f6..38f079108 100644 --- a/backends/itt/gen_itt_library_base.rb +++ b/backends/itt/gen_itt_library_base.rb @@ -8,11 +8,6 @@ $all_enums = $itt_api['enums'] $all_funcs = $itt_api['functions'] -$all_enum_names = [] -$all_bitfield_names = [] -$all_struct_names = [] -$all_union_names = [] - $objects = $all_types.select do |t| t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) @@ -63,25 +58,8 @@ def to_name_space(name) name.match(/\A(__itt[dt]?)_/)[1].upcase end -$all_types.each do |t| - if t.type.is_a? YAMLCAst::Enum - enum = $all_enums.find { |e| t.type.name == e.name } - # Handle anonymous enum, and typedef enum - if enum&.name&.end_with?('flag_t') - $all_bitfield_names.push t.name - else - $all_enum_names.push t.name - end - elsif t.type.is_a? YAMLCAst::Struct - $all_struct_names.push t.name - elsif t.type.is_a? YAMLCAst::Union - $all_union_names.push t.name - end -end - -$all_bitfield_names += $all_bitfield_names.select do |n| - n.end_with?('_flag_t') -end.map { |n| n.gsub('_flag_t', '_flags_t') } +$all_enum_names, $all_bitfield_names, $all_struct_names, $all_union_names = + classify_ast_types($all_types, $all_enums) FFI_STRUCT = 'FFI::ITTStruct' FFI_UNION = 'FFI::ITTUnion' diff --git a/backends/mpi/gen_mpi_library_base.rb b/backends/mpi/gen_mpi_library_base.rb index 8695769f3..20028c7c3 100644 --- a/backends/mpi/gen_mpi_library_base.rb +++ b/backends/mpi/gen_mpi_library_base.rb @@ -8,11 +8,6 @@ $all_enums = $mpi_api['enums'] || [] $all_funcs = $mpi_api['functions'] || [] -$all_enum_names = [] -$all_bitfield_names = [] -$all_struct_names = [] -$all_union_names = [] - $objects = $all_types.filter_map do |t| t.name if t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) end @@ -49,16 +44,8 @@ def to_name_space(name) end end -$all_types.each do |t| - if t.type.is_a? YAMLCAst::Enum - $all_enums.find { |e| t.type.name == e.name } - $all_enum_names.push t.name - elsif t.type.is_a? YAMLCAst::Struct - $all_struct_names.push t.name - elsif t.type.is_a? YAMLCAst::Union - $all_union_names.push t.name - end -end +$all_enum_names, $all_bitfield_names, $all_struct_names, $all_union_names = + classify_ast_types($all_types, $all_enums) FFI_STRUCT = 'FFI::MPIStruct' FFI_UNION = 'FFI::MPIUnion' diff --git a/backends/omp/gen_omp_library_base.rb b/backends/omp/gen_omp_library_base.rb index 0040f76a6..693594785 100644 --- a/backends/omp/gen_omp_library_base.rb +++ b/backends/omp/gen_omp_library_base.rb @@ -8,11 +8,6 @@ $all_enums = $ompt_api['enums'] $all_funcs = $ompt_api['functions'] -$all_enum_names = [] -$all_bitfield_names = [] -$all_struct_names = [] -$all_union_names = [] - $objects = $all_types.select do |t| t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) @@ -41,24 +36,8 @@ def to_name_space(name) name.match(/\A(omp[dt]?)_/)[1].upcase end -$all_types.each do |t| - if t.type.is_a? YAMLCAst::Enum - enum = $all_enums.find { |e| t.type.name == e.name } - if enum.name.end_with?('flag_t') - $all_bitfield_names.push t.name - else - $all_enum_names.push t.name - end - elsif t.type.is_a? YAMLCAst::Struct - $all_struct_names.push t.name - elsif t.type.is_a? YAMLCAst::Union - $all_union_names.push t.name - end -end - -$all_bitfield_names += $all_bitfield_names.select do |n| - n.end_with?('_flag_t') -end.map { |n| n.gsub('_flag_t', '_flags_t') } +$all_enum_names, $all_bitfield_names, $all_struct_names, $all_union_names = + classify_ast_types($all_types, $all_enums) FFI_STRUCT = 'FFI::OMPTStruct' FFI_UNION = 'FFI::OMPTUnion' diff --git a/backends/ze/gen_ze_library_base.rb b/backends/ze/gen_ze_library_base.rb index 2d3b09a5c..c76753ebb 100644 --- a/backends/ze/gen_ze_library_base.rb +++ b/backends/ze/gen_ze_library_base.rb @@ -8,11 +8,6 @@ $all_enums = $ze_api['enums'] + $zet_api['enums'] + $zes_api['enums'] + $zel_api['enums'] $all_funcs = $ze_api['functions'] + $zet_api['functions'] + $zes_api['functions'] + $zel_api['functions'] -$all_enum_names = [] -$all_bitfield_names = [] -$all_struct_names = [] -$all_union_names = [] - $objects = $all_types.select do |t| t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) @@ -41,24 +36,8 @@ def to_name_space(name) name.match(/\A(ze[xstlr]?)_/)[1].upcase end -$all_types.each do |t| - if t.type.is_a? YAMLCAst::Enum - enum = $all_enums.find { |e| t.type.name == e.name } - if enum.members.find { |m| m.val && m.val.is_a?(String) && m.val.match('ZE_BIT') } - $all_bitfield_names.push t.name - else - $all_enum_names.push t.name - end - elsif t.type.is_a? YAMLCAst::Struct - $all_struct_names.push t.name - elsif t.type.is_a? YAMLCAst::Union - $all_union_names.push t.name - end -end - -$all_bitfield_names += $all_bitfield_names.select do |n| - n.end_with?('_flag_t') -end.map { |n| n.gsub('_flag_t', '_flags_t') } +$all_enum_names, $all_bitfield_names, $all_struct_names, $all_union_names = + classify_ast_types($all_types, $all_enums) FFI_STRUCT = 'FFI::ZEStruct' FFI_UNION = 'FFI::ZEUnion' diff --git a/utils/gen_library_base.rb b/utils/gen_library_base.rb index 7c5b26b6b..dcb0bdf30 100644 --- a/utils/gen_library_base.rb +++ b/utils/gen_library_base.rb @@ -1,5 +1,37 @@ require_relative 'yaml_ast' +# Classify a backend's typedef'd types into enum / bitfield / struct / union +# name lists (in typedef order). A typedef'd enum whose underlying enum name +# ends in `flag_t` is treated as a bitfield (OR-able flags); every other enum +# is a plain enum. Each `_flag_t` bitfield additionally aliases the `_flags_t` +# name the headers use for the OR'd value. Backends with no `flag_t` enums get +# an empty bitfield list (the `flag_t` test and `_flags_t` derivation are then +# no-ops), so the same rule serves all backends. +def classify_ast_types(all_types, all_enums) + enum_names = [] + bitfield_names = [] + struct_names = [] + union_names = [] + all_types.each do |t| + case t.type + when YAMLCAst::Enum + enum = all_enums.find { |e| t.type.name == e.name } + if enum&.name&.end_with?('flag_t') + bitfield_names.push t.name + else + enum_names.push t.name + end + when YAMLCAst::Struct + struct_names.push t.name + when YAMLCAst::Union + union_names.push t.name + end + end + bitfield_names += bitfield_names.select { |n| n.end_with?('_flag_t') } + .map { |n| n.gsub('_flag_t', '_flags_t') } + [enum_names, bitfield_names, struct_names, union_names] +end + def has_typedef?(name) $all_types.any? { |t| t.type.respond_to?(:name) && t.type.name == name } end From c888bac419aa0874a5eff41f568470e1fd94327a Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 03:27:51 +0000 Subject: [PATCH 13/26] Dedup meta-parameter YAML loading into load_meta_parameters helper Every AST backend repeated the same 6-line block per meta-parameter YAML: load the file, iterate meta_parameters, const_get the type, register. Fold that into a single load_meta_parameters(filename) helper in utils/command.rb and replace all 12 call sites (hip, mpi, omp, itt, cuda x2, cudart, ze x5). Byte-identical: oracle 53/53. opencl left untouched (its own Command class, does not require utils/command.rb). Co-Authored-By: Claude Opus 4.8 --- backends/cuda/cuda_model.rb | 14 ++--------- backends/cuda/cudart_model.rb | 7 +----- backends/hip/hip_model.rb | 7 +----- backends/itt/itt_model.rb | 7 +----- backends/mpi/mpi_model.rb | 7 +----- backends/omp/ompt_model.rb | 7 +----- backends/ze/ze_model.rb | 46 +++++------------------------------ utils/command.rb | 12 +++++++++ 8 files changed, 25 insertions(+), 82 deletions(-) diff --git a/backends/cuda/cuda_model.rb b/backends/cuda/cuda_model.rb index a02a0b065..527cb1a2f 100644 --- a/backends/cuda/cuda_model.rb +++ b/backends/cuda/cuda_model.rb @@ -81,18 +81,8 @@ def initialize(command, name) end end -$cuda_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'cuda_meta_parameters.yaml')) -$cuda_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end -$cuda_exports_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'cuda_exports_meta_parameters.yaml')) -$cuda_exports_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('cuda_meta_parameters.yaml') +load_meta_parameters('cuda_exports_meta_parameters.yaml') $cuda_commands = cuda_funcs_e.collect do |func| Command.new(func) diff --git a/backends/cuda/cudart_model.rb b/backends/cuda/cudart_model.rb index 656183512..1f9123c35 100644 --- a/backends/cuda/cudart_model.rb +++ b/backends/cuda/cudart_model.rb @@ -24,12 +24,7 @@ # Currently ignored by gen_cudart.rb INIT_FUNCTIONS = /.*/ -$cudart_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'cudart_meta_parameters.yaml')) -$cudart_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('cudart_meta_parameters.yaml') $cudart_commands = funcs.collect do |func| Command.new(func) diff --git a/backends/hip/hip_model.rb b/backends/hip/hip_model.rb index 60c69b52a..8f9035fc5 100644 --- a/backends/hip/hip_model.rb +++ b/backends/hip/hip_model.rb @@ -24,12 +24,7 @@ INIT_FUNCTIONS = /.*/ -$hip_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'hip_meta_parameters.yaml')) -$hip_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('hip_meta_parameters.yaml') $hip_commands = funcs.collect do |func| Command.new(func) diff --git a/backends/itt/itt_model.rb b/backends/itt/itt_model.rb index 4f3c9dd41..fa5e5a606 100644 --- a/backends/itt/itt_model.rb +++ b/backends/itt/itt_model.rb @@ -21,12 +21,7 @@ INIT_FUNCTIONS = /None/ -$itt_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'itt_meta_parameters.yaml')) -$itt_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('itt_meta_parameters.yaml') # Function we care whitelisted_functions = %w[ diff --git a/backends/mpi/mpi_model.rb b/backends/mpi/mpi_model.rb index c8f3cc56c..e271057d3 100644 --- a/backends/mpi/mpi_model.rb +++ b/backends/mpi/mpi_model.rb @@ -55,12 +55,7 @@ P?MPI_T_init_thread)\b /ix -$mpi_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'mpi_meta_parameters.yaml')) -$mpi_meta_parameters.fetch('meta_parameters', []).each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('mpi_meta_parameters.yaml') $mpi_commands = mpi_funcs_e.collect do |func| Command.new(func) diff --git a/backends/omp/ompt_model.rb b/backends/omp/ompt_model.rb index e3e9ef240..83afbf040 100644 --- a/backends/omp/ompt_model.rb +++ b/backends/omp/ompt_model.rb @@ -29,12 +29,7 @@ INIT_FUNCTIONS = /None/ -$ompt_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'ompt_meta_parameters.yaml')) -$ompt_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('ompt_meta_parameters.yaml') $ompt_commands = OMPT_CALLBACKS.collect do |func| Command.new(func) diff --git a/backends/ze/ze_model.rb b/backends/ze/ze_model.rb index b9fd4b8e7..5604286a2 100644 --- a/backends/ze/ze_model.rb +++ b/backends/ze/ze_model.rb @@ -64,46 +64,12 @@ $struct_type_reject = Set.new(['zet_metric_source_id_exp_t']) -$ze_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'ze_meta_parameters.yaml')) -$ze_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end -$zet_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'zet_meta_parameters.yaml')) -$zet_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end - -$zes_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'zes_meta_parameters.yaml')) -$zes_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end - -$zel_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'zel_meta_parameters.yaml')) -$zel_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end - -# $zer_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'zer_meta_parameters.yaml')) -# $zer_meta_parameters['meta_parameters'].each do |func, list| -# list.each do |type, *args| -# register_meta_parameter func, Kernel.const_get(type), *args -# end -# end - -$zex_meta_parameters = YAML.load_file(File.join(SRC_DIR, 'zex_meta_parameters.yaml')) -$zex_meta_parameters['meta_parameters'].each do |func, list| - list.each do |type, *args| - register_meta_parameter func, Kernel.const_get(type), *args - end -end +load_meta_parameters('ze_meta_parameters.yaml') +load_meta_parameters('zet_meta_parameters.yaml') +load_meta_parameters('zes_meta_parameters.yaml') +load_meta_parameters('zel_meta_parameters.yaml') +# zer disabled: load_meta_parameters('zer_meta_parameters.yaml') +load_meta_parameters('zex_meta_parameters.yaml') $ze_commands = ze_funcs_e.collect do |func| Command.new(func) diff --git a/utils/command.rb b/utils/command.rb index 7ef5e402e..f2b014147 100644 --- a/utils/command.rb +++ b/utils/command.rb @@ -1,3 +1,5 @@ +require 'yaml' + class Command attr_reader :tracepoint_parameters, :meta_parameters, :prologues, :epilogues, :function @@ -114,6 +116,16 @@ def register_meta_parameter(method, type, *args) META_PARAMETERS[method].push [type, args] end +# Load a backend's meta-parameter YAML (relative to SRC_DIR) and register every +# entry. The file maps each function name to a list of [type, *args] rows. +def load_meta_parameters(filename) + YAML.load_file(File.join(SRC_DIR, filename)).fetch('meta_parameters', []).each do |func, list| + list.each do |type, *args| + register_meta_parameter func, Kernel.const_get(type), *args + end + end +end + def register_meta_struct(method, name, type) raise "Unknown struct: #{type}!" unless STRUCT_TYPES.include?(type) From bd19b7f85392ffebc7d211bba3ff2c2c43bedf60 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 03:36:16 +0000 Subject: [PATCH 14/26] Dedup upper_snake_case into utils/LTTng.rb The identical 3-line upper_snake_case helper was copy-pasted into 7 backend model files (itt, cuda, cudart, hip, ze, ompt, opencl). Define it once at the top of utils/LTTng.rb, which every backend already requires, and drop the duplicates. mpi has its own distinct underscore() and is untouched. Byte-identical: oracle 53/53. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/cuda_model.rb | 4 ---- backends/cuda/cudart_model.rb | 4 ---- backends/hip/hip_model.rb | 4 ---- backends/itt/itt_model.rb | 4 ---- backends/omp/ompt_model.rb | 4 ---- backends/opencl/opencl_model.rb | 4 ---- backends/ze/ze_model.rb | 4 ---- utils/LTTng.rb | 4 ++++ 8 files changed, 4 insertions(+), 28 deletions(-) diff --git a/backends/cuda/cuda_model.rb b/backends/cuda/cuda_model.rb index 527cb1a2f..b646d360d 100644 --- a/backends/cuda/cuda_model.rb +++ b/backends/cuda/cuda_model.rb @@ -92,10 +92,6 @@ def initialize(command, name) Command.new(func) end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - CUDA_POINTER_NAMES = ($cuda_commands + $cuda_exports_commands).collect do |c| [c, upper_snake_case(c.pointer_name)] diff --git a/backends/cuda/cudart_model.rb b/backends/cuda/cudart_model.rb index 1f9123c35..329f31310 100644 --- a/backends/cuda/cudart_model.rb +++ b/backends/cuda/cudart_model.rb @@ -30,10 +30,6 @@ Command.new(func) end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - CUDART_POINTER_NAMES = $cudart_commands.collect do |c| [c, upper_snake_case(c.pointer_name)] end.to_h diff --git a/backends/hip/hip_model.rb b/backends/hip/hip_model.rb index 8f9035fc5..42e399417 100644 --- a/backends/hip/hip_model.rb +++ b/backends/hip/hip_model.rb @@ -30,10 +30,6 @@ Command.new(func) end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - HIP_POINTER_NAMES = $hip_commands.collect do |c| [c, upper_snake_case(c.pointer_name)] end.to_h diff --git a/backends/itt/itt_model.rb b/backends/itt/itt_model.rb index fa5e5a606..982464c70 100644 --- a/backends/itt/itt_model.rb +++ b/backends/itt/itt_model.rb @@ -41,10 +41,6 @@ Command.new(func) end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - ITT_POINTER_NAMES = $itt_commands.collect do |c| [c, upper_snake_case(c.pointer_name)] end.to_h diff --git a/backends/omp/ompt_model.rb b/backends/omp/ompt_model.rb index 83afbf040..b6b8296a7 100644 --- a/backends/omp/ompt_model.rb +++ b/backends/omp/ompt_model.rb @@ -35,10 +35,6 @@ Command.new(func) end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - OMPT_POINTER_NAMES = $ompt_commands.collect do |c| [c, upper_snake_case(c.pointer_name)] end.to_h diff --git a/backends/opencl/opencl_model.rb b/backends/opencl/opencl_model.rb index 56d592d68..bc5e88599 100644 --- a/backends/opencl/opencl_model.rb +++ b/backends/opencl/opencl_model.rb @@ -718,10 +718,6 @@ def void_parameters? eval "$#{c.prototype.name} = c" end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - OPENCL_POINTER_NAMES = ($opencl_commands.collect do |c| [c, upper_snake_case(c.prototype.pointer_name)] end + $opencl_extension_commands.collect do |c| diff --git a/backends/ze/ze_model.rb b/backends/ze/ze_model.rb index 5604286a2..ddee2bf84 100644 --- a/backends/ze/ze_model.rb +++ b/backends/ze/ze_model.rb @@ -95,10 +95,6 @@ Command.new(func) end -def upper_snake_case(str) - str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase -end - ze_pointer_names = ($ze_commands + $zet_commands + $zes_commands + $zel_commands + $zer_commands).collect do |c| [c, upper_snake_case(c.pointer_name)] end diff --git a/utils/LTTng.rb b/utils/LTTng.rb index 2c2958c9b..5034d0c46 100644 --- a/utils/LTTng.rb +++ b/utils/LTTng.rb @@ -1,5 +1,9 @@ MEMBER_SEPARATOR = '__' +def upper_snake_case(str) + str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').upcase +end + module LTTng class TracepointField FIELDS = { From 37a5a4b542219d3d09b2dcc4ebe9a68ff81f72a6 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 03:45:03 +0000 Subject: [PATCH 15/26] babeltrace-model: fold TypeRegistry construction into build_ast_registry All 6 AST gen_babeltrace__model.rb files repeated the identical 5-line TypeRegistry.from_ast(...) call reading the same globals, followed by a per-backend bitfield-presence assertion. Fold both into build_ast_registry( backend, expect_bitfields:) in gen_babeltrace_model_helper.rb; the invariant (ze/omp have bitfields, cuda/hip/mpi/itt do not) is preserved via the flag. Byte-identical: oracle 53/53. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_babeltrace_cuda_model.rb | 7 +------ backends/hip/gen_babeltrace_hip_model.rb | 7 +------ backends/itt/gen_babeltrace_itt_model.rb | 7 +------ backends/mpi/gen_babeltrace_mpi_model.rb | 7 +------ backends/omp/gen_babeltrace_omp_model.rb | 7 +------ backends/ze/gen_babeltrace_ze_model.rb | 7 +------ utils/gen_babeltrace_model_helper.rb | 17 +++++++++++++++++ 7 files changed, 23 insertions(+), 36 deletions(-) diff --git a/backends/cuda/gen_babeltrace_cuda_model.rb b/backends/cuda/gen_babeltrace_cuda_model.rb index 5ae5361bf..23ebcf1a2 100644 --- a/backends/cuda/gen_babeltrace_cuda_model.rb +++ b/backends/cuda/gen_babeltrace_cuda_model.rb @@ -1,12 +1,7 @@ require_relative 'gen_cuda_library_base' require_relative '../../utils/gen_babeltrace_model_helper' -registry = TypeRegistry.from_ast( - all_types: $all_types, all_enums: $all_enums, - enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), -) -raise 'cuda: expected no bitfield types' unless registry.bitfield_names.empty? +registry = build_ast_registry('cuda', expect_bitfields: false) event_classes = [[:lttng_ust_cuda, $cuda_commands], diff --git a/backends/hip/gen_babeltrace_hip_model.rb b/backends/hip/gen_babeltrace_hip_model.rb index a0c96240b..8e135bb92 100644 --- a/backends/hip/gen_babeltrace_hip_model.rb +++ b/backends/hip/gen_babeltrace_hip_model.rb @@ -1,12 +1,7 @@ require_relative 'gen_hip_library_base' require_relative '../../utils/gen_babeltrace_model_helper' -registry = TypeRegistry.from_ast( - all_types: $all_types, all_enums: $all_enums, - enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), -) -raise 'hip: expected no bitfield types' unless registry.bitfield_names.empty? +registry = build_ast_registry('hip', expect_bitfields: false) event_classes = [[:lttng_ust_hip, $hip_commands]].collect do |provider, commands| diff --git a/backends/itt/gen_babeltrace_itt_model.rb b/backends/itt/gen_babeltrace_itt_model.rb index 9dd30749b..eb7a3028a 100644 --- a/backends/itt/gen_babeltrace_itt_model.rb +++ b/backends/itt/gen_babeltrace_itt_model.rb @@ -1,12 +1,7 @@ require_relative 'gen_itt_library_base' require_relative '../../utils/gen_babeltrace_model_helper' -registry = TypeRegistry.from_ast( - all_types: $all_types, all_enums: $all_enums, - enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), -) -raise 'itt: expected no bitfield types' unless registry.bitfield_names.empty? +registry = build_ast_registry('itt', expect_bitfields: false) event_classes = [[:lttng_ust_itt, $itt_commands]].collect do |provider, commands| diff --git a/backends/mpi/gen_babeltrace_mpi_model.rb b/backends/mpi/gen_babeltrace_mpi_model.rb index a2781c3ad..de657ae90 100644 --- a/backends/mpi/gen_babeltrace_mpi_model.rb +++ b/backends/mpi/gen_babeltrace_mpi_model.rb @@ -1,12 +1,7 @@ require_relative 'gen_mpi_library_base' require_relative '../../utils/gen_babeltrace_model_helper' -registry = TypeRegistry.from_ast( - all_types: $all_types, all_enums: $all_enums, - enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), -) -raise 'mpi: expected no bitfield types' unless registry.bitfield_names.empty? +registry = build_ast_registry('mpi', expect_bitfields: false) event_classes = [[:lttng_ust_mpi, $mpi_commands]].collect do |provider, commands| diff --git a/backends/omp/gen_babeltrace_omp_model.rb b/backends/omp/gen_babeltrace_omp_model.rb index 68c97d0ae..66f9ebcce 100644 --- a/backends/omp/gen_babeltrace_omp_model.rb +++ b/backends/omp/gen_babeltrace_omp_model.rb @@ -1,12 +1,7 @@ require_relative 'gen_omp_library_base' require_relative '../../utils/gen_babeltrace_model_helper' -registry = TypeRegistry.from_ast( - all_types: $all_types, all_enums: $all_enums, - enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), -) -raise 'omp: expected bitfield types' if registry.bitfield_names.empty? +registry = build_ast_registry('omp', expect_bitfields: true) event_classes = [[:lttng_ust_ompt, $ompt_commands]].collect do |provider, commands| diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index 4d00368dd..f5bb304c8 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -2,12 +2,7 @@ require_relative '../../utils/gen_babeltrace_model_helper' require 'set' -registry = TypeRegistry.from_ast( - all_types: $all_types, all_enums: $all_enums, - enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), -) -raise 'ze: expected bitfield types' if registry.bitfield_names.empty? +registry = build_ast_registry('ze', expect_bitfields: true) event_classes = [[:lttng_ust_ze, $ze_commands], diff --git a/utils/gen_babeltrace_model_helper.rb b/utils/gen_babeltrace_model_helper.rb index 3f6d508cd..fe1f7fc22 100644 --- a/utils/gen_babeltrace_model_helper.rb +++ b/utils/gen_babeltrace_model_helper.rb @@ -2,6 +2,23 @@ require_relative 'yaml_ast' require_relative 'type_registry' +# Build the babeltrace TypeRegistry for an AST backend from its load-time +# globals and assert the per-backend bitfield invariant: ze/omp have bitfield +# types, cuda/hip/mpi/itt have none (see the babeltrace-model bitfield note). +def build_ast_registry(backend, expect_bitfields:) + registry = TypeRegistry.from_ast( + all_types: $all_types, all_enums: $all_enums, + enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, + class_namer: method(:to_scoped_class_name), + ) + if expect_bitfields + raise "#{backend}: expected bitfield types" if registry.bitfield_names.empty? + else + raise "#{backend}: expected no bitfield types" unless registry.bitfield_names.empty? + end + registry +end + def meta_parameter_types_name(m, dir = nil) lttng = if dir == :start m.lttng_in_type From fb7826a11ce551e5e8027cee22123f3b634109c7 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 03:54:03 +0000 Subject: [PATCH 16/26] babeltrace-model: fold command/extra event loops into shared helpers All 6 AST gen_babeltrace__model.rb files repeated the same two loops: one building [start, stop] event pairs per command (or a single event for the itt/omp phased:false case), and one building the extra events declared in _events.yaml. Extract gen_command_events_bt_model(registry, provider_commands, phased:) and gen_extra_events_bt_model(registry, filename) into gen_babeltrace_model_helper.rb and collapse the call sites. Byte-identical: oracle 53/53. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_babeltrace_cuda_model.rb | 17 +++------------ backends/hip/gen_babeltrace_hip_model.rb | 16 ++------------ backends/itt/gen_babeltrace_itt_model.rb | 15 ++----------- backends/mpi/gen_babeltrace_mpi_model.rb | 16 ++------------ backends/omp/gen_babeltrace_omp_model.rb | 7 +----- backends/ze/gen_babeltrace_ze_model.rb | 17 +++------------ utils/gen_babeltrace_model_helper.rb | 25 ++++++++++++++++++++++ 7 files changed, 38 insertions(+), 75 deletions(-) diff --git a/backends/cuda/gen_babeltrace_cuda_model.rb b/backends/cuda/gen_babeltrace_cuda_model.rb index 23ebcf1a2..de0d23b19 100644 --- a/backends/cuda/gen_babeltrace_cuda_model.rb +++ b/backends/cuda/gen_babeltrace_cuda_model.rb @@ -3,20 +3,9 @@ registry = build_ast_registry('cuda', expect_bitfields: false) -event_classes = +event_classes = gen_command_events_bt_model(registry, [[:lttng_ust_cuda, $cuda_commands], - [:lttng_ust_cuda_exports, $cuda_exports_commands]].collect do |provider, commands| - commands.collect do |c| - [gen_event_bt_model(registry, provider, c, :start), - gen_event_bt_model(registry, provider, c, :stop)] - end - end.flatten(2) - -cuda_events = YAML.load_file(File.join(SRC_DIR, 'cuda_events.yaml')) -event_classes += cuda_events.collect do |provider, es| - es['events'].collect do |event| - gen_extra_event_bt_model(registry, provider, event) - end -end.flatten + [:lttng_ust_cuda_exports, $cuda_exports_commands]]) +event_classes += gen_extra_events_bt_model(registry, 'cuda_events.yaml') puts YAML.dump(gen_yaml(event_classes, 'cuda')) diff --git a/backends/hip/gen_babeltrace_hip_model.rb b/backends/hip/gen_babeltrace_hip_model.rb index 8e135bb92..ff2df4577 100644 --- a/backends/hip/gen_babeltrace_hip_model.rb +++ b/backends/hip/gen_babeltrace_hip_model.rb @@ -3,19 +3,7 @@ registry = build_ast_registry('hip', expect_bitfields: false) -event_classes = - [[:lttng_ust_hip, $hip_commands]].collect do |provider, commands| - commands.collect do |c| - [gen_event_bt_model(registry, provider, c, :start), - gen_event_bt_model(registry, provider, c, :stop)] - end - end.flatten(2) - -hip_events = YAML.load_file(File.join(SRC_DIR, 'hip_events.yaml')) -event_classes += hip_events.collect do |provider, es| - es['events'].collect do |event| - gen_extra_event_bt_model(registry, provider, event) - end -end.flatten +event_classes = gen_command_events_bt_model(registry, [[:lttng_ust_hip, $hip_commands]]) +event_classes += gen_extra_events_bt_model(registry, 'hip_events.yaml') puts YAML.dump(gen_yaml(event_classes, 'hip')) diff --git a/backends/itt/gen_babeltrace_itt_model.rb b/backends/itt/gen_babeltrace_itt_model.rb index eb7a3028a..38e154f29 100644 --- a/backends/itt/gen_babeltrace_itt_model.rb +++ b/backends/itt/gen_babeltrace_itt_model.rb @@ -3,18 +3,7 @@ registry = build_ast_registry('itt', expect_bitfields: false) -event_classes = - [[:lttng_ust_itt, $itt_commands]].collect do |provider, commands| - commands.collect do |c| - [gen_event_bt_model(registry, provider, c)] - end - end.flatten(2) - -itt_events = YAML.load_file(File.join(SRC_DIR, 'itt_events.yaml')) -event_classes += itt_events.collect do |provider, es| - es['events'].collect do |event| - gen_extra_event_bt_model(registry, provider, event) - end -end.flatten +event_classes = gen_command_events_bt_model(registry, [[:lttng_ust_itt, $itt_commands]], phased: false) +event_classes += gen_extra_events_bt_model(registry, 'itt_events.yaml') puts YAML.dump(gen_yaml(event_classes, 'itt')) diff --git a/backends/mpi/gen_babeltrace_mpi_model.rb b/backends/mpi/gen_babeltrace_mpi_model.rb index de657ae90..c0fd06386 100644 --- a/backends/mpi/gen_babeltrace_mpi_model.rb +++ b/backends/mpi/gen_babeltrace_mpi_model.rb @@ -3,19 +3,7 @@ registry = build_ast_registry('mpi', expect_bitfields: false) -event_classes = - [[:lttng_ust_mpi, $mpi_commands]].collect do |provider, commands| - commands.collect do |c| - [gen_event_bt_model(registry, provider, c, :start), - gen_event_bt_model(registry, provider, c, :stop)] - end - end.flatten(2) - -mpi_events = YAML.load_file(File.join(SRC_DIR, 'mpi_events.yaml')) -event_classes += mpi_events.collect do |provider, es| - es['events'].collect do |event| - gen_extra_event_bt_model(registry, provider, event) - end -end.flatten +event_classes = gen_command_events_bt_model(registry, [[:lttng_ust_mpi, $mpi_commands]]) +event_classes += gen_extra_events_bt_model(registry, 'mpi_events.yaml') puts YAML.dump(gen_yaml(event_classes, 'mpi')) diff --git a/backends/omp/gen_babeltrace_omp_model.rb b/backends/omp/gen_babeltrace_omp_model.rb index 66f9ebcce..dfd1be087 100644 --- a/backends/omp/gen_babeltrace_omp_model.rb +++ b/backends/omp/gen_babeltrace_omp_model.rb @@ -3,11 +3,6 @@ registry = build_ast_registry('omp', expect_bitfields: true) -event_classes = - [[:lttng_ust_ompt, $ompt_commands]].collect do |provider, commands| - commands.collect do |c| - [gen_event_bt_model(registry, provider, c)] - end - end.flatten(2) +event_classes = gen_command_events_bt_model(registry, [[:lttng_ust_ompt, $ompt_commands]], phased: false) puts YAML.dump(gen_yaml(event_classes, 'omp')) diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index f5bb304c8..6c6d6aa33 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -4,25 +4,14 @@ registry = build_ast_registry('ze', expect_bitfields: true) -event_classes = +event_classes = gen_command_events_bt_model(registry, [[:lttng_ust_ze, $ze_commands], [:lttng_ust_zet, $zet_commands], [:lttng_ust_zes, $zes_commands], [:lttng_ust_zel, $zel_commands], [:lttng_ust_zer, $zer_commands], - [:lttng_ust_zex, $zex_commands]].collect do |provider, commands| - commands.collect do |c| - [gen_event_bt_model(registry, provider, c, :start), - gen_event_bt_model(registry, provider, c, :stop)] - end - end.flatten(2) - -ze_events = YAML.load_file(File.join(SRC_DIR, 'ze_events.yaml')) -event_classes += ze_events.collect do |provider, es| - es['events'].collect do |event| - gen_extra_event_bt_model(registry, provider, event) - end -end.flatten + [:lttng_ust_zex, $zex_commands]]) +event_classes += gen_extra_events_bt_model(registry, 'ze_events.yaml') def get_structs_types(namespace, types, structs) types.select do |t| diff --git a/utils/gen_babeltrace_model_helper.rb b/utils/gen_babeltrace_model_helper.rb index fe1f7fc22..7f68aaaa6 100644 --- a/utils/gen_babeltrace_model_helper.rb +++ b/utils/gen_babeltrace_model_helper.rb @@ -204,6 +204,31 @@ def gen_extra_event_bt_model(registry, provider, event) d end +# Build the command event classes for a backend: one [start, stop] pair per +# command (phased), or a single event per command for itt/omp (phased: false). +# provider_commands is a list of [provider_symbol, commands] pairs. +def gen_command_events_bt_model(registry, provider_commands, phased: true) + provider_commands.collect do |provider, commands| + commands.collect do |c| + if phased + [gen_event_bt_model(registry, provider, c, :start), + gen_event_bt_model(registry, provider, c, :stop)] + else + [gen_event_bt_model(registry, provider, c)] + end + end + end.flatten(2) +end + +# Build the "extra" event classes declared in a backend's _events.yaml. +def gen_extra_events_bt_model(registry, filename) + YAML.load_file(File.join(SRC_DIR, filename)).collect do |provider, es| + es['events'].collect do |event| + gen_extra_event_bt_model(registry, provider, event) + end + end.flatten +end + def gen_yaml(event_classes, backend) { environment: { entries: [ From 5c87e293bfbf69b85bf4ff39fd8bb8ca971bccdb Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Thu, 30 Jul 2026 04:06:16 +0000 Subject: [PATCH 17/26] gen: extract find_objects / find_int_scalars from library-base files All 6 AST gen__library_base.rb files derived $objects (pointer-to-struct typedefs plus CustomType aliases of OBJECT_TYPES) and $int_scalars (typedefs aliasing integer types) with the same two loops. Extract find_objects(all_types, extra:) and find_int_scalars(all_types) into utils/gen_library_base.rb; hip's one seeded name is threaded via extra:. Unlike load_meta_parameters these helpers RETURN their result (assigned explicitly at the call site) rather than mutating a global. Byte-identical: oracle 53/53. Co-Authored-By: Claude Opus 4.8 --- backends/cuda/gen_cuda_library_base.rb | 15 ++------------- backends/hip/gen_hip_library_base.rb | 15 ++------------- backends/itt/gen_itt_library_base.rb | 15 ++------------- backends/mpi/gen_mpi_library_base.rb | 14 ++------------ backends/omp/gen_omp_library_base.rb | 15 ++------------- backends/ze/gen_ze_library_base.rb | 15 ++------------- utils/gen_library_base.rb | 23 +++++++++++++++++++++++ 7 files changed, 35 insertions(+), 77 deletions(-) diff --git a/backends/cuda/gen_cuda_library_base.rb b/backends/cuda/gen_cuda_library_base.rb index e1c00100d..79157f7dc 100644 --- a/backends/cuda/gen_cuda_library_base.rb +++ b/backends/cuda/gen_cuda_library_base.rb @@ -8,19 +8,8 @@ $all_enums = $cuda_api['enums'] $all_funcs = $cuda_api['functions'] -$objects = $all_types.select do |t| - t.type.is_a?(YAMLCAst::Pointer) && - t.type.type.is_a?(YAMLCAst::Struct) -end.collect { |t| t.name } - -$all_types.each do |t| - $objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) -end - -$int_scalars = {} -$all_types.each do |t| - $int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) -end +$objects = find_objects($all_types) +$int_scalars = find_int_scalars($all_types) def to_snake_case(str) str.gsub(/([A-Z][A-Z0-9]*)/, '_\1').downcase diff --git a/backends/hip/gen_hip_library_base.rb b/backends/hip/gen_hip_library_base.rb index dd88733d1..1ee412a37 100644 --- a/backends/hip/gen_hip_library_base.rb +++ b/backends/hip/gen_hip_library_base.rb @@ -8,19 +8,8 @@ $all_enums = $hip_api['enums'] $all_funcs = $hip_api['functions'] -$objects = $all_types.filter_map do |t| - t.name if t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) -end -$objects.push 'hipGraphicsResource_t' - -$all_types.each do |t| - $objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) -end - -$int_scalars = {} -$all_types.each do |t| - $int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) -end +$objects = find_objects($all_types, extra: ['hipGraphicsResource_t']) +$int_scalars = find_int_scalars($all_types) def to_class_name(name) mod = to_name_space(name) diff --git a/backends/itt/gen_itt_library_base.rb b/backends/itt/gen_itt_library_base.rb index 38f079108..46980143b 100644 --- a/backends/itt/gen_itt_library_base.rb +++ b/backends/itt/gen_itt_library_base.rb @@ -8,19 +8,8 @@ $all_enums = $itt_api['enums'] $all_funcs = $itt_api['functions'] -$objects = $all_types.select do |t| - t.type.is_a?(YAMLCAst::Pointer) && - t.type.type.is_a?(YAMLCAst::Struct) -end.collect { |t| t.name } - -$all_types.each do |t| - $objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) -end - -$int_scalars = {} -$all_types.each do |t| - $int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) -end +$objects = find_objects($all_types) +$int_scalars = find_int_scalars($all_types) # Convert C / ITT names (e.g. "__itt_domain_t") to Ruby CamelCase class names def to_class_name(name) diff --git a/backends/mpi/gen_mpi_library_base.rb b/backends/mpi/gen_mpi_library_base.rb index 20028c7c3..6104bf2bd 100644 --- a/backends/mpi/gen_mpi_library_base.rb +++ b/backends/mpi/gen_mpi_library_base.rb @@ -8,18 +8,8 @@ $all_enums = $mpi_api['enums'] || [] $all_funcs = $mpi_api['functions'] || [] -$objects = $all_types.filter_map do |t| - t.name if t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) -end - -$all_types.each do |t| - $objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) -end - -$int_scalars = {} -$all_types.each do |t| - $int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) -end +$objects = find_objects($all_types) +$int_scalars = find_int_scalars($all_types) def to_class_name(name) mod = to_name_space(name) diff --git a/backends/omp/gen_omp_library_base.rb b/backends/omp/gen_omp_library_base.rb index 693594785..e9a24851e 100644 --- a/backends/omp/gen_omp_library_base.rb +++ b/backends/omp/gen_omp_library_base.rb @@ -8,19 +8,8 @@ $all_enums = $ompt_api['enums'] $all_funcs = $ompt_api['functions'] -$objects = $all_types.select do |t| - t.type.is_a?(YAMLCAst::Pointer) && - t.type.type.is_a?(YAMLCAst::Struct) -end.collect { |t| t.name } - -$all_types.each do |t| - $objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) -end - -$int_scalars = {} -$all_types.each do |t| - $int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) -end +$objects = find_objects($all_types) +$int_scalars = find_int_scalars($all_types) def to_class_name(name) mod = to_name_space(name) diff --git a/backends/ze/gen_ze_library_base.rb b/backends/ze/gen_ze_library_base.rb index c76753ebb..63cebf005 100644 --- a/backends/ze/gen_ze_library_base.rb +++ b/backends/ze/gen_ze_library_base.rb @@ -8,19 +8,8 @@ $all_enums = $ze_api['enums'] + $zet_api['enums'] + $zes_api['enums'] + $zel_api['enums'] $all_funcs = $ze_api['functions'] + $zet_api['functions'] + $zes_api['functions'] + $zel_api['functions'] -$objects = $all_types.select do |t| - t.type.is_a?(YAMLCAst::Pointer) && - t.type.type.is_a?(YAMLCAst::Struct) -end.collect { |t| t.name } - -$all_types.each do |t| - $objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) -end - -$int_scalars = {} -$all_types.each do |t| - $int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) -end +$objects = find_objects($all_types) +$int_scalars = find_int_scalars($all_types) def to_class_name(name) mod = to_name_space(name) diff --git a/utils/gen_library_base.rb b/utils/gen_library_base.rb index dcb0bdf30..b9bc213b1 100644 --- a/utils/gen_library_base.rb +++ b/utils/gen_library_base.rb @@ -32,6 +32,29 @@ def classify_ast_types(all_types, all_enums) [enum_names, bitfield_names, struct_names, union_names] end +# Collect the "object" type names: typedefs of pointer-to-struct, plus any +# CustomType aliasing a known OBJECT_TYPES name. `extra` names are inserted +# after the pointer-to-struct seed and before the alias pass (hip seeds one). +def find_objects(all_types, extra: []) + objects = all_types.filter_map do |t| + t.name if t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Struct) + end + objects.concat(extra) + all_types.each do |t| + objects.push t.name if t.type.is_a?(YAMLCAst::CustomType) && OBJECT_TYPES.include?(t.type.name) + end + objects +end + +# Map each typedef that aliases an integer type to that underlying type name. +def find_int_scalars(all_types) + int_scalars = {} + all_types.each do |t| + int_scalars[t.name] = t.type.name if t.type.is_a?(YAMLCAst::CustomType) && INT_TYPES.include?(t.type.name) + end + int_scalars +end + def has_typedef?(name) $all_types.any? { |t| t.type.respond_to?(:name) && t.type.name == name } end From c681786d7928ea193c0aa62b508fd6958213eb19 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 20:56:27 +0000 Subject: [PATCH 18/26] gen: hoist shared Handle/UUID modules into gen_library_base cuda, hip and mpi each carried a byte-identical 35-line copy of the Handle/UUID to_s modules inside their library heredoc. Extract the one copy into print_handle_uuid_modules and call it from the three backends. ze keeps its own copy: it uses :data/:id field names and prints the UUID bytes back to front, so it cannot share this helper as-is. Generated output is byte-identical (oracle: 53 passed). Net -55 LOC. --- backends/cuda/gen_cuda_library.rb | 39 ++---------------------- backends/hip/gen_hip_library.rb | 50 +++++++------------------------ backends/mpi/gen_mpi_library.rb | 37 ++--------------------- utils/gen_library_base.rb | 41 +++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 111 deletions(-) diff --git a/backends/cuda/gen_cuda_library.rb b/backends/cuda/gen_cuda_library.rb index a9d1ecc20..08756f740 100644 --- a/backends/cuda/gen_cuda_library.rb +++ b/backends/cuda/gen_cuda_library.rb @@ -19,44 +19,11 @@ module CUDA CUDA_IPC_HANDLE_SIZE = 64 extend FFI::Library - module Handle - def to_s - s = '{ reserved: "' - s << self[:reserved].to_a.collect { |v| "\\\\x%02x" % ((v + 256)%256) }.join - s << '" }' - end - end - - module UUID - def to_s - a = self[:bytes].to_a.collect { |v| v < 0 ? 0x100 + v : v } - s = "{ id: " - s << "%02x" % a[0] - s << "%02x" % a[1] - s << "%02x" % a[2] - s << "%02x" % a[3] - s << "-" - s << "%02x" % a[4] - s << "%02x" % a[5] - s << "-" - s << "%02x" % a[6] - s << "%02x" % a[7] - s << "-" - s << "%02x" % a[8] - s << "%02x" % a[9] - s << "-" - s << "%02x" % a[10] - s << "%02x" % a[11] - s << "%02x" % a[12] - s << "%02x" % a[13] - s << "%02x" % a[14] - s << "%02x" % a[15] - s << " }" - end - end - EOF +print_handle_uuid_modules +puts + def print_union(name, union) print_union_with_namespace(:CUDA, name, union) end diff --git a/backends/hip/gen_hip_library.rb b/backends/hip/gen_hip_library.rb index ea7f11297..c4e98a5c9 100644 --- a/backends/hip/gen_hip_library.rb +++ b/backends/hip/gen_hip_library.rb @@ -15,46 +15,16 @@ module HIP HIP_IPC_HANDLE_SIZE = 64 extend FFI::Library - module Handle - def to_s - s = '{ reserved: "' - s << self[:reserved].to_a.collect { |v| "\\\\x%02x" % ((v + 256)%256) }.join - s << '" }' - end - end - - module UUID - def to_s - a = self[:bytes].to_a.collect { |v| v < 0 ? 0x100 + v : v } - s = "{ id: " - s << "%02x" % a[0] - s << "%02x" % a[1] - s << "%02x" % a[2] - s << "%02x" % a[3] - s << "-" - s << "%02x" % a[4] - s << "%02x" % a[5] - s << "-" - s << "%02x" % a[6] - s << "%02x" % a[7] - s << "-" - s << "%02x" % a[8] - s << "%02x" % a[9] - s << "-" - s << "%02x" % a[10] - s << "%02x" % a[11] - s << "%02x" % a[12] - s << "%02x" % a[13] - s << "%02x" % a[14] - s << "%02x" % a[15] - s << " }" - end - end - - hipDeviceAttributeCudaCompatibleBegin = 0 - hipDeviceAttributeAmdSpecificBegin = 10000 - HIPRTC_JIT_NUM_LEGACY_INPUT_TYPES = 6 - ACTIVITY_DOMAIN_HIP_OPS = 2 +EOF + +print_handle_uuid_modules + +puts < Date: Mon, 10 Aug 2026 20:59:02 +0000 Subject: [PATCH 19/26] gen: call print_object directly, drop the per-backend aliases cuda, hip, mpi, itt and ze each defined print__object(object) whose whole body was print_object(object). Call the shared helper directly. Generated output is byte-identical (oracle: 53 passed). --- backends/cuda/gen_cuda_library.rb | 6 +----- backends/hip/gen_hip_library.rb | 6 +----- backends/itt/gen_itt_library.rb | 6 +----- backends/mpi/gen_mpi_library.rb | 6 +----- backends/ze/gen_ze_library.rb | 6 +----- 5 files changed, 5 insertions(+), 25 deletions(-) diff --git a/backends/cuda/gen_cuda_library.rb b/backends/cuda/gen_cuda_library.rb index 08756f740..ac7c3aaf2 100644 --- a/backends/cuda/gen_cuda_library.rb +++ b/backends/cuda/gen_cuda_library.rb @@ -4,10 +4,6 @@ def print_enum(name, enum) print_enum_with_namespace(:CUDA, name, enum) end -def print_cuda_object(object) - print_object(object) -end - print_ffi_module(:CUDA) puts <<~EOF @@ -50,7 +46,7 @@ def print_struct(name, struct) enum = $all_enums.find { |e| t.type.name == e.name } print_enum(t.name, enum) elsif $objects.include?(t.name) - print_cuda_object(t.name) + print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct struct = $all_structs.find { |s| t.type.name == s.name } next unless struct diff --git a/backends/hip/gen_hip_library.rb b/backends/hip/gen_hip_library.rb index c4e98a5c9..ea93297fa 100644 --- a/backends/hip/gen_hip_library.rb +++ b/backends/hip/gen_hip_library.rb @@ -4,10 +4,6 @@ def print_enum(name, enum) print_enum_with_namespace(:HIP, name, enum) end -def print_hip_object(object) - print_object(object) -end - print_ffi_module(:HIP) puts <<~EOF @@ -50,7 +46,7 @@ def print_struct(name, struct) enum = $all_enums.find { |e| t.type.name == e.name } print_enum(t.name, enum) elsif $objects.include?(t.name) - print_hip_object(t.name) + print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct struct = t.type.name ? $all_structs.find { |s| t.type.name == s.name } : t.type next unless struct diff --git a/backends/itt/gen_itt_library.rb b/backends/itt/gen_itt_library.rb index 1e78ce2cd..d9565dc43 100644 --- a/backends/itt/gen_itt_library.rb +++ b/backends/itt/gen_itt_library.rb @@ -98,10 +98,6 @@ def print_enum(name, enum) RUBY end -def print_itt_object(object) - print_object(object) -end - print_ffi_module(:ITT) puts <<~EOF @@ -175,7 +171,7 @@ class #{to_class_name(name)} < FFI::ITTStruct if t.type.is_a? YAMLCAst::Enum print_enum(t.name, find_enum_by_name(t.name, $itt_api)) elsif $objects.include?(t.name) - print_itt_object(t.name) + print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct struct = $all_structs.find { |s| t.type.name == s.name } next unless struct diff --git a/backends/mpi/gen_mpi_library.rb b/backends/mpi/gen_mpi_library.rb index 2c376b4c8..603e343ef 100644 --- a/backends/mpi/gen_mpi_library.rb +++ b/backends/mpi/gen_mpi_library.rb @@ -4,10 +4,6 @@ def print_enum(name, enum) print_enum_with_namespace(:MPI, name, enum) end -def print_mpi_object(object) - print_object(object) -end - print_ffi_module(:MPI) puts <<~EOF @@ -31,7 +27,7 @@ def print_struct(name, struct) enum = $all_enums.find { |e| t.type.name == e.name } print_enum(t.name, enum) elsif $objects.include?(t.name) - print_mpi_object(t.name) + print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct struct = $all_structs.find { |s| t.type.name == s.name } next unless struct diff --git a/backends/ze/gen_ze_library.rb b/backends/ze/gen_ze_library.rb index bfe2301cf..ac8840aaa 100644 --- a/backends/ze/gen_ze_library.rb +++ b/backends/ze/gen_ze_library.rb @@ -35,10 +35,6 @@ def print_enum(name, enum) end end -def print_ze_object(object) - print_object(object) -end - print_ffi_module(:ZE, enclosing_module: false) puts <<~EOF @@ -345,7 +341,7 @@ def is_primitive_type?(t_type) enum = $all_enums.find { |e| t.type.name == e.name } print_enum(t.name, enum) elsif $objects.include?(t.name) - print_ze_object(t.name) + print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct struct = $all_structs.find { |s| t.type.name == s.name } next unless struct From faa47f54e3f62879419df0aac26f2b35d95ee57f Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 21:03:23 +0000 Subject: [PATCH 20/26] gen: call the *_with_namespace helpers directly, drop namespace aliases The per-backend print_union (all five backends) and mpi's print_struct only re-bound the namespace argument. Pass the namespace at the call site instead; the indirection hid which namespace was in play. Backends that add real behaviour on top of the shared helper (cuda/hip/ze UUID prepends, itt's function-pointer rewriting, ze's version enums) keep their wrappers. Generated output is byte-identical (oracle: 53 passed). --- backends/cuda/gen_cuda_library.rb | 6 +----- backends/hip/gen_hip_library.rb | 6 +----- backends/itt/gen_itt_library.rb | 6 +----- backends/mpi/gen_mpi_library.rb | 12 ++---------- backends/ze/gen_ze_library.rb | 6 +----- 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/backends/cuda/gen_cuda_library.rb b/backends/cuda/gen_cuda_library.rb index ac7c3aaf2..2cb2a01b8 100644 --- a/backends/cuda/gen_cuda_library.rb +++ b/backends/cuda/gen_cuda_library.rb @@ -20,10 +20,6 @@ module CUDA print_handle_uuid_modules puts -def print_union(name, union) - print_union_with_namespace(:CUDA, name, union) -end - def print_struct(name, struct) prepends = [] prepends << 'UUID' if to_class_name(name).match('UUID') @@ -56,7 +52,7 @@ def print_struct(name, struct) union = $all_unions.find { |s| t.type.name == s.name } next unless union - print_union(t.name, union) + print_union_with_namespace(:CUDA, t.name, union) elsif t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Function) print_function_pointer_type(t.name, t.type.type) end diff --git a/backends/hip/gen_hip_library.rb b/backends/hip/gen_hip_library.rb index ea93297fa..baa882c1c 100644 --- a/backends/hip/gen_hip_library.rb +++ b/backends/hip/gen_hip_library.rb @@ -23,10 +23,6 @@ module HIP ACTIVITY_DOMAIN_HIP_OPS = 2 EOF -def print_union(name, union) - print_union_with_namespace(:HIP, name, union) -end - def print_struct(name, struct) prepends = [] prepends << 'UUID' if to_class_name(name).match('UUID') @@ -56,7 +52,7 @@ def print_struct(name, struct) union = $all_unions.find { |s| t.type.name == s.name } next unless union - print_union(t.name, union) + print_union_with_namespace(:HIP, t.name, union) elsif t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Function) print_function_pointer_type(t.name, t.type.type) elsif t.type.is_a?(YAMLCAst::Pointer) diff --git a/backends/itt/gen_itt_library.rb b/backends/itt/gen_itt_library.rb index d9565dc43..d7c1eb166 100644 --- a/backends/itt/gen_itt_library.rb +++ b/backends/itt/gen_itt_library.rb @@ -106,10 +106,6 @@ module ITT EOF -def print_union(name, union) - print_union_with_namespace(:ITT, name, union) -end - def print_struct(name, struct) members = struct.to_ffi @@ -181,7 +177,7 @@ class #{to_class_name(name)} < FFI::ITTStruct union = $all_unions.find { |s| t.type.name == s.name } next unless union - print_union(t.name, union) + print_union_with_namespace(:ITT, t.name, union) elsif t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Function) # Defer callbacks until the end so all referenced types are defined callbacks << [t.name, t.type.type] diff --git a/backends/mpi/gen_mpi_library.rb b/backends/mpi/gen_mpi_library.rb index 603e343ef..41f4a98dc 100644 --- a/backends/mpi/gen_mpi_library.rb +++ b/backends/mpi/gen_mpi_library.rb @@ -14,14 +14,6 @@ module MPI print_handle_uuid_modules -def print_union(name, union) - print_union_with_namespace(:MPI, name, union) -end - -def print_struct(name, struct) - print_struct_with_namespace(:MPI, name, struct) -end - $all_types.each do |t| if t.type.is_a? YAMLCAst::Enum enum = $all_enums.find { |e| t.type.name == e.name } @@ -32,12 +24,12 @@ def print_struct(name, struct) struct = $all_structs.find { |s| t.type.name == s.name } next unless struct - print_struct(t.name, struct) + print_struct_with_namespace(:MPI, t.name, struct) elsif t.type.is_a? YAMLCAst::Union union = $all_unions.find { |s| t.type.name == s.name } next unless union - print_union(t.name, union) + print_union_with_namespace(:MPI, t.name, union) elsif t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Function) print_function_pointer_type(t.name, t.type.type) elsif t.type.is_a?(YAMLCAst::Pointer) diff --git a/backends/ze/gen_ze_library.rb b/backends/ze/gen_ze_library.rb index ac8840aaa..75b8f7c6b 100644 --- a/backends/ze/gen_ze_library.rb +++ b/backends/ze/gen_ze_library.rb @@ -198,10 +198,6 @@ def to_i EOF -def print_union(name, union) - print_union_with_namespace(:ZE, name, union) -end - def print_struct(name, struct) prepends = [] if to_class_name(name).match('UUID') @@ -351,7 +347,7 @@ def is_primitive_type?(t_type) union = $all_unions.find { |s| t.type.name == s.name } next unless union - print_union(t.name, union) + print_union_with_namespace(:ZE, t.name, union) elsif t.type.is_a?(YAMLCAst::Pointer) && t.type.type.is_a?(YAMLCAst::Function) print_function_pointer_type(t.name, t.type.type) end From 555d417159d8675ae31b72a1f41e6f7c9585c14b Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 21:04:33 +0000 Subject: [PATCH 21/26] gen: inline the cuda/hip/mpi print_enum namespace aliases Same pass-through shape as print_union: the wrapper only supplied the namespace. itt, omp and ze keep theirs -- those pick between enum and bitfield printing, or handle version enums. Generated output is byte-identical (oracle: 53 passed). --- backends/cuda/gen_cuda_library.rb | 6 +----- backends/hip/gen_hip_library.rb | 8 ++------ backends/mpi/gen_mpi_library.rb | 6 +----- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/backends/cuda/gen_cuda_library.rb b/backends/cuda/gen_cuda_library.rb index 2cb2a01b8..970871e0e 100644 --- a/backends/cuda/gen_cuda_library.rb +++ b/backends/cuda/gen_cuda_library.rb @@ -1,9 +1,5 @@ require_relative 'gen_cuda_library_base' -def print_enum(name, enum) - print_enum_with_namespace(:CUDA, name, enum) -end - print_ffi_module(:CUDA) puts <<~EOF @@ -40,7 +36,7 @@ def print_struct(name, struct) $all_types.each do |t| if t.type.is_a? YAMLCAst::Enum enum = $all_enums.find { |e| t.type.name == e.name } - print_enum(t.name, enum) + print_enum_with_namespace(:CUDA, t.name, enum) elsif $objects.include?(t.name) print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct diff --git a/backends/hip/gen_hip_library.rb b/backends/hip/gen_hip_library.rb index baa882c1c..cef975524 100644 --- a/backends/hip/gen_hip_library.rb +++ b/backends/hip/gen_hip_library.rb @@ -1,9 +1,5 @@ require_relative 'gen_hip_library_base' -def print_enum(name, enum) - print_enum_with_namespace(:HIP, name, enum) -end - print_ffi_module(:HIP) puts <<~EOF @@ -34,13 +30,13 @@ def print_struct(name, struct) next unless e.name next if typedef_enum_names.include?(e.name) - print_enum(e.name, e) + print_enum_with_namespace(:HIP, e.name, e) end $all_types.each do |t| if t.type.is_a? YAMLCAst::Enum enum = $all_enums.find { |e| t.type.name == e.name } - print_enum(t.name, enum) + print_enum_with_namespace(:HIP, t.name, enum) elsif $objects.include?(t.name) print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct diff --git a/backends/mpi/gen_mpi_library.rb b/backends/mpi/gen_mpi_library.rb index 41f4a98dc..d0ef88cc8 100644 --- a/backends/mpi/gen_mpi_library.rb +++ b/backends/mpi/gen_mpi_library.rb @@ -1,9 +1,5 @@ require_relative 'gen_mpi_library_base' -def print_enum(name, enum) - print_enum_with_namespace(:MPI, name, enum) -end - print_ffi_module(:MPI) puts <<~EOF @@ -17,7 +13,7 @@ module MPI $all_types.each do |t| if t.type.is_a? YAMLCAst::Enum enum = $all_enums.find { |e| t.type.name == e.name } - print_enum(t.name, enum) + print_enum_with_namespace(:MPI, t.name, enum) elsif $objects.include?(t.name) print_object(t.name) elsif t.type.is_a? YAMLCAst::Struct From c414c282939711ecf327219bc71896450f1c1478 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 21:07:35 +0000 Subject: [PATCH 22/26] gen: share the UUID-prepending struct printer between cuda and hip cuda and hip both prepended the UUID module for structs whose class name mentions UUID, differing only in namespace. Hoist to print_struct_prepending_uuid in gen_library_base. ze keeps its own: it also selects the KUUID module for kernel UUIDs. Generated output is byte-identical (oracle: 53 passed). --- backends/cuda/gen_cuda_library.rb | 8 +------- backends/hip/gen_hip_library.rb | 8 +------- utils/gen_library_base.rb | 6 ++++++ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/backends/cuda/gen_cuda_library.rb b/backends/cuda/gen_cuda_library.rb index 970871e0e..67bdec1c9 100644 --- a/backends/cuda/gen_cuda_library.rb +++ b/backends/cuda/gen_cuda_library.rb @@ -16,12 +16,6 @@ module CUDA print_handle_uuid_modules puts -def print_struct(name, struct) - prepends = [] - prepends << 'UUID' if to_class_name(name).match('UUID') - print_struct_with_namespace(:CUDA, name, struct, prepends: prepends) -end - puts < Date: Mon, 10 Aug 2026 21:22:03 +0000 Subject: [PATCH 23/26] lint: satisfy rubocop on the files this branch touches CI lints every changed .rb with `rubocop --display-only-safe-correctable`, which fails on any autocorrectable offence. Five came from earlier commits on this branch (argument alignment, a long line, a trailing comma, a while-modifier); the indentation one in gen_babeltrace_lib_helper.rb pre-dates the branch but CI lints that file because we touch it. Applied via targeted `rubocop -a`, not a blanket run: the wider codebase has ~1000 pre-existing offences (Style/GlobalVars, heredoc naming) that are out of scope here. Generated output is byte-identical (oracle: 53 passed on a clean build). --- backends/cuda/gen_babeltrace_cuda_model.rb | 4 +- backends/opencl/gen_opencl_model.rb | 4 +- backends/ze/gen_babeltrace_ze_model.rb | 12 +-- utils/gen_babeltrace_lib_helper.rb | 100 ++++++++++----------- utils/gen_babeltrace_model_helper.rb | 6 +- 5 files changed, 63 insertions(+), 63 deletions(-) diff --git a/backends/cuda/gen_babeltrace_cuda_model.rb b/backends/cuda/gen_babeltrace_cuda_model.rb index de0d23b19..c4b0c9004 100644 --- a/backends/cuda/gen_babeltrace_cuda_model.rb +++ b/backends/cuda/gen_babeltrace_cuda_model.rb @@ -4,8 +4,8 @@ registry = build_ast_registry('cuda', expect_bitfields: false) event_classes = gen_command_events_bt_model(registry, - [[:lttng_ust_cuda, $cuda_commands], - [:lttng_ust_cuda_exports, $cuda_exports_commands]]) + [[:lttng_ust_cuda, $cuda_commands], + [:lttng_ust_cuda_exports, $cuda_exports_commands]]) event_classes += gen_extra_events_bt_model(registry, 'cuda_events.yaml') puts YAML.dump(gen_yaml(event_classes, 'cuda')) diff --git a/backends/opencl/gen_opencl_model.rb b/backends/opencl/gen_opencl_model.rb index 85910f444..868b9bf68 100644 --- a/backends/opencl/gen_opencl_model.rb +++ b/backends/opencl/gen_opencl_model.rb @@ -109,7 +109,9 @@ field['type'] = 'cl_errcode' if fname == 'errcode_ret_val' fields[fname] = field end - c.meta_parameters.select { |p| p.lttng_out_type && LTTngFieldTuple.name(*p.lttng_out_type) != '_param_name' }.each do |p| + c.meta_parameters.select do |p| + p.lttng_out_type && LTTngFieldTuple.name(*p.lttng_out_type) != '_param_name' + end.each do |p| meta_field = {} lttng = p.lttng_out_type fname = LTTngFieldTuple.name(*lttng) diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index 6c6d6aa33..0beaae59a 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -5,12 +5,12 @@ registry = build_ast_registry('ze', expect_bitfields: true) event_classes = gen_command_events_bt_model(registry, - [[:lttng_ust_ze, $ze_commands], - [:lttng_ust_zet, $zet_commands], - [:lttng_ust_zes, $zes_commands], - [:lttng_ust_zel, $zel_commands], - [:lttng_ust_zer, $zer_commands], - [:lttng_ust_zex, $zex_commands]]) + [[:lttng_ust_ze, $ze_commands], + [:lttng_ust_zet, $zet_commands], + [:lttng_ust_zes, $zes_commands], + [:lttng_ust_zel, $zel_commands], + [:lttng_ust_zer, $zer_commands], + [:lttng_ust_zex, $zex_commands]]) event_classes += gen_extra_events_bt_model(registry, 'ze_events.yaml') def get_structs_types(namespace, types, structs) diff --git a/utils/gen_babeltrace_lib_helper.rb b/utils/gen_babeltrace_lib_helper.rb index 11911f058..70d961cfb 100644 --- a/utils/gen_babeltrace_lib_helper.rb +++ b/utils/gen_babeltrace_lib_helper.rb @@ -7,58 +7,58 @@ def add_babeltrace_event_callbacks(file) fields = m.reject { |f| /^_.*_length$/ =~ f[:name] } .map do |f| - name = f[:name] - fc = f[:field_class] - be_class = f[:metadata]&.[](:be_class) + name = f[:name] + fc = f[:field_class] + be_class = f[:metadata]&.[](:be_class) - default_command = %(s << "#{name}: \#{defi["#{name}"]}") + default_command = %(s << "#{name}: \#{defi["#{name}"]}") - case fc[:type] - when 'integer_signed', 'integer_unsigned' - if be_class - # Remaining read of the $all_bitfield_names global. This is - # in the library/bindings path (not the babeltrace-model - # path that was de-globalized): callers require their - # gen__library_base first, which populates the global - # before this call, so there is no load-order hazard. The - # global cannot be dropped while gen_library_base.rb still - # reads $all_struct_names, so it is left explicit here. - if $all_bitfield_names.include?(fc[:cast_type]) - %{s << "#{name}: [ \#{#{be_class}.from_native(defi["#{name}"], nil).join(", ")} ]"} - else - %{s << "#{name}: \#{#{be_class}.from_native(defi["#{name}"], nil)}"} - end - elsif fc[:preferred_display_base] == 16 - %(s << "#{name}: \#{"0x%016x" % defi["#{name}"]}") - else - default_command - end - when 'double', 'single' - default_command - when 'string' - if be_class - if name.end_with?('_vals') - %{s << "#{name}: [ \#{p = FFI::MemoryPointer.from_string(defi["#{name}"]); sz = #{be_class}.size; n = p.size / sz; (0...n).collect { |i| #{be_class}.new(p + i*sz).to_s}.join(", ")} ]"} - else - %{s << "#{name}: \#{defi["#{name}"].size > 0 ? #{be_class}.new(FFI::MemoryPointer.from_string(defi["#{name}"])) : nil}"} - end - else - %(s << "#{name}: \#{defi["#{name}"].inspect}") - end - when 'array_dynamic', 'array_static' - case fc[:element_field_class][:type] - when 'integer_signed', 'integer_unsigned' - if fc[:element_field_class][:preferred_display_base] == 16 - %{s << "#{name}: [ \#{defi["#{name}"].collect { |v| "0x%016x" % v }.join(", ")} ]"} - else - default_command - end - else - raise "Unsupported field type for array: #{fc[:element_field_class][:type]}" - end - else - raise "Unsupported field type: #{fc[:type]}" - end + case fc[:type] + when 'integer_signed', 'integer_unsigned' + if be_class + # Remaining read of the $all_bitfield_names global. This is + # in the library/bindings path (not the babeltrace-model + # path that was de-globalized): callers require their + # gen__library_base first, which populates the global + # before this call, so there is no load-order hazard. The + # global cannot be dropped while gen_library_base.rb still + # reads $all_struct_names, so it is left explicit here. + if $all_bitfield_names.include?(fc[:cast_type]) + %{s << "#{name}: [ \#{#{be_class}.from_native(defi["#{name}"], nil).join(", ")} ]"} + else + %{s << "#{name}: \#{#{be_class}.from_native(defi["#{name}"], nil)}"} + end + elsif fc[:preferred_display_base] == 16 + %(s << "#{name}: \#{"0x%016x" % defi["#{name}"]}") + else + default_command + end + when 'double', 'single' + default_command + when 'string' + if be_class + if name.end_with?('_vals') + %{s << "#{name}: [ \#{p = FFI::MemoryPointer.from_string(defi["#{name}"]); sz = #{be_class}.size; n = p.size / sz; (0...n).collect { |i| #{be_class}.new(p + i*sz).to_s}.join(", ")} ]"} + else + %{s << "#{name}: \#{defi["#{name}"].size > 0 ? #{be_class}.new(FFI::MemoryPointer.from_string(defi["#{name}"])) : nil}"} + end + else + %(s << "#{name}: \#{defi["#{name}"].inspect}") + end + when 'array_dynamic', 'array_static' + case fc[:element_field_class][:type] + when 'integer_signed', 'integer_unsigned' + if fc[:element_field_class][:preferred_display_base] == 16 + %{s << "#{name}: [ \#{defi["#{name}"].collect { |v| "0x%016x" % v }.join(", ")} ]"} + else + default_command + end + else + raise "Unsupported field type for array: #{fc[:element_field_class][:type]}" + end + else + raise "Unsupported field type: #{fc[:type]}" + end end.join("\n s << ', '\n ") # Now just print the full strings to pretty printf the struct diff --git a/utils/gen_babeltrace_model_helper.rb b/utils/gen_babeltrace_model_helper.rb index 7f68aaaa6..e6f21ef91 100644 --- a/utils/gen_babeltrace_model_helper.rb +++ b/utils/gen_babeltrace_model_helper.rb @@ -9,7 +9,7 @@ def build_ast_registry(backend, expect_bitfields:) registry = TypeRegistry.from_ast( all_types: $all_types, all_enums: $all_enums, enum_names: $all_enum_names, bitfield_names: $all_bitfield_names, struct_names: $all_struct_names, - class_namer: method(:to_scoped_class_name), + class_namer: method(:to_scoped_class_name) ) if expect_bitfields raise "#{backend}: expected bitfield types" if registry.bitfield_names.empty? @@ -118,9 +118,7 @@ def gen_bt_field_model(registry, lttng_name, type, name, lttng) when 'ctf_sequence_text', 'ctf_array_text' field[:type] = 'string' t = type.sub(' *', '') - while types_by_name.include?(t) && types_by_name[t].type.is_a?(YAMLCAst::CustomType) - t = types_by_name[t].type.name - end + t = types_by_name[t].type.name while types_by_name.include?(t) && types_by_name[t].type.is_a?(YAMLCAst::CustomType) member[:metadata] = { be_class: registry.class_namer.call(t) } if registry.struct_names.include?(t) # Too complicated, not sure why `all_struct_names` is not enough From 047ef11114a2afe5e246229827195e91babc4cd0 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 21:31:08 +0000 Subject: [PATCH 24/26] gitignore: ignore __pycache__ Running the generated-file comparison oracle (pytest) leaves utils/__pycache__ behind, which is easy to sweep into a commit by accident. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fa728da51..362d83d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ m4 aclocal.m4 configure Makefile.in +__pycache__ From 005ea9312c807bdf26ab23993bcbbeebafae6ada Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 21:47:23 +0000 Subject: [PATCH 25/26] ci: build the opencl model yamls the oracle compares The comparison oracle gained backends/opencl/opencl_model.yaml and btx_cl_model.yaml, but the CI build step only asked for libOpenCL.la and opencl_profiling.tp. Neither pulls those two in -- btx_cl_model.yaml is a plain intermediate -- so the oracle hit FileNotFoundError on the base branch. Name them on the make line, as every other backend already does for its model yaml. Verified by reproducing the CI build locally: both files are absent before this change and present after, and identical between base and PR. --- .github/workflows/presubmit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml index 6fdbff835..ebacd5766 100644 --- a/.github/workflows/presubmit.yml +++ b/.github/workflows/presubmit.yml @@ -234,7 +234,7 @@ jobs: make -C backends/cuda tracer_cuda.c cuda_library.rb btx_cuda_model.yaml libcuda.la make -C backends/cuda tracer_cudart.c libcudart.la make -C backends/ze tracer_ze.c ze_library.rb btx_ze_model.yaml libze_loader.la - make -C backends/opencl libOpenCL.la + make -C backends/opencl opencl_model.yaml btx_cl_model.yaml libOpenCL.la make -C backends/cxi cxi_sampling.tp make -C backends/itt tracer_itt.c itt_library.rb btx_itt_model.yaml libittnotify.la make -C backends/opencl opencl_profiling.tp From 44e9396c5e85b5e78bd474070438c540a3653d82 Mon Sep 17 00:00:00 2001 From: Thomas Applencourt Date: Mon, 10 Aug 2026 22:03:51 +0000 Subject: [PATCH 26/26] gen: fail loudly when a meta-parameter YAML has no meta_parameters key load_meta_parameters read content['meta_parameters'] and silently registered nothing when the key was absent, which is indistinguishable from a backend that genuinely has none. A typo in the key -- or the string-vs-symbol confusion -- therefore dropped every entry in the file without a word. Raise instead. A backend with no meta-parameters of its own already has a way to say so explicitly: `meta_parameters: []`, as cudart does. This check is what caught mpi_meta_parameters.yaml using the symbol key `:meta_parameters:`, which had left all of its entries dead since 9ae9297. That file was reconciled with the current code in f2ae743, so every backend builds. --- utils/command.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/utils/command.rb b/utils/command.rb index f2b014147..7bfe17d1f 100644 --- a/utils/command.rb +++ b/utils/command.rb @@ -117,9 +117,17 @@ def register_meta_parameter(method, type, *args) end # Load a backend's meta-parameter YAML (relative to SRC_DIR) and register every -# entry. The file maps each function name to a list of [type, *args] rows. +# entry. The file maps each function name to a list of [type, *args] rows under +# a top-level `meta_parameters` key. A backend with none of its own writes +# `meta_parameters: []`; a missing key means a typo, which would otherwise +# register nothing and look identical to having none. def load_meta_parameters(filename) - YAML.load_file(File.join(SRC_DIR, filename)).fetch('meta_parameters', []).each do |func, list| + path = File.join(SRC_DIR, filename) + content = YAML.load_file(path) + entries = content['meta_parameters'] + raise "#{path} has no 'meta_parameters' key (use `meta_parameters: []` if it was not a typo)" if entries.nil? + + entries.each do |func, list| list.each do |type, *args| register_meta_parameter func, Kernel.const_get(type), *args end