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
40 changes: 40 additions & 0 deletions pegainfer-qwen35/src/cublas_thread.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Bind the calling thread to a model's CUDA device/context and cuBLAS
//! handle; the guard destroys the handle when the binding ends.

use anyhow::Result;

use crate::weights::Qwen35Model;

pub(crate) struct CublasThreadGuard;

impl Drop for CublasThreadGuard {
fn drop(&mut self) {
unsafe {
crate::ffi::cublas_destroy();
}
}
}

/// Bind this thread to `model`'s device and context, then initialize cuBLAS.
/// `role` names the thread kind in failure messages ("scheduler", "TP worker");
/// every thread that runs model work must hold the returned guard.
pub(crate) fn bind_model_thread(model: &Qwen35Model, role: &str) -> Result<CublasThreadGuard> {
let ctx = model.device_ctx();
unsafe {
let err = crate::ffi::cuda_set_device(ctx.device_ordinal as i32);
if err != 0 {
return Err(anyhow::anyhow!(
"Failed to set CUDA device {} on Qwen3.5 {role} thread: cudaError={}",
ctx.device_ordinal,
err
));
}
}
ctx.ctx.bind_to_thread().map_err(|e| {
anyhow::anyhow!("Failed to bind CUDA context to Qwen3.5 {role} thread: {e}")
})?;
unsafe {
crate::ffi::cublas_init();
}
Ok(CublasThreadGuard)
}
1 change: 1 addition & 0 deletions pegainfer-qwen35/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
mod batch_decode;
pub(crate) mod batch_decode_graph;
pub(crate) mod config;
mod cublas_thread;
mod decode_buffers;
mod executor;
mod ffi;
Expand Down
66 changes: 20 additions & 46 deletions pegainfer-qwen35/src/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,20 +379,26 @@ pub(crate) fn start_with_capacity_and_policy(

let join_handle = thread::Builder::new()
.name("scheduler-qwen35".into())
.spawn(move || match bind_model_thread(backend.model()) {
Ok(_guard) => {
let _ = startup_tx.send(Ok(()));
scheduler_loop(
SchedulerBackend::Single(backend),
submit_rx,
seed,
max_prefill_tokens,
scheduler_policy,
load_tx,
);
}
Err(err) => {
let _ = startup_tx.send(Err(err));
.spawn(move || {
match crate::cublas_thread::bind_model_thread(backend.model(), "scheduler") {
Ok(_guard) => {
if let Err(err) = backend.model().tune_decode_gemm_algos() {
let _ = startup_tx.send(Err(err));
return;
}
let _ = startup_tx.send(Ok(()));
scheduler_loop(
SchedulerBackend::Single(backend),
submit_rx,
seed,
max_prefill_tokens,
scheduler_policy,
load_tx,
);
}
Err(err) => {
let _ = startup_tx.send(Err(err));
}
}
})
.expect("failed to spawn Qwen3.5 scheduler thread");
Expand Down Expand Up @@ -491,38 +497,6 @@ fn servable_len(max_context: usize, max_pages: usize, page_size: usize) -> u32 {
.unwrap_or(u32::MAX)
}

struct CublasThreadGuard;

impl Drop for CublasThreadGuard {
fn drop(&mut self) {
unsafe {
crate::ffi::cublas_destroy();
}
}
}

fn bind_model_thread(model: &Qwen35Model) -> Result<CublasThreadGuard> {
let ctx = model.device_ctx();
unsafe {
let err = crate::ffi::cuda_set_device(ctx.device_ordinal as i32);
if err != 0 {
return Err(anyhow::anyhow!(
"Failed to set CUDA device {} on Qwen3.5 scheduler thread: cudaError={}",
ctx.device_ordinal,
err
));
}
}
ctx.ctx.bind_to_thread().map_err(|e| {
anyhow::anyhow!("Failed to bind CUDA context to Qwen3.5 scheduler thread: {e}")
})?;
unsafe {
crate::ffi::cublas_init();
}
model.tune_decode_gemm_algos()?;
Ok(CublasThreadGuard)
}

// ── Main loop ───────────────────────────────────────────────────────────

fn publish_load(
Expand Down
Loading
Loading