Fix: suppress ONNX Runtime stderr warnings on macOS
This commit is contained in:
@@ -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
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user