Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backends/native/runtime/BUCK
Original file line number Diff line number Diff line change
@@ -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)
54 changes: 54 additions & 0 deletions backends/native/runtime/Program.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.

#include <executorch/backends/native/runtime/Program.h>

#include <cstdint>
#include <stdexcept>
#include <utility>
#include <vector>

#include <flatbuffers/flatbuffers.h>

#include <executorch/backends/native/runtime/native_graph_generated.h>

namespace ptn {

namespace {
// Minimum bytes for a FlatBuffer carrying a file identifier: a 4-byte root
// offset plus the 4-byte identifier.
constexpr size_t kMinBufferSize = 8;
} // namespace

Program Program::load(const void* data, size_t size) {
if (data == nullptr || size < kMinBufferSize) {
throw std::runtime_error("native program: buffer is null or too small");
}

const uint8_t* begin = static_cast<const uint8_t*>(data);
std::vector<uint8_t> bytes(begin, begin + size);

if (!::native_backend::ProgramBufferHasIdentifier(bytes.data())) {
throw std::runtime_error(
"native program: bad FlatBuffer file identifier (expected 'NPTG')");
}

flatbuffers::Verifier verifier(bytes.data(), bytes.size());
if (!::native_backend::VerifyProgramBuffer(verifier)) {
throw std::runtime_error("native program: FlatBuffer verification failed");
}

const ::native_backend::Program* program_fb =
::native_backend::GetProgram(bytes.data());
return Program(std::move(bytes), program_fb);
}

size_t Program::num_methods() const {
const auto* methods = program_fb_->methods();
return methods == nullptr ? 0 : methods->size();
}

} // namespace ptn
65 changes: 65 additions & 0 deletions backends/native/runtime/Program.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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.

#pragma once

#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>

// Forward-declaration of the generated FlatBuffer root type. The generated
// header is included only in Program.cpp / utils/ToGraphViz.cpp, so flatbuffers
// stays an implementation detail of the reader.
namespace native_backend {
struct Program;
} // namespace native_backend

namespace ptn {

// A loaded native-graph program: owns the serialized FlatBuffer bytes and
// exposes a zero-copy view of the root. Reader-only for now (no in-memory
// mutable graph, constants, or execution).
class Program {
private:
// Owns the bytes; the program_fb_ pointer aliases into this buffer.
// std::vector's move preserves the buffer address, so program_fb_ stays valid
// across a move. Never null on a live Program: the constructor is private and
// load(), the only caller, throws rather than hand back a null root, so the
// accessors below dereference it unchecked.
std::vector<uint8_t> bytes_;
const ::native_backend::Program* program_fb_ = nullptr;

Program(
std::vector<uint8_t> bytes,
const ::native_backend::Program* program_fb)
: bytes_(std::move(bytes)), program_fb_(program_fb) {}

public:
~Program() = default;
Program(Program&&) noexcept = default;
Program& operator=(Program&&) noexcept = default;
Program(const Program&) = delete;
Program& operator=(const Program&) = delete;

// Parse and verify serialized native-graph bytes (a *.nptg buffer). Throws
// std::runtime_error on failure. The returned Program owns a copy of the
// bytes; the zero-copy accessors are valid for its lifetime.
static Program load(const void* data, size_t size);

// Zero-copy FlatBuffer root, pointing into this Program's owned bytes.
const ::native_backend::Program* flatbuffer() const {
return program_fb_;
}

size_t num_methods() const;

// Render this program to Graphviz DOT text (impl in utils/ToDot.cpp). Pure
// string builder; the caller writes/renders it (e.g. `dot -Tpng`).
std::string to_dot() const;
};

} // namespace ptn
11 changes: 11 additions & 0 deletions backends/native/runtime/graph/BUCK
Original file line number Diff line number Diff line change
@@ -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)
34 changes: 34 additions & 0 deletions backends/native/runtime/graph/Format.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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.

#pragma once

#include <array>
#include <charconv>
#include <string>

namespace ptn {

// Render a double for a debug dump. Not std::to_string: its fixed six-decimal
// format prints 1e-8 as "0.000000" and 1e300 as 312 digits. to_chars emits the
// shortest form that round-trips. The longest such form is 24 characters
// ("-1.7976931348623157e+308"), so the buffer cannot overflow and the result
// needs no error check.
inline std::string format_double(double value) {
std::array<char, 32> buf{};
const std::to_chars_result out =
std::to_chars(buf.data(), buf.data() + buf.size(), value);
std::string text(buf.data(), out.ptr);
// to_chars renders 6.0 as "6", which in a dump reads as an int argument.
// Put the point back; exponent, "inf" and "nan" forms are already
// unambiguous, and each carries one of these characters.
if (text.find_first_of(".eni") == std::string::npos) {
text += ".0";
}
return text;
}

} // namespace ptn
11 changes: 11 additions & 0 deletions backends/native/runtime/graph/targets.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")

def define_common_targets():
# Debug-dump formatting shared by every renderer of the IR (header-only).
runtime.cxx_library(
name = "format",
exported_headers = [
"Format.h",
],
visibility = ["//executorch/backends/native/..."],
)
59 changes: 59 additions & 0 deletions backends/native/runtime/targets.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "is_xplat", "runtime")

def define_common_targets():
# The wrapper rewrites "//executorch/..." references for xplat in deps /
# exported_deps / visibility only, not in srcs, so spell the schema target
# out per cell. is_xplat() reads the package context, so it can only be
# called from inside this function, not at module scope.
native_graph_fbs = (
"//xplat/executorch/backends/native:native_graph.fbs" if is_xplat() else "//executorch/backends/native:native_graph.fbs"
)

# Compile the native graph FlatBuffer schema to a C++ header. flatc takes an
# output directory (not a file), so use `outs` to expand ${OUT} to the dir.
runtime.genrule(
name = "generate_native_graph",
srcs = [native_graph_fbs],
outs = {"native_graph_generated.h": ["native_graph_generated.h"]},
default_outs = ["native_graph_generated.h"],
cmd = " ".join([
"$(exe {})".format(runtime.external_dep_location("flatc")),
"--cpp",
"--cpp-std c++11",
"--gen-mutable",
"--scoped-enums",
"-o ${OUT}",
"${SRCS}",
]),
)

# Header-only library exposing the generated FlatBuffer accessors. Kept internal
# so flatbuffers stays an implementation detail of the reader.
runtime.cxx_library(
name = "native_graph_schema",
srcs = [],
exported_headers = {
"native_graph_generated.h": ":generate_native_graph[native_graph_generated.h]",
},
exported_external_deps = ["flatbuffers-api"],
visibility = ["//executorch/backends/native/..."],
)

# The native runtime program reader (standalone; no ExecuTorch dependency).
# utils/ToDot.cpp implements Program::to_dot() (DOT rendering); it is part of
# this package (no BUCK under utils/).
runtime.cxx_library(
name = "runtime",
srcs = [
"Program.cpp",
"utils/ToDot.cpp",
],
exported_headers = [
"Program.h",
],
deps = [
":native_graph_schema",
"//executorch/backends/native/runtime/graph:format",
],
visibility = ["PUBLIC"],
)
Loading
Loading