oar_ocr_core/core/config/parallel.rs
1//! Shared parallel processing configuration types.
2
3use serde::{Deserialize, Serialize};
4
5/// Centralized configuration for parallel processing behavior across the OCR pipeline.
6///
7/// This struct consolidates parallel processing configuration that was previously
8/// scattered across different components, providing a unified way to tune parallelism
9/// behavior throughout the OCR pipeline.
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ParallelPolicy {
12 /// Maximum number of threads to use for parallel processing.
13 /// If None, rayon will use the default thread pool size (typically number of CPU cores).
14 /// Default: None (use rayon's default)
15 #[serde(default)]
16 pub max_threads: Option<usize>,
17
18 /// Threshold for general utility operations like image loading (<= this uses sequential)
19 /// Default: 4 (matches DEFAULT_PARALLEL_THRESHOLD constant)
20 #[serde(default = "ParallelPolicy::default_utility_threshold")]
21 pub utility_threshold: usize,
22
23 /// Threshold for postprocessing operations based on pixel area (<= this uses sequential)
24 /// Default: 8000 (use sequential for regions with <= 8000 pixels, parallel for larger)
25 #[serde(default = "ParallelPolicy::default_postprocess_pixel_threshold")]
26 pub postprocess_pixel_threshold: usize,
27}
28
29impl ParallelPolicy {
30 /// Create a new ParallelPolicy with default values.
31 pub fn new() -> Self {
32 Self::default()
33 }
34
35 /// Set the maximum number of threads.
36 pub fn with_max_threads(mut self, max_threads: Option<usize>) -> Self {
37 self.max_threads = max_threads;
38 self
39 }
40
41 /// Set the postprocessing pixel threshold.
42 pub fn with_postprocess_pixel_threshold(mut self, threshold: usize) -> Self {
43 self.postprocess_pixel_threshold = threshold;
44 self
45 }
46
47 /// Set the utility operations threshold.
48 pub fn with_utility_threshold(mut self, threshold: usize) -> Self {
49 self.utility_threshold = threshold;
50 self
51 }
52
53 /// Install the global rayon thread pool with the configured number of threads.
54 ///
55 /// This method should be called once at application startup before any parallel
56 /// processing occurs. If `max_threads` is None, this method does nothing and
57 /// rayon will use its default thread pool size.
58 ///
59 /// # Returns
60 ///
61 /// - `Ok(true)` if the thread pool was successfully configured
62 /// - `Ok(false)` if `max_threads` is None (no configuration needed)
63 /// - `Err` if the thread pool has already been initialized
64 ///
65 /// # Example
66 ///
67 /// ```ignore
68 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
69 /// let policy = ParallelPolicy::new().with_max_threads(Some(4));
70 /// policy.install_global_thread_pool()?;
71 /// # Ok(())
72 /// # }
73 /// ```
74 pub fn install_global_thread_pool(&self) -> Result<bool, rayon::ThreadPoolBuildError> {
75 if let Some(num_threads) = self.max_threads {
76 rayon::ThreadPoolBuilder::new()
77 .num_threads(num_threads)
78 .build_global()?;
79 Ok(true)
80 } else {
81 Ok(false)
82 }
83 }
84
85 /// Default value for utility threshold.
86 fn default_utility_threshold() -> usize {
87 4 // Matches DEFAULT_PARALLEL_THRESHOLD from constants.
88 }
89
90 /// Default postprocessing pixel threshold.
91 fn default_postprocess_pixel_threshold() -> usize {
92 8_000
93 }
94}
95
96impl Default for ParallelPolicy {
97 fn default() -> Self {
98 Self {
99 max_threads: None,
100 utility_threshold: Self::default_utility_threshold(),
101 postprocess_pixel_threshold: Self::default_postprocess_pixel_threshold(),
102 }
103 }
104}