[0.0.2] OCR: run each CUDA engine once when it is made, as cuBLASLt 13.8 crashed after an engine destroyed unused

This commit is contained in:
Musa Mahmood 2026-10-08 00:22:12 +01:00
parent a254e7a3dc
commit fac42e3462
4 changed files with 27 additions and 2 deletions

View File

@ -29,7 +29,7 @@ APP_NAME :: "mcap";
APP_FOLDER_NAME :: "mcap"; APP_FOLDER_NAME :: "mcap";
GIT_BRANCH :: "check"; GIT_BRANCH :: "check";
GIT_HASH :: "-"; GIT_HASH :: "-";
VERSION :: "0.0.1"; VERSION :: "0.0.2";
BUILD_DATE :: "-"; BUILD_DATE :: "-";
DEBUG :: true; DEBUG :: true;
COMPILE_TESTS :: true; COMPILE_TESTS :: true;

View File

@ -8,7 +8,7 @@ APP_NAME :: "mcap";
APP_FOLDER_NAME :: "mcap"; APP_FOLDER_NAME :: "mcap";
APP_BUNDLE_IDENTIFIER :: "com.example.mcap"; APP_BUNDLE_IDENTIFIER :: "com.example.mcap";
VERSION :: "0.0.1"; VERSION :: "0.0.2";
// Where everything goes: bin/, or bin-headless/ for builds made with no_crash_dialog, so automated // Where everything goes: bin/, or bin-headless/ for builds made with no_crash_dialog, so automated
// builds never write over the ones you run by hand. // builds never write over the ones you run by hand.
build_directory := "bin"; build_directory := "bin";

View File

@ -117,6 +117,30 @@ ocr_release_sessions :: (engine: *Ocr_Engine) {
ocr_release_session(*engine.orientation); ocr_release_session(*engine.orientation);
} }
// Runs each of a CUDA engine's sessions once, on a small input, before it is used or destroyed.
// With cuBLASLt 13.8 (CUDA 13, onnxruntime 1.30.0, RTX 5080 laptop), the process's first CUDA
// engine destroyed without ever having run left the next engine to crash in cublasLtCtxInit, with a
// DEP access violation, on its first run; an engine that has run once leaves nothing broken. It also
// moves the first run's setup into creation. On failure, the reason.
ocr_warm_up :: (engine: *Ocr_Engine) -> ok: bool, error: string {
Warm_Up :: struct { session: *Ocr_Session; height, width: s64; }
runs := Warm_Up.[
.{*engine.det, 64, 64},
.{*engine.rec, engine.model.rec_height, engine.model.rec_height * 2},
.{*engine.orientation, engine.orientation_height, engine.orientation_width},
];
for runs {
if !it.session.session continue; // no orientation classifier
shape := s64.[1, 3, it.height, it.width];
input := NewArray(3 * it.height * it.width, float, initialized = true,, context.default_allocator);
defer array_free(input,, context.default_allocator);
out, ok, error := ocr_run(it.session, engine.memory_info, input, shape);
if !ok return false, tprint("The first run on the GPU failed: %", error);
ocr_release_output(*out);
}
return true, "";
}
// A session for the model file; with CUDA when gpu is set. On failure, the reason. // A session for the model file; with CUDA when gpu is set. On failure, the reason.
ocr_create_session :: (env: *OrtEnv, path: string, gpu: bool, intra_op_threads: s32, ocr_options: Ocr_Options) -> Ocr_Session, ok: bool, error: string { ocr_create_session :: (env: *OrtEnv, path: string, gpu: bool, intra_op_threads: s32, ocr_options: Ocr_Options) -> Ocr_Session, ok: bool, error: string {
result: Ocr_Session; result: Ocr_Session;

View File

@ -118,6 +118,7 @@ ocr_create :: (models_folder: string, model_name: string, prefer_gpu := true, op
// A few CPU threads prepare images and decode results while the GPU runs the networks. // A few CPU threads prepare images and decode results while the GPU runs the networks.
engine.workers = max(options.gpu_workers, 1); engine.workers = max(options.gpu_workers, 1);
sessions_ok, sessions_error := ocr_create_sessions(engine, models_folder, true, 2); sessions_ok, sessions_error := ocr_create_sessions(engine, models_folder, true, 2);
if sessions_ok sessions_ok, sessions_error = ocr_warm_up(engine);
if sessions_ok { if sessions_ok {
engine.provider = .CUDA; engine.provider = .CUDA;
engine.rec_batch = max(engine.model.rec_batch_gpu, 1); engine.rec_batch = max(engine.model.rec_batch_gpu, 1);