Skip to content
Closed
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
177 changes: 162 additions & 15 deletions docs/paged_attention_engine.md

Large diffs are not rendered by default.

119 changes: 118 additions & 1 deletion src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Modifications Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
// Portions of this file consist of AI generated content.
#include "generators.h"
#include "models/model_state_manifest.h"
#include "models/model_type.h"
#include "runtime_settings.h"
#include "json.h"
Expand All @@ -13,6 +14,7 @@
#include <limits>
#include <cmath>
#include <stdexcept>
#include <utility>

namespace Generators {

Expand Down Expand Up @@ -497,6 +499,111 @@ struct SharedInitializers_Element : JSON::Element {
std::unique_ptr<SharedInitializer_Element> element_;
};

using DecoderStateGroup = Config::Model::Decoder::StateGroup;
using DecoderStateGroupKind = Config::Model::Decoder::StateGroupKind;

struct StateBinding_Element : JSON::Element {
explicit StateBinding_Element(Config::Model::Decoder::StateBinding& v) : v_{v} {}

void OnValue(std::string_view name, JSON::Value value) override {
if (name == "input") {
v_.input = JSON::Get<std::string_view>(value);
} else if (name == "output") {
v_.output = JSON::Get<std::string_view>(value);
} else {
throw JSON::unknown_value_error{};
}
}

private:
Config::Model::Decoder::StateBinding& v_;
};

struct StateBindings_Element : JSON::Element {
explicit StateBindings_Element(DecoderStateGroup& v) : v_{v} {}

Element& OnObject(std::string_view name) override {
std::optional<Config::Model::Decoder::StateBinding>* binding{};
std::unique_ptr<StateBinding_Element>* element{};
if (name == "key") {
binding = &v_.key;
element = &key_;
} else if (name == "value") {
binding = &v_.value;
element = &value_;
} else if (name == "state") {
binding = &v_.state;
element = &state_;
} else {
throw JSON::unknown_value_error{};
}

if (binding->has_value()) {
throw std::runtime_error("Duplicate decoder state binding semantic '" + std::string{name} + "'");
}
binding->emplace();
*element = std::make_unique<StateBinding_Element>(binding->value());
return **element;
}

private:
DecoderStateGroup& v_;
std::unique_ptr<StateBinding_Element> key_;
std::unique_ptr<StateBinding_Element> value_;
std::unique_ptr<StateBinding_Element> state_;
};

struct StateGroup_Element : JSON::Element {
explicit StateGroup_Element(DecoderStateGroup& v) : v_{v} {}

void OnValue(std::string_view name, JSON::Value value) override {
if (name != "kind") {
throw JSON::unknown_value_error{};
}
const auto kind = JSON::Get<std::string_view>(value);
if (kind == "paged_kv") {
v_.kind = DecoderStateGroupKind::PagedKeyValue;
} else if (kind == "fixed") {
v_.kind = DecoderStateGroupKind::Fixed;
} else {
throw std::runtime_error("Unsupported decoder state group kind '" + std::string{kind} + "'");
}
}

Element& OnObject(std::string_view name) override {
if (name == "bindings") {
return bindings_;
}
throw JSON::unknown_value_error{};
}

Element& OnArray(std::string_view name) override {
if (name == "layer_ids") {
return layer_ids_;
}
throw JSON::unknown_value_error{};
}

private:
DecoderStateGroup& v_;
IntArray_Element layer_ids_{v_.layer_ids};
StateBindings_Element bindings_{v_};
};

struct StateGroups_Element : JSON::Element {
explicit StateGroups_Element(std::vector<DecoderStateGroup>& v) : v_{v} {}

Element& OnObject(std::string_view /*name*/) override {
auto& group = v_.emplace_back();
current_ = std::make_unique<StateGroup_Element>(group);
return *current_;
}

private:
std::vector<DecoderStateGroup>& v_;
std::unique_ptr<StateGroup_Element> current_;
};

struct StringStringMap_Element : JSON::Element {
explicit StringStringMap_Element(std::unordered_map<std::string, std::string>& v) : v_{v} {}

Expand Down Expand Up @@ -738,6 +845,11 @@ struct Decoder_Element : JSON::Element {
if (name == "shared_initializers") {
return shared_initializers_;
}
if (name == "state_groups") {
v_.state_groups.emplace();
state_groups_ = std::make_unique<StateGroups_Element>(*v_.state_groups);
return *state_groups_;
}
throw JSON::unknown_value_error{};
}

Expand All @@ -752,6 +864,7 @@ struct Decoder_Element : JSON::Element {
std::unique_ptr<PipelineModelObject_Element> pipeline_object_; // object-style pipeline support
std::unique_ptr<StringArray_Element> layer_types_;
SharedInitializers_Element shared_initializers_{v_.shared_initializers};
std::unique_ptr<StateGroups_Element> state_groups_;
};

struct MtpInputs_Element : JSON::Element {
Expand Down Expand Up @@ -1995,9 +2108,12 @@ void ParseConfig(const fs::path& filename, std::string_view json_overlay, Config
}

void OverlayConfig(Config& config, std::string_view json) {
Root_Element root{config};
Config candidate{config};
Root_Element root{candidate};
RootObject_Element element{root};
JSON::Parse(element, json);
ModelStateManifest::ValidateConfig(candidate.model.decoder);
std::swap(config, candidate);
}

fs::path Config::ResolvePath(std::string_view value) const {
Expand Down Expand Up @@ -2094,6 +2210,7 @@ void ValidateModelPaths(const Config& config) {

Config::Config(const fs::path& path, std::string_view json_overlay) : config_path{path} {
ParseConfig(path / "genai_config.json", json_overlay, *this);
ModelStateManifest::ValidateConfig(model.decoder);

if (model.context_length == 0 && !ModelType::IsRNNT(model.type)) {
throw std::runtime_error("model context_length is 0 or was not set. It must be greater than 0");
Expand Down
22 changes: 22 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,28 @@ struct Config {
};
std::optional<SlidingWindow> sliding_window;

enum class StateGroupKind {
Invalid,
PagedKeyValue,
Fixed,
};

struct StateBinding {
std::string input;
std::string output;
};

struct StateGroup {
StateGroupKind kind{StateGroupKind::Invalid};
std::vector<int> layer_ids;
std::optional<StateBinding> key;
std::optional<StateBinding> value;
std::optional<StateBinding> state;
};

// Absence preserves the legacy dense, sequential paged-KV contract.
std::optional<std::vector<StateGroup>> state_groups;

struct Inputs {
std::string input_ids{Defaults::InputIdsName};
std::string embeddings{Defaults::InputsEmbedsName};
Expand Down
Loading