Skip to content

Commit b50c571

Browse files
authored
honor per-model packed-LHS disable in XNNPACK (#24245)
Summary: Add the `disable_packed_lhs` ExecuTorch XNNPACK backend option with a false global default and per-model runtime-spec overrides. Pass the resolved settings through `XNNCompilerOptions`. When the internal XNNPACK patch is available, set `XNN_FLAG_NO_PACKED_LHS` to preserve explicit dynamic quantization; builds without that flag retain their normal runtime flags and log enabled requests as unsupported. Reviewed By: digantdesai Differential Revision: D117888679 Pull Request resolved: #24245
1 parent c951e79 commit b50c571

11 files changed

Lines changed: 239 additions & 11 deletions

‎backends/xnnpack/runtime/XNNCompiler.cpp‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,7 +2131,7 @@ ET_NODISCARD Error XNNCompiler::compileModel(
21312131
XNNWeightsCache* weights_cache,
21322132
xnn_workspace_t workspace,
21332133
const NamedDataMap* named_data_map,
2134-
bool use_weight_cache) {
2134+
const XNNCompilerOptions& options) {
21352135
Result<XNNHeader> header = XNNHeader::Parse(buffer_pointer, num_bytes);
21362136
const uint8_t* flatbuffer_data = nullptr;
21372137
const uint8_t* constant_data = nullptr;
@@ -2239,7 +2239,7 @@ ET_NODISCARD Error XNNCompiler::compileModel(
22392239
// With the weights cache the buffers land in the cache rather than in
22402240
// unpacked_buffers, so track its list too.
22412241
size_t prev_cached_buffers =
2242-
use_weight_cache ? weights_cache->get_num_unpacked_data() : 0;
2242+
options.use_weight_cache ? weights_cache->get_num_unpacked_data() : 0;
22432243
err = defineTensor(
22442244
subgraph.get(),
22452245
remapped_ids,
@@ -2253,7 +2253,7 @@ ET_NODISCARD Error XNNCompiler::compileModel(
22532253
named_data_map,
22542254
unpacked_buffers,
22552255
weights_cache,
2256-
use_weight_cache);
2256+
options.use_weight_cache);
22572257

22582258
if (err != Error::Ok) {
22592259
return err;
@@ -2268,7 +2268,7 @@ ET_NODISCARD Error XNNCompiler::compileModel(
22682268
executor->unpacked_buffers_.push_back(std::move(unpacked_buffers[i]));
22692269
}
22702270
unpacked_buffers.resize(prev_buffers);
2271-
if (use_weight_cache) {
2271+
if (options.use_weight_cache) {
22722272
weights_cache->take_unpacked_data_from(
22732273
prev_cached_buffers, executor->unpacked_buffers_);
22742274
}
@@ -2288,10 +2288,20 @@ ET_NODISCARD Error XNNCompiler::compileModel(
22882288
runtime_flags |= XNN_FLAG_BASIC_PROFILING;
22892289
#endif
22902290

2291+
if (options.disable_packed_lhs) {
2292+
#if defined(XNN_FLAG_NO_PACKED_LHS)
2293+
runtime_flags |= XNN_FLAG_NO_PACKED_LHS;
2294+
#else
2295+
ET_LOG(
2296+
Error,
2297+
"Ignoring disable_packed_lhs: this XNNPACK build does not support it");
2298+
#endif
2299+
}
2300+
22912301
xnn_runtime_t runtime_ptr = nullptr;
22922302

22932303
xnn_weights_cache_t weights_cache_ptr = nullptr;
2294-
if (use_weight_cache) {
2304+
if (options.use_weight_cache) {
22952305
ET_CHECK_OR_RETURN_ERROR(
22962306
unpacked_buffers.size() == 0,
22972307
Internal,
@@ -2319,7 +2329,7 @@ ET_NODISCARD Error XNNCompiler::compileModel(
23192329
xnn_status_to_string(status));
23202330

23212331
std::vector<std::string> packed_weights_names;
2322-
if (use_weight_cache) {
2332+
if (options.use_weight_cache) {
23232333
// Constants XNNPACK does not pack were already moved to the executor in
23242334
// the value loop above, so everything left here is safe to free.
23252335
auto packed_weights_names_result = weights_cache->finalize_for_runtime();

‎backends/xnnpack/runtime/XNNCompiler.h‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ namespace backends {
1818
namespace xnnpack {
1919
namespace delegate {
2020

21+
struct XNNCompilerOptions {
22+
bool use_weight_cache{false};
23+
bool disable_packed_lhs{false};
24+
};
25+
2126
class XNNCompiler {
2227
public:
2328
// Takes Flatbuffer Serialized XNNPACK Model and rebuilds the xnn-subgraph
@@ -30,7 +35,7 @@ class XNNCompiler {
3035
XNNWeightsCache* weights_cache,
3136
xnn_workspace_t workspace,
3237
const NamedDataMap* named_data_map,
33-
bool use_weight_cache);
38+
const XNNCompilerOptions& options);
3439
};
3540

3641
} // namespace delegate

‎backends/xnnpack/runtime/XNNExecutor.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class XNNExecutor {
146146
executorch::runtime::Span<executorch::runtime::EValue*> args) const;
147147

148148
friend class XNNCompiler;
149+
friend class XNNPackedLhsTest;
149150
};
150151

151152
} // namespace delegate

‎backends/xnnpack/runtime/XNNPACKBackend.cpp‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,15 @@ class XnnpackBackend final
9090
}
9191
auto workspace = workspace_result.get();
9292

93-
bool use_weight_cache = options_.resolve_weight_cache(context);
93+
const xnnpack::delegate::XNNCompilerOptions compiler_options{
94+
.use_weight_cache = options_.resolve_weight_cache(context),
95+
.disable_packed_lhs = options_.resolve_disable_packed_lhs(context),
96+
};
9497
// Per-path weights cache: same-path PTEs share an instance and
9598
// serialize on its mutex; different paths run in parallel.
9699
std::shared_ptr<xnnpack::delegate::XNNWeightsCache> weights_cache;
97100
std::unique_lock<std::mutex> lock_weights_cache;
98-
if (use_weight_cache) {
101+
if (compiler_options.use_weight_cache) {
99102
// Only honor a path coming through runtime_spec (per-PTE opt-in).
100103
// Reading the backend-singleton global would let a non-opt-in PTE
101104
// inherit another model's cache file.
@@ -131,7 +134,7 @@ class XnnpackBackend final
131134
weights_cache.get(),
132135
workspace_ptr,
133136
named_data_map,
134-
use_weight_cache);
137+
compiler_options);
135138
// This backend does not need its processed data after compiling the model.
136139
processed->Free();
137140

@@ -147,7 +150,7 @@ class XnnpackBackend final
147150

148151
// Hand the cache to the executor (held by shared_ptr so it
149152
// outlives any sibling executors that share it).
150-
if (use_weight_cache) {
153+
if (compiler_options.use_weight_cache) {
151154
executor->set_weights_cache(std::move(weights_cache));
152155
}
153156

‎backends/xnnpack/runtime/XNNPACKBackend.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ const char workspace_sharing_mode_option_key[] = "workspace_sharing_mode";
1919
// across delegate instances. Changes only affect subsequently loaded models.
2020
const char weight_cache_option_key[] = "weight_cache_enabled";
2121

22+
/// The key for disabling packed-LHS graph rewrites. When enabled, XNNPACK
23+
/// preserves explicit dynamic-quantization nodes instead of folding them into
24+
/// packed-LHS consumers.
25+
// Must remain a C array for the BackendOptions template overloads.
26+
// @lint-ignore CLANGTIDY facebook-hte-CArray
27+
const char disable_packed_lhs_option_key[] = "disable_packed_lhs";
28+
2229
/// Path for the packed weight file. When set, reserve_space() allocates from
2330
/// a MAP_SHARED file instead of heap; msync makes pages clean on iOS.
2431
// Must remain a C array (not const char*) so it can bind to the

‎backends/xnnpack/runtime/XnnpackBackendOptions.cpp‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Error XnnpackBackendOptions::get_option(BackendOption& option) const {
3737
option.value = static_cast<int>(sharing_mode_.load());
3838
} else if (strcmp(option.key, weight_cache_option_key) == 0) {
3939
option.value = weight_cache_enabled_.load();
40+
} else if (strcmp(option.key, disable_packed_lhs_option_key) == 0) {
41+
option.value = disable_packed_lhs_.load();
4042
} else if (strcmp(option.key, packed_cache_path_option_key) == 0) {
4143
std::array<char, runtime::kMaxOptionValueLength> arr{};
4244
const std::lock_guard<std::mutex> lock(path_mutex_);
@@ -73,6 +75,14 @@ Error XnnpackBackendOptions::set_option(const BackendOption& option) {
7375
}
7476
ET_LOG(Debug, "Setting XNNPACK weight cache enabled to %d.", *val);
7577
weight_cache_enabled_.store(*val);
78+
} else if (strcmp(option.key, disable_packed_lhs_option_key) == 0) {
79+
auto* val = std::get_if<bool>(&option.value);
80+
if (!val) {
81+
ET_LOG(Error, "XNNPACK disable packed LHS must be a bool.");
82+
return Error::InvalidArgument;
83+
}
84+
ET_LOG(Debug, "Setting XNNPACK disable packed LHS to %d.", *val);
85+
disable_packed_lhs_.store(*val);
7686
} else if (strcmp(option.key, packed_cache_path_option_key) == 0) {
7787
auto* val = std::get_if<std::array<char, runtime::kMaxOptionValueLength>>(
7888
&option.value);
@@ -126,6 +136,12 @@ bool XnnpackBackendOptions::resolve_weight_cache(
126136
context, weight_cache_option_key, weight_cache_enabled_.load());
127137
}
128138

139+
bool XnnpackBackendOptions::resolve_disable_packed_lhs(
140+
const ET_RUNTIME_NAMESPACE::BackendInitContext& context) const {
141+
return resolve_option<bool>(
142+
context, disable_packed_lhs_option_key, disable_packed_lhs_.load());
143+
}
144+
129145
runtime::Result<WorkspaceSharingMode>
130146
XnnpackBackendOptions::resolve_sharing_mode(
131147
const ET_RUNTIME_NAMESPACE::BackendInitContext& context) const {

‎backends/xnnpack/runtime/XnnpackBackendOptions.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ class XnnpackBackendOptions {
3737
bool resolve_weight_cache(
3838
const ET_RUNTIME_NAMESPACE::BackendInitContext& context) const;
3939

40+
// Resolve whether packed-LHS graph rewrites are disabled for a delegate,
41+
// applying any runtime spec override.
42+
bool resolve_disable_packed_lhs(
43+
const ET_RUNTIME_NAMESPACE::BackendInitContext& context) const;
44+
4045
// Resolve the effective workspace sharing mode for a delegate, applying
4146
// any runtime spec override. Returns InvalidArgument for out-of-range values.
4247
runtime::Result<WorkspaceSharingMode> resolve_sharing_mode(
@@ -95,6 +100,8 @@ class XnnpackBackendOptions {
95100
std::atomic<bool> weight_cache_enabled_{false};
96101
#endif
97102

103+
std::atomic<bool> disable_packed_lhs_{false};
104+
98105
// The most-recently-set packed cache path. Today's callers (Cria
99106
// runner) set this via set_option(packed_cache_path_option_key) per
100107
// PTE, then invoke init() which reads it and calls

‎backends/xnnpack/test/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ et_cxx_test(
3636
target_include_directories(
3737
backends_xnnpack_test
3838
PRIVATE ${EXECUTORCH_ROOT}/backends/xnnpack/third-party/XNNPACK/include
39+
${EXECUTORCH_ROOT}/backends/xnnpack/third-party/XNNPACK
3940
${EXECUTORCH_ROOT}/backends/xnnpack/third-party/XNNPACK/src
4041
${EXECUTORCH_ROOT}/backends/xnnpack/third-party/cpuinfo/include
4142
${EXECUTORCH_ROOT}/backends/xnnpack/third-party/pthreadpool/include

‎backends/xnnpack/test/runtime/test_weight_cache.cpp‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
using namespace ::testing;
2222

23+
using executorch::backends::xnnpack::disable_packed_lhs_option_key;
2324
using executorch::backends::xnnpack::get_packed_cache_report;
2425
using executorch::backends::xnnpack::packed_cache_path_option_key;
2526
using executorch::backends::xnnpack::PackedCacheHeapReason;
@@ -53,6 +54,24 @@ static void set_and_check_weight_cache_enabled(bool enabled) {
5354
ASSERT_EQ(std::get<bool>(read_option.value), enabled);
5455
}
5556

57+
static void set_and_check_disable_packed_lhs(bool disabled) {
58+
executorch::runtime::runtime_init();
59+
60+
BackendOptions<1> backend_options;
61+
backend_options.set_option(disable_packed_lhs_option_key, disabled);
62+
63+
auto status = executorch::runtime::set_option(
64+
xnnpack_backend_key, backend_options.view());
65+
ASSERT_EQ(status, Error::Ok);
66+
67+
BackendOption read_option;
68+
strcpy(read_option.key, disable_packed_lhs_option_key);
69+
read_option.value = !disabled;
70+
status = get_option(xnnpack_backend_key, read_option);
71+
72+
ASSERT_EQ(std::get<bool>(read_option.value), disabled);
73+
}
74+
5675
static TensorPtr create_input_tensor(float val) {
5776
std::vector<float> data(1000, val);
5877
return executorch::extension::make_tensor_ptr({10, 10, 10}, std::move(data));
@@ -101,6 +120,22 @@ TEST(WeightCache, SetInvalidType) {
101120
ASSERT_EQ(status, Error::InvalidArgument);
102121
}
103122

123+
TEST(PackedLhs, SetDisabled) {
124+
set_and_check_disable_packed_lhs(true);
125+
set_and_check_disable_packed_lhs(false);
126+
}
127+
128+
TEST(PackedLhs, SetInvalidType) {
129+
executorch::runtime::runtime_init();
130+
131+
BackendOptions<1> backend_options;
132+
backend_options.set_option(disable_packed_lhs_option_key, 1);
133+
134+
auto status = executorch::runtime::set_option(
135+
xnnpack_backend_key, backend_options.view());
136+
ASSERT_EQ(status, Error::InvalidArgument);
137+
}
138+
104139
TEST(WeightCache, SetMultipleOptions) {
105140
executorch::runtime::runtime_init();
106141

0 commit comments

Comments
 (0)