diff --git a/backends/native/tools/BUCK b/backends/native/tools/BUCK new file mode 100644 index 00000000000..0ab35888218 --- /dev/null +++ b/backends/native/tools/BUCK @@ -0,0 +1,11 @@ +load("@fbcode_macros//build_defs:build_file_migration.bzl", "fbcode_target", "non_fbcode_target") +load(":targets.bzl", "define_common_targets") + +oncall("executorch") + +# Any targets that should be shared between fbcode and xplat must be defined in +# targets.bzl. This file can contain cell-only targets. + +non_fbcode_target(_kind = define_common_targets) + +fbcode_target(_kind = define_common_targets) diff --git a/backends/native/tools/native_executor.cpp b/backends/native/tools/native_executor.cpp new file mode 100644 index 00000000000..1188d616b94 --- /dev/null +++ b/backends/native/tools/native_executor.cpp @@ -0,0 +1,107 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// All rights reserved. +// +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the root directory of this source tree. + +// native_executor: a standalone harness for native-runtime graphs. +// +// Scope today: load a serialized native graph (*.nptg) and its optional +// out-of-line constant file into memory, and report what was loaded. This is +// the seed of a central tool that will grow load / inspect / benchmark / +// validate / profile subcommands. It has no ExecuTorch or torch dependency; +// until the C++ program reader lands it treats both files as raw bytes. + +#include +#include +#include +#include +#include +#include +#include + +#include + +DEFINE_string(program, "", "Path to the *.nptg to load. Required."); +DEFINE_string(constants, "", "Path to the out-of-line constant file."); + +namespace { + +// FlatBuffer file_identifier for a native Program, at byte offset 4 (see +// native_graph.fbs: file_identifier "NPTG"). +constexpr char kProgramMagic[4] = {'N', 'P', 'T', 'G'}; +constexpr size_t kMagicOffset = 4; + +// Read an entire file into a byte buffer; nullopt (with a message) on failure. +std::optional> read_file(const std::string& path) { + std::ifstream f(path, std::ios::binary | std::ios::ate); + if (!f) { + std::fprintf(stderr, "error: cannot open %s\n", path.c_str()); + return std::nullopt; + } + const std::streamsize size = f.tellg(); + if (size < 0) { + std::fprintf(stderr, "error: cannot size %s\n", path.c_str()); + return std::nullopt; + } + f.seekg(0, std::ios::beg); + std::vector buf(static_cast(size)); + if (size > 0 && !f.read(reinterpret_cast(buf.data()), size)) { + std::fprintf(stderr, "error: cannot read %s\n", path.c_str()); + return std::nullopt; + } + return buf; +} + +bool has_program_magic(const std::vector& buf) { + if (buf.size() < kMagicOffset + sizeof(kProgramMagic)) { + return false; + } + return std::memcmp( + buf.data() + kMagicOffset, kProgramMagic, sizeof(kProgramMagic)) == + 0; +} + +} // namespace + +int main(int argc, char** argv) { + gflags::SetUsageMessage( + "Load a serialized native graph and report what it holds."); + gflags::ParseCommandLineFlags(&argc, &argv, true); + if (FLAGS_program.empty()) { + std::fprintf(stderr, "error: --program is required\n"); + return 1; + } + + const std::optional> program = read_file(FLAGS_program); + if (!program) { + return 1; + } + const bool magic_ok = has_program_magic(*program); + std::printf("program: %s\n", FLAGS_program.c_str()); + std::printf(" bytes: %zu\n", program->size()); + std::printf( + " magic: %s (expect 'NPTG' at offset 4)\n", + magic_ok ? "NPTG ok" : "MISSING/BAD"); + + if (!FLAGS_constants.empty()) { + const std::optional> constants = + read_file(FLAGS_constants); + if (!constants) { + return 1; + } + std::printf("constants: %s\n", FLAGS_constants.c_str()); + std::printf(" bytes: %zu\n", constants->size()); + std::printf( + " note: opaque bytes only (torch pickle; not parsed in " + "standalone C++)\n"); + } + + if (!magic_ok) { + std::fprintf( + stderr, "error: program is not a native graph (bad NPTG magic)\n"); + return 2; + } + std::printf("ok: loaded into memory\n"); + return 0; +} diff --git a/backends/native/tools/targets.bzl b/backends/native/tools/targets.bzl new file mode 100644 index 00000000000..211e474f9b4 --- /dev/null +++ b/backends/native/tools/targets.bzl @@ -0,0 +1,9 @@ +load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime") + +def define_common_targets(): + runtime.cxx_binary( + name = "native_executor", + srcs = ["native_executor.cpp"], + external_deps = ["gflags"], + visibility = ["PUBLIC"], + )