Skip to content

Commit

Permalink
perf(compile): code cache (#26528)
Browse files Browse the repository at this point in the history
Adds a lazily created code cache to `deno compile` by default.

The code cache is created on first run to a single file in the temp
directory and is only written once. After it's been written, the code
cache becomes read only on subsequent runs. Only the modules loaded
during startup are cached (dynamic imports are not code cached).

The code cache can be disabled by compiling with `--no-code-cache`.
  • Loading branch information
dsherret authored Nov 18, 2024
1 parent 3ba464d commit dd4570e
Show file tree
Hide file tree
Showing 14 changed files with 703 additions and 20 deletions.
7 changes: 6 additions & 1 deletion cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,7 @@ On the first invocation with deno will download the proper binary and cache it i
])
.help_heading(COMPILE_HEADING),
)
.arg(no_code_cache_arg())
.arg(
Arg::new("no-terminal")
.long("no-terminal")
Expand Down Expand Up @@ -4431,6 +4432,8 @@ fn compile_parse(
};
ext_arg_parse(flags, matches);

flags.code_cache_enabled = !matches.get_flag("no-code-cache");

flags.subcommand = DenoSubcommand::Compile(CompileFlags {
source_file,
output,
Expand Down Expand Up @@ -10040,6 +10043,7 @@ mod tests {
include: vec![]
}),
type_check_mode: TypeCheckMode::Local,
code_cache_enabled: true,
..Flags::default()
}
);
Expand All @@ -10048,7 +10052,7 @@ mod tests {
#[test]
fn compile_with_flags() {
#[rustfmt::skip]
let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--no-terminal", "--icon", "favicon.ico", "--output", "colors", "--env=.example.env", "https://examples.deno.land/color-logging.ts", "foo", "bar", "-p", "8080"]);
let r = flags_from_vec(svec!["deno", "compile", "--import-map", "import_map.json", "--no-code-cache", "--no-remote", "--config", "tsconfig.json", "--no-check", "--unsafely-ignore-certificate-errors", "--reload", "--lock", "lock.json", "--cert", "example.crt", "--cached-only", "--location", "https:foo", "--allow-read", "--allow-net", "--v8-flags=--help", "--seed", "1", "--no-terminal", "--icon", "favicon.ico", "--output", "colors", "--env=.example.env", "https://examples.deno.land/color-logging.ts", "foo", "bar", "-p", "8080"]);
assert_eq!(
r.unwrap(),
Flags {
Expand All @@ -10064,6 +10068,7 @@ mod tests {
}),
import_map_path: Some("import_map.json".to_string()),
no_remote: true,
code_cache_enabled: false,
config_flag: ConfigFlag::Path("tsconfig.json".to_owned()),
type_check_mode: TypeCheckMode::None,
reload: true,
Expand Down
10 changes: 10 additions & 0 deletions cli/cache/code_cache.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use std::sync::Arc;

use deno_ast::ModuleSpecifier;
use deno_core::error::AnyError;
use deno_runtime::code_cache;
use deno_runtime::deno_webstorage::rusqlite::params;

use crate::worker::CliCodeCache;

use super::cache_db::CacheDB;
use super::cache_db::CacheDBConfiguration;
use super::cache_db::CacheDBHash;
Expand Down Expand Up @@ -82,6 +86,12 @@ impl CodeCache {
}
}

impl CliCodeCache for CodeCache {
fn as_code_cache(self: Arc<Self>) -> Arc<dyn code_cache::CodeCache> {
self
}
}

impl code_cache::CodeCache for CodeCache {
fn get_sync(
&self,
Expand Down
14 changes: 14 additions & 0 deletions cli/standalone/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use crate::args::NpmInstallDepsProvider;
use crate::args::PermissionFlags;
use crate::args::UnstableConfig;
use crate::cache::DenoDir;
use crate::cache::FastInsecureHasher;
use crate::emit::Emitter;
use crate::file_fetcher::FileFetcher;
use crate::http_util::HttpClientProvider;
Expand Down Expand Up @@ -174,6 +175,7 @@ pub struct SerializedWorkspaceResolver {
pub struct Metadata {
pub argv: Vec<String>,
pub seed: Option<u64>,
pub code_cache_key: Option<u64>,
pub permissions: PermissionFlags,
pub location: Option<Url>,
pub v8_flags: Vec<String>,
Expand Down Expand Up @@ -604,10 +606,21 @@ impl<'a> DenoCompileBinaryWriter<'a> {
VfsBuilder::new(root_path.clone())?
};
let mut remote_modules_store = RemoteModulesStoreBuilder::default();
let mut code_cache_key_hasher = if cli_options.code_cache_enabled() {
Some(FastInsecureHasher::new_deno_versioned())
} else {
None
};
for module in graph.modules() {
if module.specifier().scheme() == "data" {
continue; // don't store data urls as an entry as they're in the code
}
if let Some(hasher) = &mut code_cache_key_hasher {
if let Some(source) = module.source() {
hasher.write(module.specifier().as_str().as_bytes());
hasher.write(source.as_bytes());
}
}
let (maybe_source, media_type) = match module {
deno_graph::Module::Js(m) => {
let source = if m.media_type.is_emittable() {
Expand Down Expand Up @@ -675,6 +688,7 @@ impl<'a> DenoCompileBinaryWriter<'a> {
let metadata = Metadata {
argv: compile_flags.args.clone(),
seed: cli_options.seed(),
code_cache_key: code_cache_key_hasher.map(|h| h.finish()),
location: cli_options.location_flag().clone(),
permissions: cli_options.permission_flags().clone(),
v8_flags: cli_options.v8_flags().clone(),
Expand Down
Loading

0 comments on commit dd4570e

Please sign in to comment.