Scan a batch of files for class names in parallel and return a classmap. Uses [`std::thread::scope`] with one thread per CPU core. Small batches (≤ 4 files) are processed sequentially to avoid thread overhead.
(files: &[PathBuf])
| 436 | /// batches (≤ 4 files) are processed sequentially to avoid thread |
| 437 | /// overhead. |
| 438 | fn scan_files_parallel_classes(files: &[PathBuf]) -> HashMap<String, PathBuf> { |
| 439 | if files.is_empty() { |
| 440 | return HashMap::new(); |
| 441 | } |
| 442 | |
| 443 | // Small batches: sequential |
| 444 | if files.len() <= 4 { |
| 445 | let mut classmap = HashMap::new(); |
| 446 | for path in files { |
| 447 | if let Ok(content) = std::fs::read(path) { |
| 448 | for fqcn in scan_content(&content) { |
| 449 | classmap.entry(fqcn).or_insert_with(|| path.clone()); |
| 450 | } |
| 451 | } |
| 452 | } |
| 453 | return classmap; |
| 454 | } |
| 455 | |
| 456 | let n_threads = thread_count().min(files.len()); |
| 457 | let chunk_size = files.len().div_ceil(n_threads); |
| 458 | |
| 459 | let results: Vec<Vec<(String, PathBuf)>> = std::thread::scope(|s| { |
| 460 | let handles: Vec<_> = files |
| 461 | .chunks(chunk_size) |
| 462 | .map(|chunk| { |
| 463 | s.spawn(move || { |
| 464 | let mut local: Vec<(String, PathBuf)> = Vec::new(); |
| 465 | for path in chunk { |
| 466 | if let Ok(content) = std::fs::read(path) { |
| 467 | for fqcn in scan_content(&content) { |
| 468 | local.push((fqcn, path.clone())); |
| 469 | } |
| 470 | } |
| 471 | } |
| 472 | local |
| 473 | }) |
| 474 | }) |
| 475 | .collect(); |
| 476 | handles |
| 477 | .into_iter() |
| 478 | .map(|h| { |
| 479 | h.join().unwrap_or_else(|_| { |
| 480 | tracing::error!("PHPantom: thread panic in scan_files_parallel_classes"); |
| 481 | Vec::new() |
| 482 | }) |
| 483 | }) |
| 484 | .collect() |
| 485 | }); |
| 486 | |
| 487 | let total: usize = results.iter().map(|v| v.len()).sum(); |
| 488 | let mut classmap = HashMap::with_capacity(total); |
| 489 | for batch in results { |
| 490 | for (fqcn, path) in batch { |
| 491 | classmap.entry(fqcn).or_insert(path); |
| 492 | } |
| 493 | } |
| 494 | classmap |
| 495 | } |
no test coverage detected