|
11 | 11 | #include <executorch/runtime/core/error.h> |
12 | 12 | #include <executorch/runtime/core/evalue.h> |
13 | 13 | #include <executorch/runtime/core/exec_aten/util/tensor_util.h> |
| 14 | +#include <sys/mman.h> |
14 | 15 | #include <unistd.h> |
| 16 | +#include <cerrno> |
15 | 17 | #include <chrono> |
16 | 18 | #include <cstdio> |
17 | 19 | #include <cstdlib> |
@@ -247,7 +249,41 @@ class ET_EXPERIMENTAL MetalBackend final |
247 | 249 | ET_LOG(Info, "MetalBackend::init - so_blob_key: %s", so_blob_key.c_str()); |
248 | 250 |
|
249 | 251 | const NamedDataMap* named_data_map = context.get_named_data_map(); |
250 | | - ET_LOG(Info, "MetalBackend::init - Got named data map: %p", named_data_map); |
| 252 | + ET_CHECK_OR_RETURN_ERROR( |
| 253 | + named_data_map != nullptr, |
| 254 | + Internal, |
| 255 | + "MetalBackend requires a NamedDataMap for weight loading"); |
| 256 | + |
| 257 | + // Prefetch the weights blob — trigger async readahead so pages are |
| 258 | + // resident by the time update_constants_from_blob memcpy's them. |
| 259 | + // This overlaps disk I/O with the .so write + dlopen (~200ms). |
| 260 | + std::string weights_blob_key = |
| 261 | + method_name.empty() ? "weights_blob" : method_name + "_weights_blob"; |
| 262 | + { |
| 263 | + auto prefetch_buf = named_data_map->get_data(weights_blob_key.c_str()); |
| 264 | + if (prefetch_buf.ok() && prefetch_buf->data() != nullptr) { |
| 265 | + // Align address down to page boundary (madvise requires it). |
| 266 | + uintptr_t addr = reinterpret_cast<uintptr_t>(prefetch_buf->data()); |
| 267 | + size_t page_size = getpagesize(); |
| 268 | + uintptr_t aligned_addr = addr & ~(page_size - 1); |
| 269 | + size_t aligned_size = prefetch_buf->size() + (addr - aligned_addr); |
| 270 | + int ret = madvise( |
| 271 | + reinterpret_cast<void*>(aligned_addr), aligned_size, MADV_WILLNEED); |
| 272 | + if (ret != 0) { |
| 273 | + ET_LOG( |
| 274 | + Info, |
| 275 | + "MetalBackend::init - madvise(MADV_WILLNEED) failed for %s: %s", |
| 276 | + weights_blob_key.c_str(), |
| 277 | + strerror(errno)); |
| 278 | + } else { |
| 279 | + ET_LOG( |
| 280 | + Info, |
| 281 | + "MetalBackend::init - Prefetching %s (%.1f MB)", |
| 282 | + weights_blob_key.c_str(), |
| 283 | + prefetch_buf->size() / (1024.0 * 1024.0)); |
| 284 | + } |
| 285 | + } |
| 286 | + } |
251 | 287 |
|
252 | 288 | ET_LOG( |
253 | 289 | Info, |
@@ -344,9 +380,8 @@ class ET_EXPERIMENTAL MetalBackend final |
344 | 380 |
|
345 | 381 | handle->container_handle = container_handle; |
346 | 382 |
|
347 | | - // Look into named data map for constant data |
348 | | - std::string weights_blob_key = |
349 | | - method_name.empty() ? "weights_blob" : method_name + "_weights_blob"; |
| 383 | + // Look into named data map for constant data (key computed above for |
| 384 | + // prefetch) |
350 | 385 | auto buffer_res = named_data_map->get_data(weights_blob_key.c_str()); |
351 | 386 | if (buffer_res.ok() && handle->update_constants_from_blob != nullptr) { |
352 | 387 | ET_LOG(Info, "Found %s in named data map", weights_blob_key.c_str()); |
|
0 commit comments