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
54 changes: 54 additions & 0 deletions backends/native/runtime/Program.h
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.

#pragma once

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

// Forward-declaration of the generated FlatBuffer root type, included only from
// .cpp files so flatbuffers stays an implementation detail of the reader.
namespace native_backend {
struct Program;
} // namespace native_backend

namespace ptn {

// Represents a loaded native-graph program
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: load() is the only constructor path and throws
// rather than return a null root, so accessors 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 *.ptg buffer). Throws
// std::runtime_error on failure.
static Program load(const void* data, size_t size);

const ::native_backend::Program* flatbuffer() const {
return program_fb_;
}

size_t num_methods() 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
10 changes: 10 additions & 0 deletions backends/native/runtime/graph/targets.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@fbsource//xplat/executorch/build:runtime_wrapper.bzl", "runtime")

def define_common_targets():
runtime.cxx_library(
name = "format",
exported_headers = [
"Format.h",
],
visibility = ["//executorch/backends/native/..."],
)
75 changes: 75 additions & 0 deletions backends/native/runtime/targets.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
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.
#
# Note that --cpp-std only picks the feature level of the flatbuffer
# *generated* accessors. flatc takes c++0x / c++11 / c++17 only -- no c++20.
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).
runtime.cxx_library(
name = "runtime",
srcs = [
"Program.cpp",
],
exported_headers = [
"Program.h",
],
deps = [
":native_graph_schema",
],
visibility = ["PUBLIC"],
)

# utils/ has no BUCK of its own, so the DOT renderer's target lives here.
runtime.cxx_library(
name = "to_dot",
srcs = [
"utils/ToDot.cpp",
],
exported_headers = [
"utils/ToDot.h",
],
deps = [
":native_graph_schema",
":runtime",
"//executorch/backends/native/runtime/graph:format",
],
visibility = ["PUBLIC"],
)
Loading
Loading