From fac42e34629c5b13f48941ef6b4a5c95c92ab216 Mon Sep 17 00:00:00 2001 From: Musa Mahmood Date: Thu, 8 Oct 2026 00:22:12 +0100 Subject: [PATCH] [0.0.2] OCR: run each CUDA engine once when it is made, as cuBLASLt 13.8 crashed after an engine destroyed unused --- check_targets.jai | 2 +- first.jai | 2 +- modules/OCR/models.jai | 24 ++++++++++++++++++++++++ modules/OCR/module.jai | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/check_targets.jai b/check_targets.jai index 5f1229e..8e0f7b3 100644 --- a/check_targets.jai +++ b/check_targets.jai @@ -29,7 +29,7 @@ APP_NAME :: "mcap"; APP_FOLDER_NAME :: "mcap"; GIT_BRANCH :: "check"; GIT_HASH :: "-"; -VERSION :: "0.0.1"; +VERSION :: "0.0.2"; BUILD_DATE :: "-"; DEBUG :: true; COMPILE_TESTS :: true; diff --git a/first.jai b/first.jai index c864eac..c50da55 100644 --- a/first.jai +++ b/first.jai @@ -8,7 +8,7 @@ APP_NAME :: "mcap"; APP_FOLDER_NAME :: "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 // builds never write over the ones you run by hand. build_directory := "bin"; diff --git a/modules/OCR/models.jai b/modules/OCR/models.jai index feb2d52..9ab6db7 100644 --- a/modules/OCR/models.jai +++ b/modules/OCR/models.jai @@ -117,6 +117,30 @@ ocr_release_sessions :: (engine: *Ocr_Engine) { 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. 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; diff --git a/modules/OCR/module.jai b/modules/OCR/module.jai index 94d0b9b..549c0cd 100644 --- a/modules/OCR/module.jai +++ b/modules/OCR/module.jai @@ -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. engine.workers = max(options.gpu_workers, 1); 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 { engine.provider = .CUDA; engine.rec_batch = max(engine.model.rec_batch_gpu, 1);