66
77#include < executorch/backends/cpu/runtime/op_helpers/Convolution.h>
88#include < executorch/backends/cpu/runtime/providers/xnnpack/XNNPACKProvider.h>
9+ #include < executorch/backends/xnnpack/runtime/profiling/XNNProfiler.h>
910#include < executorch/extension/memory_allocator/malloc_memory_allocator.h>
1011#include < xnnpack.h>
12+ #ifdef ET_EVENT_TRACER_ENABLED
13+ #include " src/xnnpack/subgraph.h" // @manual
14+ #endif
1115
1216#include < algorithm>
1317#include < array>
1418#include < cmath>
1519#include < limits>
1620#include < map>
1721#include < numeric>
22+ #include < string>
1823#include < string_view>
24+ #include < unordered_map>
1925#include < unordered_set>
2026#include < utility>
2127
2228namespace executorch ::backends::cpu {
2329namespace {
2430using namespace executorch ::runtime;
31+ using executorch::backends::xnnpack::delegate::profiling::XNNProfiler;
2532
2633Error check (xnn_status status, const char * operation) {
2734 if (status == xnn_status_success) {
@@ -41,6 +48,17 @@ Error check(xnn_status status, const char* operation) {
4148 } \
4249 } while (false )
4350
51+ bool profiling_ok (Error error, const char * operation) {
52+ if (error != Error::Ok) {
53+ ET_LOG (
54+ Error,
55+ " CPU XNNPACK profiling %s failed: %u" ,
56+ operation,
57+ static_cast <unsigned int >(error));
58+ }
59+ return error == Error::Ok;
60+ }
61+
4462bool constant (const ptn::Value& value) {
4563 return value.role == ptn::ValueRole::Parameter ||
4664 value.role == ptn::ValueRole::ConstantTensor ||
@@ -244,6 +262,8 @@ class XNNState {
244262 return std::exchange (packing_source_bytes_, 0 );
245263 }
246264 std::map<std::pair<ptn::ValueId, bool >, Buffer> converted_weights;
265+ // / Numbers ETDump operator names uniquely across the provider's regions.
266+ std::unordered_map<std::string, uint32_t > operator_counts;
247267 xnn_workspace_t workspace = nullptr ;
248268 xnn_weights_cache_t cache = nullptr ;
249269
@@ -334,13 +354,27 @@ class XNNExecutable final : public Executable {
334354 return error;
335355 }
336356 }
357+ uint32_t runtime_flags = 0 ;
358+ #ifdef ET_EVENT_TRACER_ENABLED
359+ auto * tracer = context_.execution .event_tracer ;
360+ if (tracer &&
361+ tracer->event_tracer_profiling_level () >
362+ EventTracerProfilingLevel::kProfileMethodOnly ) {
363+ runtime_flags |= XNN_FLAG_BASIC_PROFILING ;
364+ }
365+ #endif
337366 CPU_XNN_CHECK (xnn_create_runtime_v4 (
338367 subgraph_,
339368 state_.cache ,
340369 state_.workspace ,
341370 context_.execution .threadpool ,
342- 0 ,
371+ runtime_flags ,
343372 &runtime_));
373+ if (runtime_flags & XNN_FLAG_BASIC_PROFILING ) {
374+ profiling_ = profiling_ok (
375+ profiler_.initialize (runtime_, &state_.operator_counts ),
376+ " initialization" );
377+ }
344378 return Error::Ok;
345379 }
346380
@@ -359,6 +393,11 @@ class XNNExecutable final : public Executable {
359393 " XNNPACK inferred a different semantic shape for %s" ,
360394 context_.graph .value (binding.id ).name .c_str ());
361395 }
396+ #ifdef ET_EVENT_TRACER_ENABLED
397+ if (profiling_) {
398+ profiling_ok (describe_operators (), " metadata" );
399+ }
400+ #endif
362401 return Error::Ok;
363402 }
364403
@@ -381,19 +420,67 @@ class XNNExecutable final : public Executable {
381420 return Error::Ok;
382421 }
383422
384- Error run (const ExecutionContext&) override {
423+ Error run (const ExecutionContext& context) override {
424+ // Closes a session left open by a caller that skipped submit_trace.
425+ submit_trace ();
385426 ET_CHECK_OR_RETURN_ERROR (
386427 bound_, InvalidState, " XNNPACK requires a successful bind" );
387428 // Shared workspace growth can relocate another region's internal values.
388429 CPU_XNN_CHECK (
389430 xnn_setup_runtime_v2 (runtime_, external_.size (), external_.data ()));
431+ tracing_ = profiling_ &&
432+ profiling_ok (profiler_.start (context.event_tracer ), " start" );
390433 CPU_XNN_CHECK (xnn_invoke_runtime (runtime_));
391434 return Error::Ok;
392435 }
393436
437+ void submit_trace () override {
438+ if (tracing_) {
439+ tracing_ = false ;
440+ profiling_ok (profiler_.end (), " end" );
441+ }
442+ }
443+
394444 private:
395445 friend const XNNOp* find_op (std::string_view target);
396446
447+ #ifdef ET_EVENT_TRACER_ENABLED
448+ // Reads XNNPACK's internal runtime, which the public API does not expose.
449+ // xnn_get_runtime_profiling_info reports names and timings for opdata with a
450+ // primary operator, in opdata order; this must apply the same filter.
451+ Error describe_operators () {
452+ std::vector<std::string> shapes;
453+ for (size_t index = 0 ; index < runtime_->num_ops ; ++index) {
454+ const auto & op = runtime_->opdata [index];
455+ if (op.operator_objects [0 ] != nullptr ) {
456+ shapes.push_back (
457+ " {\" inputs\" :" + value_shapes (op.inputs , op.num_inputs ) +
458+ " ,\" outputs\" :" + value_shapes (op.outputs , op.num_outputs ) + " }" );
459+ }
460+ }
461+ return profiler_.set_operator_metadata (std::move (shapes));
462+ }
463+
464+ std::string value_shapes (const uint32_t * ids, uint32_t count) const {
465+ std::string text = " [" ;
466+ for (uint32_t index = 0 ; index < count; ++index) {
467+ text += index ? " ," : " " ;
468+ if (ids[index] == XNN_INVALID_VALUE_ID ||
469+ ids[index] >= runtime_->num_values ) {
470+ text += " null" ;
471+ continue ;
472+ }
473+ const auto & shape = runtime_->values [ids[index]].shape ;
474+ text += " [" ;
475+ for (size_t dim = 0 ; dim < shape.num_dims ; ++dim) {
476+ text += (dim ? " ," : " " ) + std::to_string (shape.dim [dim]);
477+ }
478+ text += " ]" ;
479+ }
480+ return text + " ]" ;
481+ }
482+ #endif
483+
397484 std::vector<size_t > dimensions (ptn::ValueId id) const {
398485 const auto & sizes = context_.graph .value (id).tensor_meta ().sizes ;
399486 return {sizes.begin (), sizes.end ()};
@@ -1122,6 +1209,9 @@ class XNNExecutable final : public Executable {
11221209 bool bound_ = false ;
11231210 std::vector<Binding> bindings_;
11241211 std::vector<xnn_external_value> external_;
1212+ XNNProfiler profiler_;
1213+ bool profiling_ = false ;
1214+ bool tracing_ = false ;
11251215};
11261216
11271217const XNNOp* find_op (std::string_view target) {
0 commit comments