Skip to content

Commit a6808a0

Browse files
committed
perf(oxfmt): Use AllocatorPool to reuse allocator between threads (#15412)
According to my local benchmark for the `outline` repo, it will be slightly better.
1 parent 57f0ce1 commit a6808a0

File tree

3 files changed

+22
-10
lines changed

3 files changed

+22
-10
lines changed

apps/oxfmt/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ path = "src/lib.rs"
2121
doctest = false
2222

2323
[dependencies]
24-
oxc_allocator = { workspace = true }
24+
oxc_allocator = { workspace = true, features = ["pool"] }
2525
oxc_diagnostics = { workspace = true }
2626
oxc_formatter = { workspace = true }
2727
oxc_parser = { workspace = true }

apps/oxfmt/src/format.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
time::Instant,
77
};
88

9+
use oxc_allocator::AllocatorPool;
910
use oxc_diagnostics::DiagnosticService;
1011
use oxc_formatter::Oxfmtrc;
1112

@@ -110,14 +111,21 @@ impl FormatRunner {
110111
print_and_flush_stdout(stdout, "Checking formatting...\n");
111112
}
112113

114+
let num_of_threads = rayon::current_num_threads();
115+
// Create allocator pool for reuse across parallel formatting tasks
116+
let allocator_pool = AllocatorPool::new(num_of_threads);
117+
113118
let output_options_clone = output_options.clone();
114119
#[cfg(feature = "napi")]
115120
let external_formatter_clone = self.external_formatter;
121+
116122
// Spawn a thread to run formatting service with streaming entries
117123
rayon::spawn(move || {
118-
let format_service = FormatService::new(cwd, output_options_clone, format_options);
124+
let format_service =
125+
FormatService::new(allocator_pool, cwd, output_options_clone, format_options);
119126
#[cfg(feature = "napi")]
120127
let format_service = format_service.with_external_formatter(external_formatter_clone);
128+
121129
format_service.run_streaming(rx_entry, &tx_error, tx_count);
122130
});
123131

@@ -127,12 +135,11 @@ impl FormatRunner {
127135
// Count the processed files
128136
let target_files_count = rx_count.iter().count();
129137
let print_stats = |stdout| {
138+
let elapsed_ms = start_time.elapsed().as_millis();
130139
print_and_flush_stdout(
131140
stdout,
132141
&format!(
133-
"Finished in {}ms on {target_files_count} files using {} threads.\n",
134-
start_time.elapsed().as_millis(),
135-
rayon::current_num_threads()
142+
"Finished in {elapsed_ms}ms on {target_files_count} files using {num_of_threads} threads.\n",
136143
),
137144
);
138145
};

apps/oxfmt/src/service.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ use std::{fs, path::Path, sync::mpsc, time::Instant};
33
use cow_utils::CowUtils;
44
use rayon::prelude::*;
55

6-
use oxc_allocator::Allocator;
6+
use oxc_allocator::AllocatorPool;
77
use oxc_diagnostics::{DiagnosticSender, DiagnosticService, OxcDiagnostic};
88
use oxc_formatter::{FormatOptions, Formatter, enable_jsx_source_type, get_parse_options};
99
use oxc_parser::Parser;
1010

1111
use crate::{command::OutputOptions, walk::WalkEntry};
1212

1313
pub struct FormatService {
14+
allocator_pool: AllocatorPool,
1415
cwd: Box<Path>,
1516
output_options: OutputOptions,
1617
format_options: FormatOptions,
@@ -19,11 +20,17 @@ pub struct FormatService {
1920
}
2021

2122
impl FormatService {
22-
pub fn new<T>(cwd: T, output_options: OutputOptions, format_options: FormatOptions) -> Self
23+
pub fn new<T>(
24+
allocator_pool: AllocatorPool,
25+
cwd: T,
26+
output_options: OutputOptions,
27+
format_options: FormatOptions,
28+
) -> Self
2329
where
2430
T: Into<Box<Path>>,
2531
{
2632
Self {
33+
allocator_pool,
2734
cwd: cwd.into(),
2835
output_options,
2936
format_options,
@@ -69,10 +76,8 @@ impl FormatService {
6976
let path = &entry.path;
7077
let source_type = enable_jsx_source_type(entry.source_type);
7178

72-
// TODO: Use `read_to_arena_str()` like `oxlint`?
79+
let allocator = self.allocator_pool.get();
7380
let source_text = fs::read_to_string(path).expect("Failed to read file");
74-
// TODO: Use `AllocatorPool.get()` like `oxlint`?
75-
let allocator = Allocator::new();
7681

7782
let ret = Parser::new(&allocator, &source_text, source_type)
7883
.with_options(get_parse_options())

0 commit comments

Comments
 (0)