Skip to content

Commit

Permalink
perf: mem cache for chunk render source (#8528)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahabhgk authored Nov 27, 2024
1 parent accbdfc commit 2edb6b4
Show file tree
Hide file tree
Showing 19 changed files with 386 additions and 377 deletions.
7 changes: 4 additions & 3 deletions crates/rspack_binding_values/src/compilation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,10 @@ impl JsCompilation {
) -> napi::Result<PathWithInfo> {
let compilation = self.as_ref()?;

let path_and_asset_info =
compilation.get_path_with_info(&filename.into(), data.to_path_data())?;
Ok(path_and_asset_info.into())
let mut asset_info = AssetInfo::default();
let path =
compilation.get_path_with_info(&filename.into(), data.to_path_data(), &mut asset_info)?;
Ok((path, asset_info).into())
}

#[napi]
Expand Down
8 changes: 8 additions & 0 deletions crates/rspack_core/src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use std::{fmt::Debug, hash::Hash};
use indexmap::IndexMap;
use itertools::Itertools;
use rspack_collections::{DatabaseItem, UkeyIndexMap, UkeyIndexSet, UkeyMap, UkeySet};
use rspack_error::Diagnostic;
use rspack_hash::{RspackHash, RspackHashDigest};
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet, FxHasher};

use crate::{
compare_chunk_group, merge_runtime, sort_group_by_index, ChunkGraph, ChunkGroupOrderKey,
RenderManifestEntry,
};
use crate::{ChunkGroupByUkey, ChunkGroupUkey, ChunkUkey, SourceType};
use crate::{Compilation, EntryOptions, Filename, ModuleGraph, RuntimeSpec};
Expand Down Expand Up @@ -42,6 +44,12 @@ impl ChunkHashesResult {
}
}

#[derive(Debug, Clone)]
pub struct ChunkRenderResult {
pub manifests: Vec<RenderManifestEntry>,
pub diagnostics: Vec<Diagnostic>,
}

#[derive(Debug, Clone)]
pub struct Chunk {
ukey: ChunkUkey,
Expand Down
85 changes: 33 additions & 52 deletions crates/rspack_core/src/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ use crate::{
old_cache::{use_code_splitting_cache, Cache as OldCache, CodeSplittingCache},
to_identifier, BoxDependency, BoxModule, CacheCount, CacheOptions, Chunk, ChunkByUkey,
ChunkContentHash, ChunkGraph, ChunkGroupByUkey, ChunkGroupUkey, ChunkHashesResult, ChunkKind,
ChunkUkey, CodeGenerationJob, CodeGenerationResult, CodeGenerationResults, CompilationLogger,
CompilationLogging, CompilerOptions, DependencyId, DependencyType, Entry, EntryData,
EntryOptions, EntryRuntime, Entrypoint, ExecuteModuleId, Filename, ImportVarMap, LocalFilenameFn,
Logger, ModuleFactory, ModuleGraph, ModuleGraphPartial, ModuleIdentifier, PathData,
ResolverFactory, RuntimeGlobals, RuntimeModule, RuntimeSpecMap, SharedPluginDriver, SourceType,
Stats,
ChunkRenderResult, ChunkUkey, CodeGenerationJob, CodeGenerationResult, CodeGenerationResults,
CompilationLogger, CompilationLogging, CompilerOptions, DependencyId, DependencyType, Entry,
EntryData, EntryOptions, EntryRuntime, Entrypoint, ExecuteModuleId, Filename, ImportVarMap,
LocalFilenameFn, Logger, ModuleFactory, ModuleGraph, ModuleGraphPartial, ModuleIdentifier,
PathData, ResolverFactory, RuntimeGlobals, RuntimeModule, RuntimeSpecMap, SharedPluginDriver,
SourceType, Stats,
};

pub type BuildDependency = (
Expand Down Expand Up @@ -175,7 +175,7 @@ pub struct Compilation {
pub cgm_runtime_requirements_results: CgmRuntimeRequirementsResults,
pub cgc_runtime_requirements_results: UkeyMap<ChunkUkey, RuntimeGlobals>,
pub chunk_hashes_results: UkeyMap<ChunkUkey, ChunkHashesResult>,
pub chunk_render_results: UkeyMap<ChunkUkey, (Vec<RenderManifestEntry>, Vec<Diagnostic>)>,
pub chunk_render_results: UkeyMap<ChunkUkey, ChunkRenderResult>,
pub built_modules: IdentifierSet,
pub code_generated_modules: IdentifierSet,
pub build_time_executed_modules: IdentifierSet,
Expand Down Expand Up @@ -972,15 +972,21 @@ impl Compilation {
let chunk_render_results = chunks
.iter()
.map(|chunk| async {
let mut manifest = Vec::new();
let mut manifests = Vec::new();
let mut diagnostics = Vec::new();
plugin_driver
.compilation_hooks
.render_manifest
.call(self, chunk, &mut manifest, &mut diagnostics)
.call(self, chunk, &mut manifests, &mut diagnostics)
.await?;

Ok((*chunk, (manifest, diagnostics)))
Ok((
*chunk,
ChunkRenderResult {
manifests,
diagnostics,
},
))
})
.collect::<FuturesResults<Result<_>>>();
let chunk_render_results = chunk_render_results
Expand All @@ -995,11 +1001,18 @@ impl Compilation {
chunk_render_results
};

for (chunk_ukey, (manifest, diagnostics)) in chunk_ukey_and_manifest {
for (
chunk_ukey,
ChunkRenderResult {
manifests,
diagnostics,
},
) in chunk_ukey_and_manifest
{
self.extend_diagnostics(diagnostics);

for file_manifest in manifest {
let filename = file_manifest.filename().to_string();
for file_manifest in manifests {
let filename = file_manifest.filename;
let current_chunk = self.chunk_by_ukey.expect_get_mut(&chunk_ukey);

current_chunk.set_rendered(true);
Expand Down Expand Up @@ -1996,13 +2009,13 @@ impl Compilation {
&'a self,
filename: &Filename<F>,
mut data: PathData<'b>,
) -> Result<(String, AssetInfo), F::Error> {
let mut info = AssetInfo::default();
info: &mut AssetInfo,
) -> Result<String, F::Error> {
if data.hash.is_none() {
data.hash = self.get_hash();
}
let path = filename.render(data, Some(&mut info))?;
Ok((path, info))
let path = filename.render(data, Some(info))?;
Ok(path)
}

pub fn get_asset_path<F: LocalFilenameFn>(
Expand Down Expand Up @@ -2324,42 +2337,10 @@ pub fn set_depth_if_lower(
#[derive(Debug, Clone)]
pub struct RenderManifestEntry {
pub source: BoxSource,
filename: String,
pub filename: String,
pub has_filename: bool, /* webpack only asset has filename, js/css/wasm has filename template */
pub info: AssetInfo,
// pub identifier: String,
// hash?: string;
pub(crate) auxiliary: bool,
has_filename: bool, /* webpack only asset has filename, js/css/wasm has filename template */
}

impl RenderManifestEntry {
pub fn new(
source: BoxSource,
filename: String,
info: AssetInfo,
auxiliary: bool,
has_filename: bool,
) -> Self {
Self {
source,
filename,
info,
auxiliary,
has_filename,
}
}

pub fn source(&self) -> &BoxSource {
&self.source
}

pub fn filename(&self) -> &str {
&self.filename
}

pub fn has_filename(&self) -> bool {
self.has_filename
}
pub auxiliary: bool,
}

fn process_runtime_requirement_hook(
Expand Down
8 changes: 3 additions & 5 deletions crates/rspack_core/src/old_cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@ mod local;
mod occasion;
mod storage;
pub use local::*;
use occasion::{
CodeGenerateOccasion, CreateChunkAssetsOccasion, ProcessRuntimeRequirementsOccasion,
};
use occasion::{ChunkRenderOccasion, CodeGenerateOccasion, ProcessRuntimeRequirementsOccasion};
use storage::new_storage;

#[derive(Debug)]
pub struct Cache {
is_idle: AtomicBool,
pub code_generate_occasion: CodeGenerateOccasion,
pub process_runtime_requirements_occasion: ProcessRuntimeRequirementsOccasion,
pub create_chunk_assets_occasion: CreateChunkAssetsOccasion,
pub chunk_render_occasion: ChunkRenderOccasion,
}

impl Cache {
Expand All @@ -33,7 +31,7 @@ impl Cache {
process_runtime_requirements_occasion: ProcessRuntimeRequirementsOccasion::new(new_storage(
&options.cache,
)),
create_chunk_assets_occasion: CreateChunkAssetsOccasion::new(new_storage(&options.cache)),
chunk_render_occasion: ChunkRenderOccasion::new(new_storage(&options.cache)),
}
}

Expand Down
51 changes: 51 additions & 0 deletions crates/rspack_core/src/old_cache/occasion/chunk_render.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use futures::Future;
use rspack_collections::Identifier;
use rspack_error::{Diagnostic, Result};
use rspack_sources::BoxSource;

use crate::{old_cache::storage, Chunk, Compilation, SourceType};

type Storage = dyn storage::Storage<(BoxSource, Vec<Diagnostic>)>;

#[derive(Debug)]
pub struct ChunkRenderOccasion {
storage: Option<Box<Storage>>,
}

impl ChunkRenderOccasion {
pub fn new(storage: Option<Box<Storage>>) -> Self {
Self { storage }
}

pub async fn use_cache<G, F>(
&self,
compilation: &Compilation,
chunk: &Chunk,
source_type: &SourceType,
generator: G,
) -> Result<(BoxSource, Vec<Diagnostic>)>
where
G: FnOnce() -> F,
F: Future<Output = Result<(BoxSource, Vec<Diagnostic>)>>,
{
let storage = match &self.storage {
Some(s) => s,
// no cache return directly
None => return generator().await,
};

let Some(content_hash) =
chunk.content_hash_by_source_type(&compilation.chunk_hashes_results, source_type)
else {
return generator().await;
};
let cache_key = Identifier::from(content_hash.encoded());
if let Some(value) = storage.get(&cache_key) {
Ok(value)
} else {
let res = generator().await?;
storage.set(cache_key, res.clone());
Ok(res)
}
}
}
62 changes: 0 additions & 62 deletions crates/rspack_core/src/old_cache/occasion/create_chunk_assets.rs

This file was deleted.

4 changes: 2 additions & 2 deletions crates/rspack_core/src/old_cache/occasion/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ mod code_generate;
pub use code_generate::*;
mod process_runtime_requirements;
pub use process_runtime_requirements::*;
mod create_chunk_assets;
pub use create_chunk_assets::*;
mod chunk_render;
pub use chunk_render::*;
22 changes: 9 additions & 13 deletions crates/rspack_core/src/options/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,6 @@ impl From<String> for PublicPath {
}
}

#[allow(clippy::if_same_then_else)]
pub fn get_css_chunk_filename_template<'filename>(
chunk: &'filename Chunk,
output_options: &'filename OutputOptions,
Expand All @@ -395,23 +394,20 @@ pub fn get_css_chunk_filename_template<'filename>(
}
}

#[allow(clippy::if_same_then_else)]
pub fn get_js_chunk_filename_template<'filename>(
chunk: &'filename Chunk,
output_options: &'filename OutputOptions,
pub fn get_js_chunk_filename_template(
chunk: &Chunk,
output_options: &OutputOptions,
chunk_group_by_ukey: &ChunkGroupByUkey,
) -> &'filename Filename {
) -> Filename {
// Align with https://github.com/webpack/webpack/blob/8241da7f1e75c5581ba535d127fa66aeb9eb2ac8/lib/javascript/JavascriptModulesPlugin.js#L480
if let Some(filename_template) = chunk.filename_template() {
filename_template
} else if chunk.can_be_initial(chunk_group_by_ukey) {
&output_options.filename
filename_template.clone()
} else if matches!(chunk.kind(), ChunkKind::HotUpdate) {
// TODO: Should return output_options.hotUpdateChunkFilename
// See https://github.com/webpack/webpack/blob/8241da7f1e75c5581ba535d127fa66aeb9eb2ac8/lib/javascript/JavascriptModulesPlugin.js#L484
&output_options.chunk_filename
output_options.hot_update_chunk_filename.clone().into()
} else if chunk.can_be_initial(chunk_group_by_ukey) {
output_options.filename.clone()
} else {
&output_options.chunk_filename
output_options.chunk_filename.clone()
}
}

Expand Down
14 changes: 7 additions & 7 deletions crates/rspack_plugin_asset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,13 +612,13 @@ async fn render_manifest(
.get::<CodeGenerationDataAssetInfo>()
.expect("should have asset_info")
.inner();
RenderManifestEntry::new(
source.clone(),
asset_filename.to_owned(),
asset_info.to_owned(),
true,
true,
)
RenderManifestEntry {
source: source.clone(),
filename: asset_filename.to_owned(),
has_filename: true,
info: asset_info.to_owned(),
auxiliary: true,
}
});

Ok(result)
Expand Down
Loading

2 comments on commit 2edb6b4

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ✅ success
_selftest ✅ success
rsdoctor ❌ failure
rspress ✅ success
rslib ❌ failure
rsbuild ✅ success
examples ✅ success
devserver ✅ success
nuxt ✅ success

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-11-27 c1e8f11) Current Change
10000_big_production-mode_disable-minimize + exec 40.2 s ± 1.43 s 42.4 s ± 760 ms +5.44 %
10000_development-mode + exec 1.82 s ± 32 ms 1.78 s ± 32 ms -2.05 %
10000_development-mode_hmr + exec 644 ms ± 15 ms 647 ms ± 10 ms +0.44 %
10000_production-mode + exec 2.41 s ± 42 ms 2.39 s ± 24 ms -0.61 %
arco-pro_development-mode + exec 1.79 s ± 61 ms 1.76 s ± 65 ms -1.23 %
arco-pro_development-mode_hmr + exec 429 ms ± 2.1 ms 426 ms ± 1.5 ms -0.78 %
arco-pro_production-mode + exec 3.1 s ± 93 ms 3.1 s ± 53 ms +0.01 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.17 s ± 67 ms 3.18 s ± 68 ms +0.24 %
threejs_development-mode_10x + exec 1.62 s ± 16 ms 1.62 s ± 8.4 ms -0.43 %
threejs_development-mode_10x_hmr + exec 811 ms ± 12 ms 810 ms ± 15 ms -0.16 %
threejs_production-mode_10x + exec 4.9 s ± 36 ms 4.93 s ± 35 ms +0.57 %
10000_big_production-mode_disable-minimize + rss memory 12451 MiB ± 95.7 MiB 13676 MiB ± 233 MiB +9.84 %
10000_development-mode + rss memory 742 MiB ± 18.2 MiB 778 MiB ± 25 MiB +4.86 %
10000_development-mode_hmr + rss memory 1578 MiB ± 403 MiB 2016 MiB ± 456 MiB +27.79 %
10000_production-mode + rss memory 679 MiB ± 64.6 MiB 667 MiB ± 23.6 MiB -1.68 %
arco-pro_development-mode + rss memory 701 MiB ± 43.4 MiB 738 MiB ± 21.6 MiB +5.27 %
arco-pro_development-mode_hmr + rss memory 871 MiB ± 88.7 MiB 946 MiB ± 41.2 MiB +8.60 %
arco-pro_production-mode + rss memory 876 MiB ± 56.8 MiB 871 MiB ± 82.7 MiB -0.57 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 859 MiB ± 52.9 MiB 877 MiB ± 44.9 MiB +2.09 %
threejs_development-mode_10x + rss memory 785 MiB ± 49.8 MiB 818 MiB ± 56 MiB +4.19 %
threejs_development-mode_10x_hmr + rss memory 1478 MiB ± 164 MiB 2010 MiB ± 381 MiB +35.94 %
threejs_production-mode_10x + rss memory 1044 MiB ± 66.8 MiB 1046 MiB ± 92.8 MiB +0.25 %

Threshold exceeded: ["10000_big_production-mode_disable-minimize + exec","threejs_development-mode_10x_hmr + rss memory"]

Please sign in to comment.