Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions backends/ze/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion backends/ze/gen_babeltrace_ze_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 9 additions & 18 deletions backends/ze/gen_ze.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 <<EOF
case #{structure_type_name(t)}:
tracepoint(lttng_ust_#{namespace}_structs, #{t}, ((#{t} *)p));
break;
EOF
end
if namespace == :ze
puts <<EOF
case ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES_1_2:
tracepoint(lttng_ust_ze_structs, ze_device_properties_t, ((ze_device_properties_t *)p));
break;
EOF
elsif namespace == :zes
puts <<EOF
case ZES_STRUCTURE_TYPE_BASE_STATE:
break;
case ZES_STRUCTURE_TYPE_DEVICE_UUID:
break;
EOF
end
# The stypes with no tracepoint of their own: an end marker
# (<NS>_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;
}
}
Expand All @@ -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])
Expand Down
4 changes: 2 additions & 2 deletions backends/ze/gen_ze_library.rb
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,15 @@ 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 = <<EOF

def initialize(*args)
super(*args)
if(args.length == 0)
EOF
initializer << <<EOF
self[:stype] = :#{structure_type_name(name)}
self[:stype] = :#{traced_structure_type_names(name).first}
end
end
EOF
Expand Down
2 changes: 1 addition & 1 deletion backends/ze/gen_ze_structs_tracepoints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require_relative 'ze_model'
require_relative '../../utils/gen_probe_base'

print_struct_tracepoint_provider(:lttng_ust_ze_structs, tagged_structs(APIS[:ze]),
print_struct_tracepoint_provider(:lttng_ust_ze_structs, traced_structs(APIS[:ze]),
include: '#include "ze.h.include"')
2 changes: 1 addition & 1 deletion backends/ze/gen_zel_structs_tracepoints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require_relative 'ze_model'
require_relative '../../utils/gen_probe_base'

print_struct_tracepoint_provider(:lttng_ust_zel_structs, tagged_structs(APIS[:zel]),
print_struct_tracepoint_provider(:lttng_ust_zel_structs, traced_structs(APIS[:zel]),
include: '#include "ze.h.include"')
2 changes: 1 addition & 1 deletion backends/ze/gen_zer_structs_tracepoints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require_relative 'ze_model'
require_relative '../../utils/gen_probe_base'

print_struct_tracepoint_provider(:lttng_ust_zer_structs, tagged_structs(APIS[:zer]),
print_struct_tracepoint_provider(:lttng_ust_zer_structs, traced_structs(APIS[:zer]),
include: '#include "ze.h.include"')
2 changes: 1 addition & 1 deletion backends/ze/gen_zes_structs_tracepoints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require_relative 'ze_model'
require_relative '../../utils/gen_probe_base'

print_struct_tracepoint_provider(:lttng_ust_zes_structs, tagged_structs(APIS[:zes]),
print_struct_tracepoint_provider(:lttng_ust_zes_structs, traced_structs(APIS[:zes]),
include: '#include "ze.h.include"')
2 changes: 1 addition & 1 deletion backends/ze/gen_zet_structs_tracepoints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require_relative 'ze_model'
require_relative '../../utils/gen_probe_base'

print_struct_tracepoint_provider(:lttng_ust_zet_structs, tagged_structs(APIS[:zet]),
print_struct_tracepoint_provider(:lttng_ust_zet_structs, traced_structs(APIS[:zet]),
include: '#include "ze.h.include"')
2 changes: 1 addition & 1 deletion backends/ze/gen_zex_structs_tracepoints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require_relative 'ze_model'
require_relative '../../utils/gen_probe_base'

print_struct_tracepoint_provider(:lttng_ust_zex_structs, tagged_structs(APIS[:zex]),
print_struct_tracepoint_provider(:lttng_ust_zex_structs, traced_structs(APIS[:zex]),
include: '#include "ze.h.include"')
115 changes: 61 additions & 54 deletions backends/ze/ze_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,6 @@
zex: ApiModel.load_file('zex_api.yaml'),
}.freeze

# A struct tagged with its own type is one the tracer can decode from a
# `void *` at runtime, which is what makes it worth its own tracepoint.
STRUCT_TYPE_TAG = 'stype'

def tagged_structs(api)
api.types.select do |t|
t.type.is_a?(YAMLCAst::Struct) &&
(struct = api.struct_named(t.type.name)) &&
struct.members.first.name == STRUCT_TYPE_TAG
end.map(&:name)
end

# Those a caller can be handed. The `<ns>_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.
Expand All @@ -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 <ns>_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 `<ns>_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
Expand Down
8 changes: 8 additions & 0 deletions xprof/xprof.rb.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading