Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2114d35
chore(hrx): regenerate Linux engines against HRX 2026.09.02
Abhishek-Varma Sep 7, 2026
f992c33
chore(hrx): regenerate Windows engine dll/lib against HRX 2026.09.02
Abhishek-Varma Sep 7, 2026
e44d82e
fix(hrx): share buffer ownership so HRX engines match IRON ABI
Abhishek-Varma Sep 7, 2026
0e4f36e
fix(hy-mt2): emit Model RAW Output so qualify sees responses
Abhishek-Varma Sep 7, 2026
0aed28f
fix(hy-mt2): gate Model RAW Output on FLM_LOG_RAW_OUTPUT
Abhishek-Varma Sep 7, 2026
561e6cc
chore(hrx): refresh Windows engine dll/lib (HRX 2026.09.02) after reb…
Abhishek-Varma Sep 9, 2026
7f1606a
chore(hrx): rebuild Linux engines from IRON fix/hrx-prefill-use-flm-rt
Abhishek-Varma Sep 9, 2026
6fe5ec3
chore(hrx): refresh Windows engines against flm-hrx-amdxdna-v2026.09.09
Abhishek-Varma Sep 9, 2026
250b5e6
chore(hrx): rebuild Linux engines against flm-hrx-amdxdna-v2026.09.09
Abhishek-Varma Sep 9, 2026
494bd10
fix(hrx): reference-count executables to free NPU contexts on model u…
Abhishek-Varma Sep 11, 2026
f356840
chore(hrx): rebuild Linux engines from IRON reference-count executabl…
Abhishek-Varma Sep 11, 2026
2f561fb
chore(hrx): bump public package to v2026.09.14 and refresh Windows en…
Abhishek-Varma Sep 14, 2026
3c60efc
chore(hrx): rebuild Linux engines against flm-hrx-amdxdna-v2026.09.14
Abhishek-Varma Sep 14, 2026
1470ec4
chore(hrx): update release pin to v2026.09.15
jtuyls Sep 15, 2026
e831f5a
ci: avoid future mtimes in HRX release extraction
jtuyls Sep 15, 2026
0630fb8
ci: gate optional flash engines by backend libs
jtuyls Sep 15, 2026
92c3600
feat(hrx): regenerate engine libs against HRX v2026.09.15 and enable …
Abhishek-Varma Sep 16, 2026
7d8829e
fix(hrx): ship optimize_qwen3 base engine libs so qwen3vl_flash MHA a…
Abhishek-Varma Sep 16, 2026
15bc9b2
refactor(hrx): remove FLM_HAS_*_FLASH gates; flash engines always com…
Abhishek-Varma Sep 16, 2026
1b26c2c
fix(hrx): regenerate all engine libs from optimize_qwen3 (28c78fc5) a…
Abhishek-Varma Sep 16, 2026
472c9f6
fix(hrx): ship the working flash-compatible base+flash engine libs
Abhishek-Varma Sep 16, 2026
74f59f5
chore(hrx): regenerate all Windows HRX engines vs main + HRX v2026.09.15
Abhishek-Varma Sep 21, 2026
7ce8710
chore(hrx): regenerate all Linux HRX engines vs main + HRX v2026.09.15
Abhishek-Varma Sep 21, 2026
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: 7 additions & 4 deletions hrx-integration/fetch-hrx-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,18 @@ actual_sha="$(sha256sum "$tarball" | awk '{print $1}')"
# Public package ships as .tar.zst (fall back to gzip for legacy assets).
# Decompress zstd via the standalone binary piped into tar, so extraction does
# not depend on tar being built with its zstd plugin, and fail with a clear
# message when the zstd package is not installed.
# message when the zstd package is not installed. Do not preserve archive mtimes:
# some HRX archives can carry future-dated entries, and CMake records imported
# package configs as regeneration inputs. Future config mtimes make Ninja rerun
# CMake until it aborts with "build.ninja still dirty after 100 tries".
case "$HRX_RELEASE_ASSET" in
*.tar.zst)
command -v zstd >/dev/null 2>&1 ||
die "zstd is required to extract $HRX_RELEASE_ASSET but was not found on PATH (install the 'zstd' package)"
zstd -dc "$tarball" | tar -C "$out_dir" -xf -
zstd -dc "$tarball" | tar -m -C "$out_dir" -xf -
;;
*.tar.gz|*.tgz) tar -C "$out_dir" -xzf "$tarball" ;;
*) tar -C "$out_dir" -xf "$tarball" ;;
*.tar.gz|*.tgz) tar -m -C "$out_dir" -xzf "$tarball" ;;
*) tar -m -C "$out_dir" -xf "$tarball" ;;
esac

# Locate the HRX CMake package config; its dir feeds find_package(hrx CONFIG).
Expand Down
10 changes: 5 additions & 5 deletions hrx-integration/hrx-release.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

# Pinned HRX (amdxdna) release consumed by the HRX runtime path.
HRX_RELEASE_REPO="jtuyls/hrx"
HRX_RELEASE_TAG="flm-hrx-amdxdna-v2026.07.30"
HRX_RELEASE_TAG="flm-hrx-amdxdna-v2026.09.15"
# For Linux.
HRX_RELEASE_ASSET="hrx-amdxdna-2026.07.30-amdxdna-hal-native-rel-eb0b39f-linux-x86_64.tar.zst"
HRX_RELEASE_SHA256="661ed94051cc6ad04f53739b2df7a791aecb658bc435bd5a6ff3c46716696345"
HRX_RELEASE_ASSET="hrx-amdxdna-2026.09.15-amdxdna-hal-native-rel-c023c3e-linux-x86_64.tar.zst"
HRX_RELEASE_SHA256="0a3437af76f6e2b5dcf0df52f26505c9f318d583328fd141c7f377170d14fe5b"
# For Windows.
HRX_RELEASE_ASSET_WINDOWS="hrx-amdxdna-2026.07.30-amdxdna-hal-native-rel-eb0b39f-windows-x86_64.zip"
HRX_RELEASE_SHA256_WINDOWS="b3af74c9b393ce49ef71a3cbec2cbe92be6d40601858b41009d2bda57eadeb43"
HRX_RELEASE_ASSET_WINDOWS="hrx-amdxdna-2026.09.15-amdxdna-hal-native-rel-c023c3e-windows-x86_64.zip"
HRX_RELEASE_SHA256_WINDOWS="be7d3bc882b61234776be35aa98ee6cd0d1822e8281f64885472eed888170105"
24 changes: 20 additions & 4 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ endif()
# and HRX-built .so/.dll/.lib never collide (see src/lib/xrt and src/lib/hrx).
set(FLM_ENGINE_LIB_DIR "${CMAKE_SOURCE_DIR}/lib/${FLM_RUNTIME_NAME}")

# The flash engine libs (qwen3vl_flash, gemma4e_flash) are always shipped in
# src/lib/${FLM_RUNTIME_NAME} for every backend, so their model families are
# always compiled in -- no probe/gate/macro needed.

# ———————————————————————————————————————————————
# NPU runtime discovery.
# HRX: consumed from its public CMake package via find_package(hrx).
Expand Down Expand Up @@ -403,22 +407,29 @@ if(MSVC)
target_link_libraries(flm PUBLIC ${STATIC_LIBS})
endif()

# Link your custom libraries (these may still be DLLs if no static versions available)
target_link_libraries(flm PUBLIC
set(FLM_ENGINE_LINK_LIBS
q4_npu_eXpress
llama_npu
qwen2_npu
qwen2vl_npu
qwen3_npu
qwen3vl_npu
qwen3vl_flash
)

list(APPEND FLM_ENGINE_LINK_LIBS qwen3vl_flash)

list(APPEND FLM_ENGINE_LINK_LIBS
qwen3_5vl_npu
qwen3_5_omni_npu
qwen3_6_moe_npu
gemma_npu
gemma_text_npu
gemma4e_npu
gemma4e_flash
)

list(APPEND FLM_ENGINE_LINK_LIBS gemma4e_flash)

list(APPEND FLM_ENGINE_LINK_LIBS
gemma4_12b_npu
gpt_oss_npu
whisper_npu
Expand All @@ -427,6 +438,11 @@ target_link_libraries(flm PUBLIC
phi4_npu
nanbeige_npu
hunyuan_npu
)

# Link your custom libraries (these may still be DLLs if no static versions available)
target_link_libraries(flm PUBLIC
${FLM_ENGINE_LINK_LIBS}
# flm's own code calls nothing in the four shared-runtime libs below -- the
# engine .so above do -- so the linker's default --as-needed drops them from
# DT_NEEDED entirely. The engines then have to find MHA/Dequant/... in some
Expand Down
2 changes: 1 addition & 1 deletion src/common/AutoModel/modeling_gemma4e.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1412,4 +1412,4 @@ StreamResult Gemma4e::parse_stream_content_impl(const std::string content, bool

result.type = current_mode_;
return result;
}
}
9 changes: 6 additions & 3 deletions src/common/AutoModel/modeling_hunyuan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@
/************ hunyuan-dense family **************/
Hunyuan::Hunyuan(flm_rt::device* npu_device_inst) : AutoModel(npu_device_inst, "Hunyuan") {
this->single_turn = true;
// the translator emits one short line per turn and the caller already has it
// from the stream / return value, so the raw dump would only double the log
this->log_raw_output = false;
// The translator streams one short line per turn, so echoing the
// "Model RAW Output:" dump only doubles the interactive log; keep it off by
// default. Diagnostics (qualification, numerical-match) anchor per-turn
// parsing on that marker, so FLM_LOG_RAW_OUTPUT=1 forces it back on for them
// without changing the interactive default.
this->log_raw_output = env_forces_raw_output();
// every turn either rewinds to the pinned prefix or clears, so the kv state
// the trailing eos forward exists to preserve is discarded either way
this->forward_on_eos = false;
Expand Down
8 changes: 4 additions & 4 deletions src/common/AutoModel/modeling_qwen3vl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ void Qwen3VL::create_engine() {
this->lm_engine = std::make_unique<qwen3vl_npu>(*this->lm_config, this->npu.get(), this->MAX_L);
}

void Qwen3VL_Flash::create_engine() {
this->lm_engine = std::make_unique<qwen3vl_flash>(*this->lm_config, this->npu.get(), this->MAX_L);
}

void Qwen3VL::load_model(std::string model_path, json model_info, int default_context_length, bool enable_preemption) {
this->_shared_load_model(model_path, model_info, default_context_length, enable_preemption);

Expand Down Expand Up @@ -430,6 +426,10 @@ StreamResult Qwen3VL::parse_stream_content(const std::string content) {

/************ Qwen3VL_Flash **************/

void Qwen3VL_Flash::create_engine() {
this->lm_engine = std::make_unique<qwen3vl_flash>(*this->lm_config, this->npu.get(), this->MAX_L);
}

int Qwen3VL_Flash::_pin_system_prefix(const std::string& system_text) {
// Full clear — drop any previous pin before building the new one.
this->lm_engine->clear_context();
Expand Down
15 changes: 14 additions & 1 deletion src/include/AutoModel/automodel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
#include <string>
#include <type_traits>
#include <any>
#include <cstdlib>
#include <cstring>
#include "typedef.hpp"
#include "causal_lm.hpp"
#include "lm_config.hpp"

#include "models/llama/llama_npu.hpp"
#include "models/qwen2/qwen2_npu.hpp"
#include "models/qwen3/qwen3_npu.hpp"
Expand Down Expand Up @@ -162,8 +165,18 @@ class AutoModel {
std::vector<int> checkpoint_his;
/// \brief dump the undecorated model output to stdout once a turn ends
/// \note on by default; models whose turns are short and driven in bulk (the
/// hunyuan translator) turn it off so the log is not doubled.
/// hunyuan translator) turn it off so the log is not doubled. Those
/// models should seed this from env_forces_raw_output() so diagnostics
/// can opt back in without changing the interactive default.
bool log_raw_output = true;
/// \brief whether FLM_LOG_RAW_OUTPUT forces the "Model RAW Output:" dump on
/// \note the qualification harness and numerical-match anchor per-turn parsing
/// on that marker, so they set FLM_LOG_RAW_OUTPUT=1 to re-enable it for
/// models that quiet it by default; unset/empty/"0" leave the default.
static bool env_forces_raw_output() {
const char* value = std::getenv("FLM_LOG_RAW_OUTPUT");
return value != nullptr && value[0] != '\0' && std::strcmp(value, "0") != 0;
}
/// \brief run one more forward on the eos token once a turn ends
/// \note this keeps the kv cache aligned with token_history so a following
/// turn can append to it. Models that rewind or clear between turns
Expand Down
2 changes: 1 addition & 1 deletion src/include/AutoModel/modeling_qwen3vl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,4 @@ class Qwen3VL_Thinking : public Qwen3VL {
}
std::string generate(chat_meta_info_t& meta_info, int length_limit, std::ostream& os, std::function<bool()> is_cancelled = [] { return false; }) override;
std::string generate_with_prompt(chat_meta_info_t& meta_info, lm_uniform_input_t& input, int length_limit, std::ostream& os = std::cout) override;
};
};
47 changes: 46 additions & 1 deletion src/include/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
Expand All @@ -30,15 +31,25 @@
/// \note A copy (or mapping) does not duplicate the underlying memory; it only maps the pointer.
class bytes {
protected:
// HRX engines (IRON) use shared_ptr so copies keep the BO mapped. Unique_ptr
// copies drop ownership and leave data_ dangling across the .so boundary.
#if defined(FLM_USE_HRX)
std::shared_ptr<uint8_t[]> owned_data_;
#else
std::unique_ptr<uint8_t[]> owned_data_;
#endif
uint8_t* data_;
size_t size_;
bool is_owner_;
#ifdef FLM_DEVICE_BUFFER
bool is_bo_owner_;
flm_rt::bo* bo_;
#if defined(FLM_USE_HRX)
std::shared_ptr<flm_rt::bo> owned_bo_;
#else
std::unique_ptr<flm_rt::bo> owned_bo_;
#endif
#endif

public:
/// \brief constructor
Expand All @@ -52,11 +63,19 @@ class bytes {

/// \brief copy constructor
/// \param other the other bytes
#if defined(FLM_USE_HRX)
bytes(const bytes& other) : owned_data_(other.owned_data_), data_(other.data_), size_(other.size_), is_owner_(other.is_owner_)
#ifdef FLM_DEVICE_BUFFER
, is_bo_owner_(other.is_bo_owner_), bo_(other.bo_), owned_bo_(other.owned_bo_)
#endif
{}
#else
bytes(const bytes& other) : owned_data_(nullptr), data_(other.data_), size_(other.size_), is_owner_(false)
#ifdef FLM_DEVICE_BUFFER
, is_bo_owner_(false), bo_(other.bo_), owned_bo_(nullptr)
#endif
{}
#endif

/// \brief move constructor
/// \param other the other bytes
Expand Down Expand Up @@ -86,7 +105,11 @@ class bytes {
{
if (size > 0 && size < 8ull * 1024 * 1024 * 1024){
try {
#if defined(FLM_USE_HRX)
owned_data_ = std::shared_ptr<uint8_t[]>(new uint8_t[size]());
#else
owned_data_ = std::make_unique<uint8_t[]>(size);
#endif
}
catch (const std::bad_alloc& e) {
throw std::runtime_error(std::string("Failed to allocate bytes of size ") + std::to_string(size) + ": " + e.what());
Expand Down Expand Up @@ -128,10 +151,14 @@ class bytes {
throw std::runtime_error("Invalid size for bytes allocation");
}
size_t alignment = 1024 * 1024;
int padded_size = (size + alignment - 1) / alignment * alignment; // 1MB alignment
size_t padded_size = (size + alignment - 1) / alignment * alignment; // 1MB alignment

try {
#if defined(FLM_USE_HRX)
owned_bo_ = std::make_shared<flm_rt::ext::bo>(device, padded_size);
#else
owned_bo_ = std::make_unique<flm_rt::ext::bo>(device, padded_size);
#endif
}
catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to allocate flm_rt::ext::bo: ") + e.what());
Expand Down Expand Up @@ -169,6 +196,17 @@ class bytes {
/// \param other the other bytes
bytes& operator=(const bytes& other) {
if (this != &other) {
#if defined(FLM_USE_HRX)
owned_data_ = other.owned_data_;
data_ = other.data_;
size_ = other.size_;
is_owner_ = other.is_owner_;
#ifdef FLM_DEVICE_BUFFER
owned_bo_ = other.owned_bo_;
is_bo_owner_ = other.is_bo_owner_;
bo_ = other.bo_;
#endif
#else
if (is_owner_){
owned_data_.reset();
}
Expand All @@ -181,6 +219,7 @@ class bytes {
}
is_bo_owner_ = false;
bo_ = other.bo_;
#endif
#endif
}
return *this;
Expand Down Expand Up @@ -257,7 +296,11 @@ class bytes {
throw std::runtime_error("Cannot resize to zero size");
}
try {
#if defined(FLM_USE_HRX)
owned_data_.reset(new uint8_t[new_size]());
#else
owned_data_.reset(new uint8_t[new_size]);
#endif
}
catch (const std::bad_alloc& e) {
throw std::runtime_error(std::string("Failed to allocate bytes of size ") + std::to_string(new_size) + ": " + e.what());
Expand Down Expand Up @@ -302,6 +345,8 @@ class bytes {
/// \return the is bo owner
bool is_bo_owner() const { return is_bo_owner_; }

bool has_bo() const { return bo_ != nullptr; }

/// \brief sync to device (host writes -> device)
#if defined(FLM_USE_HRX)
void sync_to_device() { assert(bo_); bo_->flush(); }
Expand Down
Loading
Loading