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
48 changes: 44 additions & 4 deletions backends/ze/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,12 @@ btx_ze_model.yaml: $(srcdir)/gen_babeltrace_ze_model.rb $(ZE_LIB_GEN) $(ZE_MODEL

EXTRA_DIST += \
ze_model.rb \
gen_babeltrace_ze_model.rb
gen_babeltrace_ze_model.rb \
ze_validator_zemodel.rb \
ze_validator_function_entry_exit_callbacks.rb \
ze_validator_entry_exit_helpers.rb \
ze_validator_state_object.rb \
ze_deprecated.json


ZE_PROBES = $(ZE_NAMESPACES:=_tracepoints) $(ZE_STRUCTS_NAMESPACES:=_tracepoints)
Expand Down Expand Up @@ -173,7 +178,35 @@ EXTRA_DIST += \
CLEANFILES += tracer_ze.c

bin_SCRIPTS = \
tracer_ze.sh
tracer_ze.sh \

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For compiling the ze_device_property.cpp
Binary gets stored to build/ici/bin

ze_validator

# Standalone Level Zero utility that dumps per-device command-queue-group
# topology (ordinal -> engine type + numQueues) to a JSON file. Meant to be
# invoked by a separate program. Per the requirement, it is compiled with icpx
# rather than the project's default $(CXX).
ICPX = icpx
ZE_DEVICE_PROPERTY_CXXFLAGS = -std=c++17 -Wall -Wextra -O2
ZE_DEVICE_PROPERTY_CPPFLAGS = -I$(srcdir)/include
ZE_DEVICE_PROPERTY_LIBS = -lze_loader

ze_device_property$(EXEEXT): $(srcdir)/ze_device_property.cpp
$(ICPX) $(ZE_DEVICE_PROPERTY_CXXFLAGS) $(ZE_DEVICE_PROPERTY_CPPFLAGS) \
$< -o $@ $(ZE_DEVICE_PROPERTY_LIBS)

all-local: ze_device_property$(EXEEXT)

install-exec-local: ze_device_property$(EXEEXT)
$(MKDIR_P) $(DESTDIR)$(bindir)
$(INSTALL_PROGRAM) ze_device_property$(EXEEXT) \
$(DESTDIR)$(bindir)/ze_device_property$(EXEEXT)

uninstall-local:
$(RM) $(DESTDIR)$(bindir)/ze_device_property$(EXEEXT)

CLEANFILES += ze_device_property$(EXEEXT)

EXTRA_DIST += ze_device_property.cpp

noinst_LTLIBRARIES = libzetracepoints.la

Expand Down Expand Up @@ -242,14 +275,21 @@ EXTRA_DIST += \
gen_ze_library.rb \
gen_babeltrace_ze_lib.rb \
gen_ze_refinements.rb \
gen_ze_bindings.rb
gen_ze_bindings.rb \
ze_thread_safety.yaml

CLEANFILES += $(ZE_BINDINGS)

data_DATA = \
$(ZE_BINDINGS) \
ze_bindings_base.rb \
babeltrace_zeprofiling_apis.txt
babeltrace_zeprofiling_apis.txt \
ze_thread_safety.yaml \
ze_deprecated.json \
ze_validator_zemodel.rb \
ze_validator_function_entry_exit_callbacks.rb \
ze_validator_entry_exit_helpers.rb \
ze_validator_state_object.rb

xprof_utils.hpp: $(top_srcdir)/utils/xprof_utils.hpp
cp $< $@
Expand Down
8 changes: 8 additions & 0 deletions backends/ze/ze_deprecated.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This stores deprecated APIs. The first field inside the bracket is the version number the API got deprecated from (e.g., "1.10"), and the second field denotes recommended alternative (e.g., "zeInitDrivers").

"zeInit": ["1.10", "zeInitDrivers"],
"zeDriverGet": ["1.10", "zeInitDrivers"],
"zeCommandListImmediateAppendCommandListsExp": ["1.16", "zeCommandListImmediateAppendCommandListsWithParameters"],
"zeImageViewCreateExp": ["", "zeImageViewCreateExt"],
"zesRasGetConfig": ["1.16", "zesRasGetConfigExp"],
"zesRasSetConfig": ["1.16", "zesRasSetConfigExp"]
}
147 changes: 147 additions & 0 deletions backends/ze/ze_device_property.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// ze_device_property.cpp

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This program calls zeDeviceGetCommandQueueGroupProperties for each device a host can access, and maps the ordinal index to the compute/copy engines. This program gets executed at validation time by the validator, and the mapping will be saved as a ze_device_property.json file (to avoid subsequent calls to this program at later validation times). The resulting mapping gets used for checking submission of kernels to command lists and command queues that are associated with copy-only engines

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the ordinal PR #526, is this still needed?

//
// Standalone Level Zero utility that queries every device on the system and
// dumps its command-queue-group topology to `ze_device_property.json`.
//
// For each command queue group it reports:
// - the group ordinal (the value passed as `ordinal` in ze_command_queue_desc_t
// or `commandQueueGroupOrdinal` in ze_command_list_desc_t)
// - the engine type derived from the group flags:
// "compute", "copy", or "compute-and-copy"
// - numQueues: the number of physical engines (queue indices) in the group,
// i.e. the valid range for ze_command_queue_desc_t::index is [0, numQueues-1]
//
// This binary is meant to be invoked by a separate program; it performs no
// argument parsing beyond an optional output path.
//
// Build: compiled with icpx (see Makefile.am).

#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <string>
#include <vector>

#include <ze_api.h>

namespace {

const char *result_to_string(ze_result_t r) {
switch (r) {
case ZE_RESULT_SUCCESS:
return "ZE_RESULT_SUCCESS";
case ZE_RESULT_ERROR_UNINITIALIZED:
return "ZE_RESULT_ERROR_UNINITIALIZED";
case ZE_RESULT_ERROR_DEVICE_LOST:
return "ZE_RESULT_ERROR_DEVICE_LOST";
case ZE_RESULT_ERROR_INVALID_NULL_HANDLE:
return "ZE_RESULT_ERROR_INVALID_NULL_HANDLE";
case ZE_RESULT_ERROR_INVALID_NULL_POINTER:
return "ZE_RESULT_ERROR_INVALID_NULL_POINTER";
case ZE_RESULT_ERROR_UNSUPPORTED_FEATURE:
return "ZE_RESULT_ERROR_UNSUPPORTED_FEATURE";
default:
return "ZE_RESULT_ERROR (unlisted)";
}
}

// Fatal-checks a Level Zero call; on failure prints the site and exits(1).
#define ZE_CHECK(call) \
do { \
ze_result_t _res = (call); \
if (_res != ZE_RESULT_SUCCESS) { \
std::fprintf(stderr, "%s failed: %s (0x%x)\n", #call, \
result_to_string(_res), (unsigned)_res); \
std::exit(1); \
} \
} while (0)

// Classify a command queue group by its flags.
const char *engine_type(ze_command_queue_group_property_flags_t flags) {
const bool compute = flags & ZE_COMMAND_QUEUE_GROUP_PROPERTY_FLAG_COMPUTE;
const bool copy = flags & ZE_COMMAND_QUEUE_GROUP_PROPERTY_FLAG_COPY;
if (compute && copy)
return "compute-and-copy";
if (compute)
return "compute";
if (copy)
return "copy";
return "other";
}

} // namespace

int main(int argc, char **argv) {
const char *out_path =
(argc > 1) ? argv[1] : "ze_device_property.json";

ZE_CHECK(zeInit(ZE_INIT_FLAG_GPU_ONLY));

uint32_t driver_count = 0;
ZE_CHECK(zeDriverGet(&driver_count, nullptr));
std::vector<ze_driver_handle_t> drivers(driver_count);
if (driver_count > 0)
ZE_CHECK(zeDriverGet(&driver_count, drivers.data()));

std::ofstream out(out_path);
if (!out) {
std::fprintf(stderr, "unable to open '%s' for writing\n", out_path);
return 1;
}

out << "{\n \"devices\": [";

bool first_device = true;
for (uint32_t d = 0; d < driver_count; ++d) {
uint32_t device_count = 0;
ZE_CHECK(zeDeviceGet(drivers[d], &device_count, nullptr));
std::vector<ze_device_handle_t> devices(device_count);
if (device_count > 0)
ZE_CHECK(zeDeviceGet(drivers[d], &device_count, devices.data()));

for (uint32_t i = 0; i < device_count; ++i) {
ze_device_properties_t dev_props{};
dev_props.stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES;
ZE_CHECK(zeDeviceGetProperties(devices[i], &dev_props));

uint32_t group_count = 0;
ZE_CHECK(zeDeviceGetCommandQueueGroupProperties(devices[i], &group_count,
nullptr));
std::vector<ze_command_queue_group_properties_t> groups(group_count);
for (auto &g : groups)
g.stype = ZE_STRUCTURE_TYPE_COMMAND_QUEUE_GROUP_PROPERTIES;
if (group_count > 0)
ZE_CHECK(zeDeviceGetCommandQueueGroupProperties(
devices[i], &group_count, groups.data()));

out << (first_device ? "\n" : ",\n");
first_device = false;

out << " {\n";
out << " \"driver_index\": " << d << ",\n";
out << " \"device_index\": " << i << ",\n";
out << " \"name\": \"" << dev_props.name << "\",\n";
out << " \"command_queue_groups\": [";

for (uint32_t g = 0; g < group_count; ++g) {
out << (g == 0 ? "\n" : ",\n");
out << " {\n";
out << " \"ordinal\": " << g << ",\n";
out << " \"type\": \"" << engine_type(groups[g].flags)
<< "\",\n";
out << " \"numQueues\": " << groups[g].numQueues << "\n";
out << " }";
}

out << (group_count == 0 ? "" : "\n ") << "]\n";
out << " }";
}
}

out << (first_device ? "" : "\n ") << "]\n}\n";
out.close();

std::fprintf(stderr, "wrote %s\n", out_path);
return 0;
}
29 changes: 29 additions & 0 deletions backends/ze/ze_thread_safety.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
zeCommandListDestroy:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the point of the second argument, if everything is all the time command_list?
Can we add some with event maybe?

- [hCommandList, command_list]
zeCommandListClose:
- [hCommandList, command_list]
zeCommandListReset:
- [hCommandList, command_list]
zeCommandListAppendWriteGlobalTimestamp:
- [hCommandList, command_list]
zeCommandListAppendLaunchKernel:
- [hCommandList, command_list]
zeCommandListAppendBarrier:
- [hCommandList, command_list]
zeCommandListAppendLaunchCooperativeKernel:
- [hCommandList, command_list]
zeCommandListAppendMemoryCopy:
- [hCommandList, command_list]
zeCommandListAppendMemoryFill:
- [hCommandList, command_list]
zeCommandListAppendMemoryCopyRegion:
- [hCommandList, command_list]
zeCommandListAppendSignalEvent:
- [hCommandList, command_list]
zeCommandListAppendWaitOnEvents:
- [hCommandList, command_list]
zeCommandListAppendEventReset:
- [hCommandList, command_list]
zeCommandQueueExecuteCommandLists:
- [phCommandLists_vals, command_list]
131 changes: 131 additions & 0 deletions backends/ze/ze_validator.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env ruby
# coding: utf-8
DATADIR = File.join("@prefix@", "share")
BINDIR = File.join("@prefix@", "bin")
$:.unshift(DATADIR) if File.directory?(DATADIR)
require 'optparse'
require 'babeltrace2'
require 'find'
require 'ze_library'
require 'pp'
require 'set'
require 'ze_validator_zemodel'
require 'ze_validator_function_entry_exit_callbacks'
require 'ze_validator_state_object'
require 'yaml'

# Don't complain about broken pipe
Signal.trap('SIGPIPE', 'SYSTEM_DEFAULT')

# Runs the ze_device_property helper to (re)generate ze_device_property.json.
# Best-effort: the validator continues without the device topology data.
def generate_device_properties
json_path = File.join(DATADIR, 'ze_device_property.json')
binary = File.join(BINDIR, 'ze_device_property')
binary = 'ze_device_property' unless File.executable?(binary)

ok = system(binary, json_path, out: File::NULL, err: File::NULL)
unless ok
$stderr.puts "Warning: could not generate #{json_path} via '#{binary}'; " \
"continuing without device properties."
end
rescue SystemCallError => e
$stderr.puts "Warning: could not run ze_device_property: #{e.message}; " \
"continuing without device properties."
end

$options = { live: false, device_agnostic: true, performance: true,
gen_device_properties: true }

OptionParser.new do |opts|
opts.banner = 'Usage: ze_validator [OPTIONS] trace_directory...'

opts.on('-h', '--help', 'Prints this help') do
puts opts
exit
end

opts.on('--no-device-properties',
'Skip running the ze_device_property helper to (re)generate ze_device_property.json') do
$options[:gen_device_properties] = false
end

opts.on('--live', 'Enable live processing of the trace') do
$options[:live] = true
end

opts.on('--disable-dagn', 'Disables device agnostic semantic misuse checking') do
$options[:device_agnostic] = false
end

opts.on('--disable-performance', 'Disables reporting of API usages that results in downgrade of performance') do
$options[:performance] = false
end
end.parse!


def build_and_run_graph( source_location, sink_object )
# build graph and set up source
graph = BT2::BTGraph.new

ctf_fs = BT2::BTPlugin.find('ctf').get_source_component_class_by_name('fs')
ctf_lttng_live = BT2::BTPlugin.find("ctf").get_source_component_class_by_name("lttng-live")
utils_muxer = BT2::BTPlugin.find('utils').get_filter_component_class_by_name('muxer')

if !$options[:live]
trace_locations =
Find.find(*source_location).reject do |path|
FileTest.directory?(path)
end.select do |path|
File.basename(path) == 'metadata'
end.collect do |path|
File.dirname(path)
end.select do |path|
qe = BT2::BTQueryExecutor.new(component_class: ctf_fs, object_name: 'babeltrace.support-info',
params: { 'input' => path, 'type' => 'directory' })
qe.query.value['weight'] > 0.5
end
else
trace_locations = source_location
end
raise 'Could not find lttng trace' if trace_locations.size == 0

if !$options[:live]
comp_sources = trace_locations.each_with_index.collect { |trace_location, i| graph.add_component(ctf_fs, "trace_#{i}", params: {"inputs" => [ trace_location ] }) }
else
comp_sources = trace_locations.each_with_index.collect { |trace_location, i| graph.add_component(ctf_lttng_live, "trace_#{i}", params: {"inputs" => [ trace_location ], "session-not-found-action" => "end" }) }
end

# Muxer
comp_muxer = graph.add_component(utils_muxer, 'mux')

sink = graph.add_simple_sink('babeltrace_thapi', sink_object.consume)

# Sources to muxer
comp_sources.flat_map(&:output_ports).each_with_index do |op, i|
ip = comp_muxer.input_port(i)
graph.connect_ports(op, ip)
end

# Chain the rest
[comp_muxer, sink].flatten.each_cons(2) do |_out, _in|
op = _out.output_port(0)
ip = _in.input_port(0)
graph.connect_ports(op, ip)
end

graph.run
sink_object.check_issues()

end

# only executive this code if we launch this as the main
# script. if it's just included with "require" we just want access to the functions.
if __FILE__ == $0
generate_device_properties if $options[:gen_device_properties]
sink_obj = StateObject.new(device_agnostic: $options[:device_agnostic],
performance: $options[:performance])
ARGV.uniq!
source_location = ARGV
build_and_run_graph(source_location, sink_obj)
end
Loading
Loading