Fix: suppress ONNX Runtime stderr warnings on macOS

This commit is contained in:
Olow304
2026-01-27 09:03:19 -05:00
parent f24b90db5d
commit 87c1343f4d
5 changed files with 325349 additions and 0 deletions
+4
View File
@@ -57,6 +57,10 @@ fs-err = "3.2"
atomic-write-file = "0.3"
dirs-next = "2.0"
# Platform-specific: libc for stderr suppression on macOS
[target.'cfg(target_os = "macos")'.dependencies]
libc = "0.2"
smallvec = { version = "1.13", features = ["serde", "union", "const_generics", "write"] }
tantivy = { version = "0.25.0", optional = true, default-features = false, features = ["mmap"] }
ort = { version = "=2.0.0-rc.10", optional = true }
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+62
View File
@@ -30,6 +30,58 @@ use std::time::Duration;
use crate::{MemvidError, Result, types::FrameId};
// ============================================================================
// Stderr Suppression for macOS
// ============================================================================
// ONNX Runtime on macOS emits "Context leak detected, msgtracer returned -1"
// warnings from Apple's tracing infrastructure. These are harmless but noisy.
#[cfg(all(feature = "clip", target_os = "macos"))]
mod stderr_suppress {
use std::os::unix::io::{AsRawFd, RawFd};
use std::fs::File;
use std::io;
pub struct StderrSuppressor {
original_stderr: RawFd,
#[allow(dead_code)]
dev_null: File,
}
impl StderrSuppressor {
pub fn new() -> io::Result<Self> {
let dev_null = File::open("/dev/null")?;
let original_stderr = unsafe { libc::dup(2) };
if original_stderr == -1 {
return Err(io::Error::last_os_error());
}
let result = unsafe { libc::dup2(dev_null.as_raw_fd(), 2) };
if result == -1 {
unsafe { libc::close(original_stderr) };
return Err(io::Error::last_os_error());
}
Ok(Self { original_stderr, dev_null })
}
}
impl Drop for StderrSuppressor {
fn drop(&mut self) {
unsafe {
libc::dup2(self.original_stderr, 2);
libc::close(self.original_stderr);
}
}
}
}
#[cfg(all(feature = "clip", not(target_os = "macos")))]
mod stderr_suppress {
pub struct StderrSuppressor;
impl StderrSuppressor {
pub fn new() -> std::io::Result<Self> { Ok(Self) }
}
}
// ============================================================================
// Configuration Constants
// ============================================================================
@@ -680,6 +732,9 @@ mod model {
tracing::debug!(path = %vision_path.display(), "Loading CLIP vision model");
// Suppress stderr during ONNX session creation (macOS emits harmless warnings)
let _stderr_guard = stderr_suppress::StderrSuppressor::new().ok();
let session = Session::builder()
.map_err(|e| ClipError::InferenceError {
cause: e.to_string(),
@@ -697,6 +752,8 @@ mod model {
cause: format!("Failed to load vision model: {}", e),
})?;
// _stderr_guard dropped here, restoring stderr
*session_guard = Some(session);
tracing::info!(model = %self.model_info.name, "CLIP vision model loaded");
@@ -718,6 +775,9 @@ mod model {
tracing::debug!(path = %text_path.display(), "Loading CLIP text model");
// Suppress stderr during ONNX session creation (macOS emits harmless warnings)
let _stderr_guard = stderr_suppress::StderrSuppressor::new().ok();
let session = Session::builder()
.map_err(|e| ClipError::InferenceError {
cause: e.to_string(),
@@ -735,6 +795,8 @@ mod model {
cause: format!("Failed to load text model: {}", e),
})?;
// _stderr_guard dropped here, restoring stderr
*session_guard = Some(session);
tracing::info!(model = %self.model_info.name, "CLIP text model loaded");
+107
View File
@@ -39,6 +39,98 @@ use tokenizers::{
PaddingDirection, PaddingParams, PaddingStrategy, TruncationDirection, TruncationStrategy,
};
// ============================================================================
// Stderr Suppression for macOS
// ============================================================================
// ONNX Runtime on macOS emits "Context leak detected, msgtracer returned -1"
// warnings from Apple's tracing infrastructure. These are harmless but noisy.
// We suppress stderr during model loading to avoid these warnings.
#[cfg(target_os = "macos")]
mod stderr_suppress {
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::fs::File;
use std::io;
pub struct StderrSuppressor {
original_stderr: RawFd,
dev_null: File,
}
impl StderrSuppressor {
pub fn new() -> io::Result<Self> {
// Open /dev/null
let dev_null = File::open("/dev/null")?;
// Duplicate stderr to save it
let original_stderr = unsafe { libc::dup(2) };
if original_stderr == -1 {
return Err(io::Error::last_os_error());
}
// Redirect stderr to /dev/null
let result = unsafe { libc::dup2(dev_null.as_raw_fd(), 2) };
if result == -1 {
unsafe { libc::close(original_stderr) };
return Err(io::Error::last_os_error());
}
Ok(Self {
original_stderr,
dev_null,
})
}
}
impl Drop for StderrSuppressor {
fn drop(&mut self) {
// Restore original stderr
unsafe {
libc::dup2(self.original_stderr, 2);
libc::close(self.original_stderr);
}
// dev_null is closed automatically when dropped
let _ = &self.dev_null;
}
}
}
#[cfg(not(target_os = "macos"))]
mod stderr_suppress {
pub struct StderrSuppressor;
impl StderrSuppressor {
pub fn new() -> std::io::Result<Self> {
Ok(Self)
}
}
}
// ============================================================================
// Global ONNX Runtime Initialization (with stderr suppression on macOS)
// ============================================================================
// ONNX Runtime's global environment is lazily initialized on first session creation.
// On macOS, this triggers "Context leak detected, msgtracer returned -1" warnings
// from Apple's tracing infrastructure. We initialize early with stderr suppressed.
use once_cell::sync::Lazy;
static ORT_INIT: Lazy<()> = Lazy::new(|| {
// Suppress stderr during ONNX Runtime initialization on macOS
let _stderr_guard = stderr_suppress::StderrSuppressor::new().ok();
// Force ONNX Runtime initialization by creating a minimal session builder
// This triggers the global environment init which emits the warnings
let _ = Session::builder();
tracing::debug!("ONNX Runtime global environment initialized");
});
/// Ensure ONNX Runtime is initialized (call this before any ONNX operations)
fn ensure_ort_init() {
Lazy::force(&ORT_INIT);
}
// ============================================================================
// Configuration Constants
// ============================================================================
@@ -413,6 +505,9 @@ impl LocalTextEmbedder {
/// Load ONNX session lazily
fn load_session(&self) -> Result<()> {
// Ensure ONNX Runtime is initialized (with stderr suppressed on macOS)
ensure_ort_init();
let mut session_guard = self
.session
.lock()
@@ -426,6 +521,9 @@ impl LocalTextEmbedder {
tracing::debug!(path = %model_path.display(), "Loading text embedding model");
// Suppress stderr during ONNX session creation (macOS emits harmless warnings)
let _stderr_guard = stderr_suppress::StderrSuppressor::new().ok();
let session = Session::builder()
.map_err(|e| MemvidError::EmbeddingFailed {
reason: format!("Failed to create session builder: {}", e).into(),
@@ -443,6 +541,8 @@ impl LocalTextEmbedder {
reason: format!("Failed to load text embedding model: {}", e).into(),
})?;
// _stderr_guard is dropped here, restoring stderr
*session_guard = Some(session);
tracing::info!(model = %self.model_info.name, "Text embedding model loaded");
@@ -519,6 +619,10 @@ impl LocalTextEmbedder {
}
// 2. Cache miss - generate embedding normally
// Suppress stderr during model loading (macOS emits harmless "Context leak detected" warnings)
// This must be set before load_session() to catch ONNX Runtime's global initialization
let _stderr_guard = stderr_suppress::StderrSuppressor::new().ok();
// Ensure session and tokenizer are loaded
self.load_session()?;
self.load_tokenizer()?;
@@ -614,6 +718,9 @@ impl LocalTextEmbedder {
reason: format!("Failed to create token_type_ids tensor: {}", e).into(),
})?;
// Suppress stderr during inference (macOS emits harmless "Context leak detected" warnings)
let _stderr_guard = stderr_suppress::StderrSuppressor::new().ok();
// Build inputs based on what the model expects
let outputs = if input_names.len() >= 3 {
// Full BERT model with token_type_ids