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,65 @@ class XNNExecutable final : public Executable {
381420 return Error::Ok;
382421 }
383422
384- Error run (const ExecutionContext&) override {
423+ Error run (const ExecutionContext& context ) override {
385424 ET_CHECK_OR_RETURN_ERROR (
386425 bound_, InvalidState, " XNNPACK requires a successful bind" );
387426 // Shared workspace growth can relocate another region's internal values.
388427 CPU_XNN_CHECK (
389428 xnn_setup_runtime_v2 (runtime_, external_.size (), external_.data ()));
429+ tracing_ = profiling_ &&
430+ profiling_ok (profiler_.start (context.event_tracer ), " start" );
390431 CPU_XNN_CHECK (xnn_invoke_runtime (runtime_));
391432 return Error::Ok;
392433 }
393434
435+ void submit_trace () override {
436+ if (tracing_) {
437+ tracing_ = false ;
438+ profiling_ok (profiler_.end (), " end" );
439+ }
440+ }
441+
394442 private:
395443 friend const XNNOp* find_op (std::string_view target);
396444
445+ #ifdef ET_EVENT_TRACER_ENABLED
446+ // Reads XNNPACK's internal runtime, which the public API does not expose.
447+ // xnn_get_runtime_profiling_info reports names and timings for opdata with a
448+ // primary operator, in opdata order; this must apply the same filter.
449+ Error describe_operators () {
450+ std::vector<std::string> shapes;
451+ for (size_t index = 0 ; index < runtime_->num_ops ; ++index) {
452+ const auto & op = runtime_->opdata [index];
453+ if (op.operator_objects [0 ] != nullptr ) {
454+ shapes.push_back (
455+ " {\" inputs\" :" + value_shapes (op.inputs , op.num_inputs ) +
456+ " ,\" outputs\" :" + value_shapes (op.outputs , op.num_outputs ) + " }" );
457+ }
458+ }
459+ return profiler_.set_operator_metadata (std::move (shapes));
460+ }
461+
462+ std::string value_shapes (const uint32_t * ids, uint32_t count) const {
463+ std::string text = " [" ;
464+ for (uint32_t index = 0 ; index < count; ++index) {
465+ text += index ? " ," : " " ;
466+ if (ids == nullptr || ids[index] == XNN_INVALID_VALUE_ID ||
467+ ids[index] >= runtime_->num_values ) {
468+ text += " null" ;
469+ continue ;
470+ }
471+ const auto & shape = runtime_->values [ids[index]].shape ;
472+ text += " [" ;
473+ for (size_t dim = 0 ; dim < shape.num_dims ; ++dim) {
474+ text += (dim ? " ," : " " ) + std::to_string (shape.dim [dim]);
475+ }
476+ text += " ]" ;
477+ }
478+ return text + " ]" ;
479+ }
480+ #endif
481+
397482 std::vector<size_t > dimensions (ptn::ValueId id) const {
398483 const auto & sizes = context_.graph .value (id).tensor_meta ().sizes ;
399484 return {sizes.begin (), sizes.end ()};
@@ -1122,6 +1207,9 @@ class XNNExecutable final : public Executable {
11221207 bool bound_ = false ;
11231208 std::vector<Binding> bindings_;
11241209 std::vector<xnn_external_value> external_;
1210+ XNNProfiler profiler_;
1211+ bool profiling_ = false ;
1212+ bool tracing_ = false ;
11251213};
11261214
11271215const XNNOp* find_op (std::string_view target) {
0 commit comments