diff --git a/backends/ze/README.md b/backends/ze/README.md index 7b6240447..02266fdf2 100644 --- a/backends/ze/README.md +++ b/backends/ze/README.md @@ -103,17 +103,11 @@ $ diff <(grep -ho 'zex[A-Za-z]*(' /usr/include/level_zero/driver_experimental/*. <(grep -o 'zex[A-Za-z]*(' include/zex_api.h | tr -d '(' | sort -u) ``` -- Two manual changes when transcribing: - - - Spell `zex_command_list_handle_t` / `zex_event_handle_t` as their `ze_` - originals (they are plain typedefs of them). One type must have one name: - metababel dispatches on field name plus type, and a field such as - `hSignalEvent` carrying both spellings is a conflicting signature. - - - zex tags its structs with `ZEX_STRUCTURE_*` macros, not with members of - `ze_structure_type_t`. The generated bindings can only name an enum member, - so such a struct goes in `$struct_type_reject` in `ze_model.rb`; otherwise - `gen_ze_library.rb` raises `Unrecognized namespace`. +- One manual change when transcribing: spell `zex_command_list_handle_t` / + `zex_event_handle_t` as their `ze_` originals (they are plain typedefs of + them). One type must have one name: metababel dispatches on field name plus + type, and a field such as `hSignalEvent` carrying both spellings is a + conflicting signature. ## Now Try to Compile: @@ -169,7 +163,11 @@ tracer_ze.c:197:8: error: use of undeclared identifier 'ZE_STRUCTURE_TYPE_DEVICE | ZE_STRUCTURE_TYPE_DEVICE_CACHELINE_SIZE_EXT ``` -Due to Intel's lack of naming consistency, you may need to update the `struct_type_conversion_table` in `ze_model.rb`. +Due to Intel's lack of naming consistency, you may need to add a row to +`STRUCT_TYPES` in `ze_model.rb`, which maps a struct to the stypes that tag it. +The same table is where a struct tagged by *two* enumerators goes -- list both, +and the switch gives them one case each falling through to one tracepoint (see +`ze_device_properties_t`). ## 2 diff --git a/backends/ze/gen_babeltrace_ze_model.rb b/backends/ze/gen_babeltrace_ze_model.rb index 7576ad86b..61eaf0a7e 100644 --- a/backends/ze/gen_babeltrace_ze_model.rb +++ b/backends/ze/gen_babeltrace_ze_model.rb @@ -20,7 +20,7 @@ def gen_struct_event_bt_model(registry, provider, struct) # struct's bytes; no other backend has these. def struct_event_classes(registry) APIS.collect do |ns, api| - concrete_tagged_structs(ns, api).collect do |struct| + traced_structs(api).collect do |struct| gen_struct_event_bt_model(registry, :"lttng_ust_#{ns}_structs", struct) end end.flatten diff --git a/backends/ze/gen_ze.rb b/backends/ze/gen_ze.rb index ee7c24bc0..e220669dd 100644 --- a/backends/ze/gen_ze.rb +++ b/backends/ze/gen_ze.rb @@ -48,29 +48,20 @@ def gen_struct_printer(namespace, types) #{namespace}_structure_type_t stype = (#{namespace}_structure_type_t)((ze_base_desc_t *)p)->stype; switch (stype) { EOF - types.reject { |t| STRUCT_TYPE_REJECT.include?(t.to_s) }.each do |t| + types.each do |t| + puts traced_structure_type_names(t.to_s).map { |stype| " case #{stype}:\n" }.join puts <_STRUCTURE_TYPE_FORCE_UINT32), an abstract base, a value from a driver + # newer than our headers, or a tag whose struct cannot be decoded from a + # `void *` at all -- ZES_STRUCTURE_TYPE_DEVICE_UUID names zes_uuid_t, which + # is a bare byte array with no stype member to have been read here. puts <<~EOF - case #{namespace.to_s.upcase}_STRUCTURE_TYPE_FORCE_UINT32: + default: break; } } @@ -86,7 +77,7 @@ def gen_struct_printer(namespace, types) EOF end -struct_types = APIS.to_h { |ns, api| [ns, concrete_tagged_structs(ns, api)] } +struct_types = APIS.to_h { |ns, api| [ns, traced_structs(api)] } gen_struct_printer(:ze, struct_types[:ze]) gen_struct_printer(:zet, struct_types[:zet]) diff --git a/backends/ze/gen_ze_library.rb b/backends/ze/gen_ze_library.rb index 6d52cb2b6..eaad2a925 100644 --- a/backends/ze/gen_ze_library.rb +++ b/backends/ze/gen_ze_library.rb @@ -213,7 +213,7 @@ def print_struct(name, struct) prepends << 'Handle' end - if struct.to_ffi(NAMING).first[0] == ':stype' && !STRUCT_TYPE_REJECT.include?(name) + if struct.to_ffi(NAMING).first[0] == ':stype' && !traced_structure_type_names(name).empty? initializer = <_base_` types are the tag's own base -# classes: a tracepoint exists for each, but no API call ever passes one, so -# nothing dispatches on them. -def concrete_tagged_structs(namespace, api) - tagged_structs(api).reject { |n| n.start_with?("#{namespace}_base_") }.to_set -end - # Every namespace as one API, the same thing `API` names in every other # backend. The derivations have to see all of them at once: a zet typedef # routinely names a ze struct. @@ -44,45 +25,71 @@ def concrete_tagged_structs(namespace, api) CONTEXT = BackendContext.for(API, result_name: 'zeResult', init_functions: /zeInit|zeLoaderInit|zeInitDrivers|zesInit/) -STRUCT_TYPE_CONVERSION_TABLE = { - 'ZE_STRUCTURE_TYPE_IMAGE_MEMORY_PROPERTIES_EXP' => 'ZE_STRUCTURE_TYPE_IMAGE_MEMORY_EXP_PROPERTIES', - 'ZE_STRUCTURE_TYPE_IMAGE_PITCHED_EXP_DESC' => 'ZE_STRUCTURE_TYPE_PITCHED_IMAGE_EXP_DESC', - 'ZE_STRUCTURE_TYPE_IMAGE_BINDLESS_EXP_DESC' => 'ZE_STRUCTURE_TYPE_BINDLESS_IMAGE_EXP_DESC', - 'ZE_STRUCTURE_TYPE_DEVICE_PITCHED_ALLOC_EXP_PROPERTIES' => 'ZE_STRUCTURE_TYPE_PITCHED_ALLOC_DEVICE_EXP_PROPERTIES', - 'ZE_STRUCTURE_TYPE_CONTEXT_POWER_SAVING_HINT_EXP_DESC' => 'ZE_STRUCTURE_TYPE_POWER_SAVING_HINT_EXP_DESC', - 'ZE_STRUCTURE_TYPE_EVENT_POOL_COUNTER_BASED_EXP_DESC' => 'ZE_STRUCTURE_TYPE_COUNTER_BASED_EVENT_POOL_EXP_DESC', - 'ZE_STRUCTURE_TYPE_KERNEL_MAX_GROUP_SIZE_PROPERTIES_EXT' => 'ZE_STRUCTURE_TYPE_KERNEL_MAX_GROUP_SIZE_EXT_PROPERTIES', - 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32_HANDLE' => 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32', - 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_WIN32_HANDLE' => 'ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_WIN32', - 'ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_LAUNCH_KERNEL_PARAM_COOPERATIVE_DESC' => 'ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_PARAM_COOPERATIVE_DESC', - 'ZE_STRUCTURE_TYPE_DEVICE_CACHE_LINE_SIZE_EXT' => 'ZE_STRUCTURE_TYPE_DEVICE_CACHELINE_SIZE_EXT', - 'ZE_STRUCTURE_TYPE_KERNEL_ALLOCATION_EXP_PROPERTIES' => 'ZE_STRUCTURE_TYPE_KERNEL_ALLOCATION_PROPERTIES', - 'ZET_STRUCTURE_TYPE_EXPORT_DMA_BUF_EXP_PROPERTIES' => 'ZET_STRUCTURE_TYPE_EXPORT_DMA_EXP_PROPERTIES', - 'ZES_STRUCTURE_TYPE_MEM_PAGE_OFFLINE_STATE_EXP' => 'ZES_STRUCTURE_TYPE_MEMORY_PAGE_OFFLINE_STATE_EXP', -} +# The stypes of a struct whose name does not spell them. Every entry replaces +# the derived name outright, so a struct the spec renamed has one row and a +# struct the spec gave a second stype lists both. +STRUCT_TYPES = { + 'ze_image_memory_properties_exp_t' => %w[ZE_STRUCTURE_TYPE_IMAGE_MEMORY_EXP_PROPERTIES], + 'ze_image_pitched_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_PITCHED_IMAGE_EXP_DESC], + 'ze_image_bindless_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_BINDLESS_IMAGE_EXP_DESC], + 'ze_device_pitched_alloc_exp_properties_t' => %w[ZE_STRUCTURE_TYPE_PITCHED_ALLOC_DEVICE_EXP_PROPERTIES], + 'ze_context_power_saving_hint_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_POWER_SAVING_HINT_EXP_DESC], + 'ze_event_pool_counter_based_exp_desc_t' => %w[ZE_STRUCTURE_TYPE_COUNTER_BASED_EVENT_POOL_EXP_DESC], + 'ze_kernel_max_group_size_properties_ext_t' => %w[ZE_STRUCTURE_TYPE_KERNEL_MAX_GROUP_SIZE_EXT_PROPERTIES], + 'ze_external_memory_import_win32_handle_t' => %w[ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_WIN32], + 'ze_external_memory_export_win32_handle_t' => %w[ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_WIN32], + 'ze_command_list_append_launch_kernel_param_cooperative_desc_t' => + %w[ZE_STRUCTURE_TYPE_COMMAND_LIST_APPEND_PARAM_COOPERATIVE_DESC], + 'ze_device_cache_line_size_ext_t' => %w[ZE_STRUCTURE_TYPE_DEVICE_CACHELINE_SIZE_EXT], + 'ze_kernel_allocation_exp_properties_t' => %w[ZE_STRUCTURE_TYPE_KERNEL_ALLOCATION_PROPERTIES], + 'ze_device_properties_t' => %w[ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES + ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES_1_2], + 'zet_export_dma_buf_exp_properties_t' => %w[ZET_STRUCTURE_TYPE_EXPORT_DMA_EXP_PROPERTIES], + 'zes_mem_page_offline_state_exp_t' => %w[ZES_STRUCTURE_TYPE_MEMORY_PAGE_OFFLINE_STATE_EXP], +}.freeze -# Structs whose stype tag is not a member of ze_structure_type_t. -# -# - zex tags structures with a uint32_t alias (level_zero/ze_stypes.h) rather -# than an enum, we don't handle that. -# - zet_metric_source_id_exp_t's tag is simply absent from the spec. -STRUCT_TYPE_REJECT = Set.new(%w[zet_metric_source_id_exp_t - zex_device_module_register_file_exp_t]) - -# The ze_structure_type_t enumerator that tags `name`, a struct typedef such as -# ze_device_properties_t -> ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES. +# Every enumerator name the traced namespaces declare. +ENUMERATORS = APIS.values.flat_map(&:enums).flat_map(&:members).map(&:name).to_set + +# The stypes that tag `name` and that the spec really declares: what the tracer +# dispatches on, and what a Ruby class stamps into its initializer. # -# The tracer switches on this to pick a tracepoint, and the Ruby bindings stamp -# it into the struct's initializer; the two have to name the same enumerator or -# a struct is traced under a tag its class never sets. So it is derived here -# once, from the struct name, rather than recomputed on each side. +# A struct usually spells its own single stype. STRUCT_TYPES holds the ones it +# does not, and a name the spec never declares drops out -- the _base_ +# headers are tagged by nothing, and zex tags its structs with a uint32_t. # -# A handful of enumerators do not follow the rule -- the spec renamed them after -# the struct was named -- and the table has the last word. -def structure_type_name(name) +# >> traced_structure_type_names('ze_context_desc_t') +# => ["ZE_STRUCTURE_TYPE_CONTEXT_DESC"] +# >> traced_structure_type_names('ze_image_pitched_exp_desc_t') # spec renamed it +# => ["ZE_STRUCTURE_TYPE_PITCHED_IMAGE_EXP_DESC"] +# >> traced_structure_type_names('ze_device_properties_t') # two stypes +# => ["ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES", "ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES_1_2"] +# >> traced_structure_type_names('ze_base_desc_t') +# => [] +# >> traced_structure_type_names('zex_device_module_register_file_exp_t') +# => [] +def traced_structure_type_names(name) namespace = name[/\A[a-z]+/] - tag = "#{namespace}_STRUCTURE_TYPE_#{name.delete_prefix("#{namespace}_").delete_suffix('_t')}".upcase - STRUCT_TYPE_CONVERSION_TABLE.fetch(tag, tag) + derived = "#{namespace}_STRUCTURE_TYPE_#{name.delete_prefix("#{namespace}_").delete_suffix('_t')}".upcase + STRUCT_TYPES.fetch(name, [derived]).select { |stype| ENUMERATORS.include?(stype) } +end + +# The member every chained struct leads with, naming its own type. It is what +# lets the tracer decode one from a `void *` at runtime. +STRUCT_TYPE_TAG = 'stype' + +# The structs a namespace traces: the ones that carry the stype tag, and that +# a declared stype actually names. The tracer only ever reaches a tracepoint by +# switching on the stype it read, so a struct no enumerator names could never +# fire -- the `_base_` chain headers, which are the tag rather than a thing +# it selects, and the two the spec tags with nothing we can switch on. +def traced_structs(api) + api.types.select do |t| + t.type.is_a?(YAMLCAst::Struct) && + (struct = api.struct_named(t.type.name)) && + struct.members.first.name == STRUCT_TYPE_TAG && + !traced_structure_type_names(t.name).empty? + end.map(&:name).to_set end # Each namespace declares its meta-parameters in its own file, so the list diff --git a/xprof/xprof.rb.in b/xprof/xprof.rb.in index 48d5acfab..62d19453a 100755 --- a/xprof/xprof.rb.in +++ b/xprof/xprof.rb.in @@ -542,6 +542,12 @@ def enable_events_ze(channel_name, tracing_mode: 'default', profiling: true) exec("#{lttng_enable} lttng_ust_zer:*") exec("#{lttng_enable} lttng_ust_zet:*") exec("#{lttng_enable} lttng_ust_zex:*") + # The structs carried on a call's pNext chain. zer has no struct provider. + exec("#{lttng_enable} lttng_ust_ze_structs:*") + exec("#{lttng_enable} lttng_ust_zes_structs:*") + exec("#{lttng_enable} lttng_ust_zet_structs:*") + exec("#{lttng_enable} lttng_ust_zel_structs:*") + exec("#{lttng_enable} lttng_ust_zex_structs:*") when 'default' # Wildcard using the * character are supported at the end of tracepoint names. # https://lttng.org/man/1/lttng-enable-event/v2.8/#doc-_understanding_event_rule_conditions @@ -923,6 +929,8 @@ def all_env_tracers(usr_binary) # Customization if OPTIONS[:'backend-names'].include?('ze') h['LTTNG_UST_ZE_PARANOID_DRIFT'] = 1 if OPTIONS[:profile] + # Walk pNext only on full. + h['LTTNG_UST_ZE_CHAINED_STRUCTS'] = 1 if OPTIONS[:'tracing-mode'] == 'full' if SamplingDaemon.active? # The current only reliable way to use zes api # is to call zesInit and set ZES_ENABLE_SYSMAN to 0