Skip to content
Merged
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
6 changes: 3 additions & 3 deletions src/a2a3/platform/onboard/host/device_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) {
// Latch this run's diagnostic enables onto the runner before the collector
// paths below read them; block_dim/aicpu_thread_num are consumed locally.
apply_call_config(config);
// prepare_launch_shape() resolved block_dim before the graph was built, so
// the geometry this run launches with is already on the runner.
// activate_launch_shape() latches this run's geometry onto the runner on the
// executor thread immediately before run(), so block_dim_ is this run's.
const int block_dim = block_dim_;
int launch_aicpu_num = config.aicpu_thread_num;
// A prior AICore launch/sync error poisoned the device context and the
Expand Down Expand Up @@ -291,7 +291,7 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) {
ensure_device_wall_buffer();

if (block_dim < 1) {
LOG_ERROR("run() reached with unresolved block_dim; prepare_launch_shape must run first");
LOG_ERROR("run() reached with unresolved block_dim; activate_launch_shape must run first");
return -1;
}
int num_aicore = block_dim * cores_per_blockdim_;
Expand Down
6 changes: 3 additions & 3 deletions src/a5/platform/onboard/host/device_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) {
// Latch this run's diagnostic enables onto the runner before the collector
// paths below read them; block_dim/aicpu_thread_num are consumed locally.
apply_call_config(config);
// prepare_launch_shape() resolved block_dim before the graph was built, so
// the geometry this run launches with is already on the runner.
// activate_launch_shape() latches this run's geometry onto the runner on the
// executor thread immediately before run(), so block_dim_ is this run's.
const int block_dim = block_dim_;
int launch_aicpu_num = config.aicpu_thread_num;
// A prior AICore launch/sync error poisoned the device context and the
Expand Down Expand Up @@ -175,7 +175,7 @@ int DeviceRunner::run(Runtime &runtime, const CallConfig &config) {
ensure_device_wall_buffer();

if (block_dim < 1) {
LOG_ERROR("run() reached with unresolved block_dim; prepare_launch_shape must run first");
LOG_ERROR("run() reached with unresolved block_dim; activate_launch_shape must run first");
return -1;
}
int num_aicore = block_dim * cores_per_blockdim_;
Expand Down
16 changes: 13 additions & 3 deletions src/common/platform/include/host/run_stream_slots.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#define SRC_COMMON_PLATFORM_INCLUDE_HOST_RUN_STREAM_SLOTS_H_

#include <array>
#include <atomic>
#include <cstddef>
#include <functional>

Expand All @@ -33,6 +34,15 @@
* than hand it a fresh stream beside a live one, and teardown needs the handle
* to retry. Stream creation and destruction are injected so this state machine
* is exercisable without a device.
*
* Threading: a `Slot` is touched only by the thread that owns that slot's run,
* and admission gives at most one owner per slot, so the per-slot handles need
* no synchronization. Two slots are therefore serviced concurrently — a native
* prepare acquires the successor's slot while the executor retires the
* predecessor's. `created_count_` is the one field shared across those owners
* and is additionally readable from an unrelated thread through
* `get_run_stream_set_create_count`, so it is atomic. `destroy_all()` walks
* every slot and requires all runs to be quiesced.
*/
class RunStreamSlots {
public:
Expand Down Expand Up @@ -64,7 +74,7 @@ class RunStreamSlots {
s.aicore = nullptr;
return rc;
}
++created_count_;
created_count_.fetch_add(1, std::memory_order_relaxed);
return 0;
}

Expand Down Expand Up @@ -99,7 +109,7 @@ class RunStreamSlots {
void *aicpu(unsigned slot) const { return slot < slots_.size() ? slots_[slot].aicpu : nullptr; }
void *aicore(unsigned slot) const { return slot < slots_.size() ? slots_[slot].aicore : nullptr; }
bool ready(unsigned slot) const { return aicpu(slot) != nullptr && aicore(slot) != nullptr; }
size_t created_count() const { return created_count_; }
size_t created_count() const { return created_count_.load(std::memory_order_relaxed); }
static constexpr size_t capacity() { return PTO_PIPELINE_MAX_DEPTH; }

private:
Expand All @@ -111,7 +121,7 @@ class RunStreamSlots {
CreateFn create_;
DestroyFn destroy_;
std::array<Slot, PTO_PIPELINE_MAX_DEPTH> slots_{};
size_t created_count_{0};
std::atomic<size_t> created_count_{0};
};

#endif // SRC_COMMON_PLATFORM_INCLUDE_HOST_RUN_STREAM_SLOTS_H_
29 changes: 22 additions & 7 deletions src/common/platform/onboard/host/device_runner_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,30 @@ void create_run_selection_key() {
g_run_selection_key_error = pthread_key_create(&g_run_selection_key, std::free);
}

DeviceRunnerBase::NativeRunThreadSelection &run_selection() {
/** This thread's selection storage, or nullptr when it cannot be installed. */
NativeRunThreadSelection *try_run_selection() noexcept {
int once_rc = pthread_once(&g_run_selection_once, create_run_selection_key);
if (once_rc != 0 || g_run_selection_key_error != 0) {
throw std::runtime_error("failed to create native-run pthread TLS key");
}
if (once_rc != 0 || g_run_selection_key_error != 0) return nullptr;
auto *selection = static_cast<NativeRunThreadSelection *>(pthread_getspecific(g_run_selection_key));
if (selection == nullptr) {
void *storage = std::malloc(sizeof(NativeRunThreadSelection));
if (storage == nullptr) throw std::bad_alloc();
if (storage == nullptr) return nullptr;
selection = new (storage) NativeRunThreadSelection{};
int set_rc = pthread_setspecific(g_run_selection_key, selection);
if (set_rc != 0) {
selection->~NativeRunThreadSelection();
std::free(storage);
throw std::runtime_error("failed to install native-run pthread TLS state");
return nullptr;
}
}
return selection;
}

DeviceRunnerBase::NativeRunThreadSelection &run_selection() {
NativeRunThreadSelection *selection = try_run_selection();
if (selection == nullptr) {
throw std::runtime_error("failed to install native-run pthread TLS state");
}
return *selection;
}

Expand Down Expand Up @@ -196,7 +203,15 @@ DeviceRunnerBase::NativeRunThreadSelection DeviceRunnerBase::capture_native_run_
}

void DeviceRunnerBase::restore_native_run_thread_selection(const NativeRunThreadSelection &selection) noexcept {
run_selection() = selection;
NativeRunThreadSelection *target = try_run_selection();
if (target == nullptr) {
// Returning would leave this thread on the default slot and bank, so a
// run would address storage another run's lease owns. There is no
// caller-visible channel for the failure on a freshly started thread.
LOG_ERROR("native-run thread selection storage could not be installed");
std::abort();
}
*target = selection;
}

uint64_t DeviceRunnerBase::arena_bank_gm_heap_base(uint32_t bank_id) const {
Expand Down
6 changes: 6 additions & 0 deletions src/common/platform/onboard/host/device_runner_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ class DeviceRunnerBase {
uint32_t pipeline_slot() const;
uint32_t selected_arena_bank() const;
NativeRunThreadSelection capture_native_run_thread_selection() const;
/**
* Install `selection` on the calling thread. Aborts if the per-thread
* storage cannot be created: every caller either runs inside a scope guard
* or on a thread that has not started its run yet, so proceeding on the
* default slot and bank would silently address another lease's storage.
*/
void restore_native_run_thread_selection(const NativeRunThreadSelection &selection) noexcept;

/**
Expand Down
5 changes: 5 additions & 0 deletions src/common/platform/sim/host/c_api_shared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,11 @@ int set_task_accepted_state_ctx(DeviceContextHandle ctx, volatile int32_t *state
}
}

/**
* Simulation keeps no per-thread run selection, so the identity is carried only
* by the onboard runner's trace attributes and is discarded here. Accepting it
* keeps the pipeline symbol set uniform across every host runtime.
*/
int set_native_run_identity_ctx(DeviceContextHandle ctx, uint64_t, uint64_t, uint64_t, uint64_t) {
return ctx == NULL ? -1 : 0;
}
Expand Down
5 changes: 4 additions & 1 deletion src/common/worker/chip_worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ T load_symbol(void *handle, const char *name) {
msg += name;
msg += "': ";
msg += err;
msg += "; every host runtime built from this source tree exports it, so rebuild the runtime";
throw std::runtime_error(msg);
}
return reinterpret_cast<T>(sym);
Expand Down Expand Up @@ -668,7 +669,9 @@ ChipWorkerNativeRun ChipWorker::prepare_native_run_on_slot(
);
}
}
if (occupied != 0 && occupied != 1) {
// The loop above already rejected every predecessor that may not carry a
// successor, so more than one survivor means a successor is staged.
if (occupied > 1) {
throw std::runtime_error(
"prepare_native_run already owns a prepared successor " + format_native_run_identity(run_identity)
);
Expand Down
Loading