In HalideRuntime.h, we document the meaning of a trace event's parent as follows:
|
* halide_trace returns a unique ID which will be passed to future |
|
* events that "belong" to the earlier event as the parent id. The |
|
* ownership hierarchy looks like: |
|
* |
|
* begin_pipeline |
|
* +--trace_tag (if any) |
|
* +--trace_tag (if any) |
|
* ... |
|
* +--begin_realization |
|
* | +--produce |
|
* | | +--load/store |
|
* | | +--end_produce |
|
* | +--consume |
|
* | | +--load |
|
* | | +--end_consume |
|
* | +--end_realization |
|
* +--end_pipeline |
From this, we see that loads may be owned by either produce events or consume events, and that these are further tied to a specific realization. Every trace packet also contains a reference to a func name1, as shown here:
|
/** Get the func name, assuming this packet is laid out in memory |
|
* as it was written. It comes after the value. */ |
|
HALIDE_ALWAYS_INLINE const char *func() const { |
|
return (const char *)value() + type.lanes * type.bytes(); |
|
} |
|
|
|
HALIDE_ALWAYS_INLINE char *func() { |
|
return (char *)value() + type.lanes * type.bytes(); |
|
} |
Clearly, for a load packet, this is the name of the func loaded from.
So one is left to assume that the parent PRODUCE node of a load would be tied to the func whose realization is doing the loading, right? Unfortunately, no. The lowering in Tracing.cpp uses the load target's name both for writing out the name in the packet directly, as seen here:
|
TraceEventBuilder builder; |
|
builder.func = op->name; |
|
builder.value = {value_var}; |
|
builder.coordinates = op->args; |
|
builder.type = op->type; |
|
builder.event = halide_trace_load; |
|
builder.parent_id = trace_parent; |
|
builder.value_index = op->value_index; |
|
Expr trace = builder.build(); |
and also for determining the parent ID, which always points to a CONSUME node, as seen here:
|
if (op->call_type == Call::Halide) { |
|
auto it = env.find(op->name); |
|
internal_assert(it != env.end()) << op->name << " not in environment\n"; |
|
Function f = it->second; |
|
internal_assert(!f.can_be_inlined() || !f.schedule().compute_level().is_inlined()); |
|
|
|
trace_it = trace_all_loads || f.is_tracing_loads(); |
|
trace_parent = Variable::make(Int(32), op->name + ".trace_id"); |
|
if (trace_it) { |
|
add_trace_tags(op->name, f.get_trace_tags()); |
|
touch(funcs_touched, op->name, op->value_index, op->type); |
|
} |
Even more vexingly, loads to ImageParams have the pipeline itself as the parent, which is not even permitted under the documentation.
|
} else if (op->call_type == Call::Image) { |
|
// op->param is defined when we're loading from an ImageParam, and undefined |
|
// when we're loading from an inlined Buffer. |
|
trace_it = trace_all_loads || (op->param.defined() && op->param.is_tracing_loads()); |
|
trace_parent = Variable::make(Int(32), "pipeline.trace_id"); |
|
if (trace_it) { |
|
if (op->param.defined()) { |
|
add_trace_tags(op->name, op->param.get_trace_tags()); |
|
} |
|
touch(images_touched, op->name, op->value_index, op->type); |
|
} |
|
} |
In all cases, op refers to a Call node in the IR.
In HalideRuntime.h, we document the meaning of a trace event's parent as follows:
Halide/src/runtime/HalideRuntime.h
Lines 643 to 659 in 5423753
From this, we see that loads may be owned by either produce events or consume events, and that these are further tied to a specific realization. Every trace packet also contains a reference to a func name1, as shown here:
Halide/src/runtime/HalideRuntime.h
Lines 720 to 728 in 5423753
Clearly, for a load packet, this is the name of the func loaded from.
So one is left to assume that the parent PRODUCE node of a load would be tied to the func whose realization is doing the loading, right? Unfortunately, no. The lowering in Tracing.cpp uses the load target's name both for writing out the name in the packet directly, as seen here:
Halide/src/Tracing.cpp
Lines 141 to 149 in 5423753
and also for determining the parent ID, which always points to a CONSUME node, as seen here:
Halide/src/Tracing.cpp
Lines 112 to 123 in 5423753
Even more vexingly, loads to ImageParams have the pipeline itself as the parent, which is not even permitted under the documentation.
Halide/src/Tracing.cpp
Lines 124 to 135 in 5423753
In all cases,
oprefers to a Call node in the IR.Footnotes
Because a func might be realized multiple times in parallel, I believe the name alone is insufficient to determine a true load target, unless there is some additional invariant we can use to disambiguate. ↩