[orc-rt] Add BootstrapInfo: info for controller session bootstrap. (#187184)

BootstrapInfo holds information needed to bootstrap the ExecutionSession
in the controller. Future patches will update ControllerAccess to send
the bootstrap information at controller-connection time.

BootstrapInfo includes information about the executor process (via
Session::processInfo), an initial set of symbols (replacing
Session::controllerInterface()), and a simple key/value store.
This commit is contained in:
Lang Hames 2026-03-18 15:07:57 +11:00 committed by GitHub
parent c61d11df40
commit ffcb5745ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 275 additions and 46 deletions

View File

@ -6,6 +6,7 @@ set(ORC_RT_HEADERS
orc-rt-c/orc-rt.h
orc-rt/AllocAction.h
orc-rt/BitmaskEnum.h
orc-rt/BootstrapInfo.h
orc-rt/Compiler.h
orc-rt/SimpleSymbolTable.h
orc-rt/Error.h

View File

@ -0,0 +1,67 @@
//===- BootstrapInfo.h - Bootstrap syms & values for controller -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// BootstrapInfo API.
//
//===----------------------------------------------------------------------===//
#ifndef ORC_RT_BOOTSTRAPINFO_H
#define ORC_RT_BOOTSTRAPINFO_H
#include "orc-rt/Error.h"
#include "orc-rt/SimpleSymbolTable.h"
#include "orc-rt/move_only_function.h"
#include "orc-rt/sps-ci/AllSPSCI.h"
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace orc_rt {
class ExecutorProcessInfo;
class Session;
/// Holds initial values that will be used to bootstrap the controller's
/// ExecutorProcessControl object.
class BootstrapInfo {
public:
using ValueMap = std::unordered_map<std::string, std::string>;
using InitialSymbolsBuilder = move_only_function<Error(SimpleSymbolTable &)>;
using InitialValuesBuilder = move_only_function<Error(ValueMap &)>;
/// Construct a BootstrapInfo object from the given Session, Symbols, and
/// Values.
BootstrapInfo(Session &S, SimpleSymbolTable Symbols = {},
ValueMap Values = {});
/// Construct with a default initial symbols and values.
static Expected<BootstrapInfo>
CreateDefault(Session &S,
InitialSymbolsBuilder AddInitialSymbols = sps_ci::addAll,
InitialValuesBuilder AddInitialValues = {});
const Session &session() const noexcept { return S; }
const ExecutorProcessInfo &processInfo() const noexcept;
SimpleSymbolTable &symbols() noexcept { return Symbols; }
const SimpleSymbolTable &symbols() const noexcept { return Symbols; }
ValueMap &values() noexcept { return Values; }
const ValueMap &values() const noexcept { return Values; }
private:
Session &S;
SimpleSymbolTable Symbols;
ValueMap Values;
};
} // namespace orc_rt
#endif // ORC_RT_BOOTSTRAPINFO_H

View File

@ -139,10 +139,6 @@ public:
/// Report an error via the ErrorReporter function.
void reportError(Error Err) { ReportError(std::move(Err)); }
/// Controller interface symbols map.
auto controllerInterface() { return LockedAccess(CI, M); }
auto controllerInterface() const { return LockedAccess(CI, M); }
/// Initiate session shutdown.
///
/// Runs shutdown on registered resources in reverse order.
@ -216,7 +212,6 @@ private:
mutable std::mutex M;
std::vector<std::unique_ptr<Service>> Services;
SimpleSymbolTable CI;
std::unique_ptr<ShutdownInfo> SI;
};

View File

@ -0,0 +1,52 @@
//===- BootstrapInfo.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Contains the implementation of APIs in the orc-rt/BootstrapInfo.h header.
//
//===----------------------------------------------------------------------===//
#include "orc-rt/BootstrapInfo.h"
#include "orc-rt/ExecutorProcessInfo.h"
#include "orc-rt/Session.h"
namespace orc_rt {
BootstrapInfo::BootstrapInfo(Session &S, SimpleSymbolTable Symbols,
ValueMap Values)
: S(S), Symbols(std::move(Symbols)), Values(std::move(Values)) {}
Expected<BootstrapInfo>
BootstrapInfo::CreateDefault(Session &S,
InitialSymbolsBuilder AddInitialSymbols,
InitialValuesBuilder AddInitialValues) {
SimpleSymbolTable InitialSymbols;
// Add session symbol.
std::pair<const char *, const void *> SessionSymbol[] = {
{"orc_rt_Session_Instance", static_cast<const void *>(&S)}};
if (auto Err = InitialSymbols.addUnique(SessionSymbol))
return std::move(Err);
if (AddInitialSymbols)
if (auto Err = AddInitialSymbols(InitialSymbols))
return std::move(Err);
ValueMap InitialValues;
if (AddInitialValues)
if (auto Err = AddInitialValues(InitialValues))
return std::move(Err);
return BootstrapInfo(S, std::move(InitialSymbols), std::move(InitialValues));
}
const ExecutorProcessInfo &BootstrapInfo::processInfo() const noexcept {
return S.processInfo();
}
} // namespace orc_rt

View File

@ -1,5 +1,6 @@
set(files
AllocAction.cpp
BootstrapInfo.cpp
SimpleSymbolTable.cpp
Error.cpp
ExecutorProcessInfo.cpp

View File

@ -20,12 +20,7 @@ Session::Session(ExecutorProcessInfo EPI,
std::unique_ptr<TaskDispatcher> Dispatcher,
ErrorReporterFn ReportError)
: EPI(std::move(EPI)), Dispatcher(std::move(Dispatcher)),
ReportError(std::move(ReportError)) {
std::pair<const char *, void *> InitialSymbols[] = {
{"orc_rt_SessionInstance", static_cast<void *>(this)}};
cantFail(CI.addUnique(InitialSymbols));
}
ReportError(std::move(ReportError)) {}
Session::~Session() { waitForShutdown(); }

View File

@ -0,0 +1,152 @@
//===- BootstrapInfoTest.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Tests for orc-rt's BootstrapInfo.h APIs.
//
//===----------------------------------------------------------------------===//
#include "orc-rt/BootstrapInfo.h"
#include "orc-rt/Session.h"
#include "orc-rt/TaskDispatcher.h"
#include "gtest/gtest.h"
using namespace orc_rt;
static ExecutorProcessInfo mockExecutorProcessInfo() noexcept {
return ExecutorProcessInfo("arm64-apple-darwin", 16384);
}
class NoDispatcher : public TaskDispatcher {
public:
void dispatch(std::unique_ptr<Task> T) override {
assert(false && "strictly no dispatching!");
}
void shutdown() override {}
};
static void noErrors(Error Err) { cantFail(std::move(Err)); }
TEST(BootstrapInfoTest, ExplicitConstruction) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
BootstrapInfo BI(S);
EXPECT_EQ(&BI.session(), &S);
EXPECT_TRUE(BI.symbols().empty());
EXPECT_TRUE(BI.values().empty());
}
TEST(BootstrapInfoTest, ExplicitConstructionWithSymbolsAndValues) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
int X = 0;
SimpleSymbolTable Symbols;
std::pair<const char *, void *> Syms[] = {{"orc_rt_X", &X}};
cantFail(Symbols.addUnique(Syms));
BootstrapInfo::ValueMap Values;
Values["key"] = "value";
BootstrapInfo BI(S, std::move(Symbols), std::move(Values));
EXPECT_EQ(BI.symbols().size(), 1U);
EXPECT_TRUE(BI.symbols().count("orc_rt_X"));
EXPECT_EQ(BI.symbols().at("orc_rt_X"), &X);
EXPECT_EQ(BI.values().size(), 1U);
EXPECT_EQ(BI.values().at("key"), "value");
}
TEST(BootstrapInfoTest, ProcessInfoDelegates) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
BootstrapInfo BI(S);
EXPECT_EQ(&BI.processInfo(), &S.processInfo());
}
TEST(BootstrapInfoTest, CreateDefaultSucceeds) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = cantFail(BootstrapInfo::CreateDefault(S));
EXPECT_EQ(&BI.session(), &S);
}
TEST(BootstrapInfoTest, CreateDefaultContainsSessionSymbol) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = cantFail(BootstrapInfo::CreateDefault(S));
ASSERT_TRUE(BI.symbols().count("orc_rt_Session_Instance"));
EXPECT_EQ(BI.symbols().at("orc_rt_Session_Instance"),
static_cast<const void *>(&S));
}
TEST(BootstrapInfoTest, CreateDefaultContainsSPSCISymbols) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = cantFail(BootstrapInfo::CreateDefault(S));
// The default addAll should have registered SPS CI symbols.
EXPECT_TRUE(BI.symbols().count(
"orc_rt_sps_ci_SimpleNativeMemoryMap_reserve_sps_wrapper"));
}
TEST(BootstrapInfoTest, CreateDefaultWithNoSymbolsBuilder) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = cantFail(BootstrapInfo::CreateDefault(S, /*AddInitialSymbols=*/{},
/*AddInitialValues=*/{}));
// Should still contain the session symbol (added unconditionally).
ASSERT_TRUE(BI.symbols().count("orc_rt_Session_Instance"));
// But no SPS CI symbols.
EXPECT_FALSE(BI.symbols().count(
"orc_rt_sps_ci_SimpleNativeMemoryMap_reserve_sps_wrapper"));
}
TEST(BootstrapInfoTest, CreateDefaultWithCustomValuesBuilder) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = cantFail(BootstrapInfo::CreateDefault(
S, sps_ci::addAll, [](BootstrapInfo::ValueMap &Values) -> Error {
Values["test_key"] = "test_value";
return Error::success();
}));
EXPECT_EQ(BI.values().at("test_key"), "test_value");
}
TEST(BootstrapInfoTest, CreateDefaultSymbolsBuilderError) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = BootstrapInfo::CreateDefault(S, [](SimpleSymbolTable &) -> Error {
return make_error<StringError>("symbols builder failed");
});
EXPECT_FALSE(!!BI);
auto ErrMsg = toString(BI.takeError());
EXPECT_NE(ErrMsg.find("symbols builder failed"), std::string::npos);
}
TEST(BootstrapInfoTest, CreateDefaultValuesBuilderError) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
auto BI = BootstrapInfo::CreateDefault(
S, sps_ci::addAll, [](BootstrapInfo::ValueMap &) -> Error {
return make_error<StringError>("values builder failed");
});
EXPECT_FALSE(!!BI);
auto ErrMsg = toString(BI.takeError());
EXPECT_NE(ErrMsg.find("values builder failed"), std::string::npos);
}
TEST(BootstrapInfoTest, MutableSymbolsAndValues) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
BootstrapInfo BI(S);
int X = 0;
std::pair<const char *, void *> Syms[] = {{"orc_rt_X", &X}};
cantFail(BI.symbols().addUnique(Syms));
BI.values()["key"] = "value";
EXPECT_EQ(BI.symbols().size(), 1U);
EXPECT_EQ(BI.values().size(), 1U);
}

View File

@ -14,6 +14,7 @@ endfunction()
add_orc_rt_unittest(CoreTests
AllocActionTest.cpp
BitmaskEnumTest.cpp
BootstrapInfoTest.cpp
CallableTraitsHelperTest.cpp
SimpleSymbolTableTest.cpp
EndianTest.cpp

View File

@ -398,41 +398,6 @@ TEST(SessionTest, CreateServiceAndUseRef) {
CS.doMoreConfig(1);
}
TEST(SessionTest, ControllerInterfaceContainsSessionByDefault) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
ASSERT_TRUE(S.controllerInterface()->count("orc_rt_SessionInstance"));
EXPECT_EQ(S.controllerInterface()->at("orc_rt_SessionInstance"),
static_cast<void *>(&S));
}
TEST(SessionTest, ControllerInterfaceWithRef) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
int X = 0, Y = 0;
S.controllerInterface().with_ref([&](SimpleSymbolTable &ST) {
std::pair<const char *, void *> Syms[] = {
{"orc_rt_A", static_cast<void *>(&X)},
{"orc_rt_B", static_cast<void *>(&Y)}};
cantFail(ST.addUnique(Syms));
});
EXPECT_EQ(S.controllerInterface()->at("orc_rt_A"), &X);
EXPECT_EQ(S.controllerInterface()->at("orc_rt_B"), &Y);
}
TEST(SessionTest, ControllerInterfaceConstAccess) {
Session S(mockExecutorProcessInfo(), std::make_unique<NoDispatcher>(),
noErrors);
int X = 0;
std::pair<const char *, void *> Syms[] = {{"orc_rt_X", &X}};
cantFail(S.controllerInterface()->addUnique(Syms));
const Session &CS = S;
ASSERT_TRUE(CS.controllerInterface()->count("orc_rt_X"));
EXPECT_EQ(CS.controllerInterface()->at("orc_rt_X"), &X);
}
TEST(ControllerAccessTest, Basics) {
// Test that we can set the ControllerAccess implementation and still shut
// down as expected.