perf: lazy bootstrap options - first pass (#21164)

Move most runtime options to be lazily loaded. Constant options will be
covered in a different PR.

Towards https://github.com/denoland/deno/issues/21133
This commit is contained in:
Divy Srivastava 2023-11-12 20:52:59 -08:00 committed by GitHub
parent 39223f709b
commit 1ef617e8f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 139 additions and 149 deletions

View file

@ -406,6 +406,7 @@ fn create_cli_snapshot(snapshot_path: PathBuf) -> CreateSnapshotOutput {
deno_runtime::ops::signal::deno_signal::init_ops(), deno_runtime::ops::signal::deno_signal::init_ops(),
deno_runtime::ops::tty::deno_tty::init_ops(), deno_runtime::ops::tty::deno_tty::init_ops(),
deno_runtime::ops::http::deno_http_runtime::init_ops(), deno_runtime::ops::http::deno_http_runtime::init_ops(),
deno_runtime::ops::bootstrap::deno_bootstrap::init_ops(),
cli::init_ops_and_esm(), // NOTE: This needs to be init_ops_and_esm! cli::init_ops_and_esm(), // NOTE: This needs to be init_ops_and_esm!
]; ];

View file

@ -137,14 +137,14 @@ const {
isNaN, isNaN,
} = primordials; } = primordials;
let noColor = false; let noColor = () => false;
function setNoColor(value) { function setNoColorFn(fn) {
noColor = value; noColor = fn;
} }
function getNoColor() { function getNoColor() {
return noColor; return noColor();
} }
function assert(cond, msg = "Assertion failed.") { function assert(cond, msg = "Assertion failed.") {
@ -3646,7 +3646,7 @@ export {
inspect, inspect,
inspectArgs, inspectArgs,
quoteString, quoteString,
setNoColor, setNoColorFn,
styles, styles,
wrapConsole, wrapConsole,
}; };

View file

@ -1,5 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
const core = globalThis.Deno.core;
const ops = core.ops;
const primordials = globalThis.__bootstrap.primordials; const primordials = globalThis.__bootstrap.primordials;
const { const {
Promise, Promise,
@ -14,18 +16,18 @@ const LogLevel = {
Debug: 4, Debug: 4,
}; };
let logLevel = 3; const logSource = "JS";
let logSource = "JS";
function setLogLevel(level, source) { let logLevel_ = null;
logLevel = level; function logLevel() {
if (source) { if (logLevel_ === null) {
logSource = source; logLevel_ = ops.op_bootstrap_log_level() || 3;
} }
return logLevel_;
} }
function log(...args) { function log(...args) {
if (logLevel >= LogLevel.Debug) { if (logLevel() >= LogLevel.Debug) {
// if we destructure `console` off `globalThis` too early, we don't bind to // if we destructure `console` off `globalThis` too early, we don't bind to
// the right console, therefore we don't log anything out. // the right console, therefore we don't log anything out.
globalThis.console.error( globalThis.console.error(
@ -83,12 +85,4 @@ function getterOnly(getter) {
}; };
} }
export { export { createResolvable, getterOnly, log, nonEnumerable, readOnly, writable };
createResolvable,
getterOnly,
log,
nonEnumerable,
readOnly,
setLogLevel,
writable,
};

View file

@ -1,6 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
const core = globalThis.Deno.core; const core = globalThis.Deno.core;
const ops = core.ops;
const primordials = globalThis.__bootstrap.primordials; const primordials = globalThis.__bootstrap.primordials;
const { const {
ObjectDefineProperties, ObjectDefineProperties,
@ -157,19 +158,19 @@ class Navigator {
const navigator = webidl.createBranded(Navigator); const navigator = webidl.createBranded(Navigator);
let numCpus, userAgent, language; function memoizeLazy(f) {
let v_ = null;
function setNumCpus(val) { return () => {
numCpus = val; if (v_ === null) {
v_ = f();
}
return v_;
};
} }
function setUserAgent(val) { const numCpus = memoizeLazy(() => ops.op_bootstrap_numcpus());
userAgent = val; const userAgent = memoizeLazy(() => ops.op_bootstrap_user_agent());
} const language = memoizeLazy(() => ops.op_bootstrap_language());
function setLanguage(val) {
language = val;
}
ObjectDefineProperties(Navigator.prototype, { ObjectDefineProperties(Navigator.prototype, {
hardwareConcurrency: { hardwareConcurrency: {
@ -177,7 +178,7 @@ ObjectDefineProperties(Navigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, NavigatorPrototype); webidl.assertBranded(this, NavigatorPrototype);
return numCpus; return numCpus();
}, },
}, },
userAgent: { userAgent: {
@ -185,7 +186,7 @@ ObjectDefineProperties(Navigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, NavigatorPrototype); webidl.assertBranded(this, NavigatorPrototype);
return userAgent; return userAgent();
}, },
}, },
language: { language: {
@ -193,7 +194,7 @@ ObjectDefineProperties(Navigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, NavigatorPrototype); webidl.assertBranded(this, NavigatorPrototype);
return language; return language();
}, },
}, },
languages: { languages: {
@ -201,7 +202,7 @@ ObjectDefineProperties(Navigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, NavigatorPrototype); webidl.assertBranded(this, NavigatorPrototype);
return [language]; return [language()];
}, },
}, },
}); });
@ -225,7 +226,7 @@ ObjectDefineProperties(WorkerNavigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, WorkerNavigatorPrototype); webidl.assertBranded(this, WorkerNavigatorPrototype);
return numCpus; return numCpus();
}, },
}, },
userAgent: { userAgent: {
@ -233,7 +234,7 @@ ObjectDefineProperties(WorkerNavigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, WorkerNavigatorPrototype); webidl.assertBranded(this, WorkerNavigatorPrototype);
return userAgent; return userAgent();
}, },
}, },
language: { language: {
@ -241,7 +242,7 @@ ObjectDefineProperties(WorkerNavigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, WorkerNavigatorPrototype); webidl.assertBranded(this, WorkerNavigatorPrototype);
return language; return language();
}, },
}, },
languages: { languages: {
@ -249,7 +250,7 @@ ObjectDefineProperties(WorkerNavigator.prototype, {
enumerable: true, enumerable: true,
get() { get() {
webidl.assertBranded(this, WorkerNavigatorPrototype); webidl.assertBranded(this, WorkerNavigatorPrototype);
return [language]; return [language()];
}, },
}, },
}); });
@ -284,9 +285,7 @@ const workerRuntimeGlobalProperties = {
export { export {
mainRuntimeGlobalProperties, mainRuntimeGlobalProperties,
setLanguage, memoizeLazy,
setNumCpus,
setUserAgent,
unstableWindowOrWorkerGlobalScope, unstableWindowOrWorkerGlobalScope,
windowOrWorkerGlobalScope, windowOrWorkerGlobalScope,
workerRuntimeGlobalProperties, workerRuntimeGlobalProperties,

View file

@ -26,7 +26,6 @@ const {
ObjectAssign, ObjectAssign,
ObjectDefineProperties, ObjectDefineProperties,
ObjectDefineProperty, ObjectDefineProperty,
ObjectFreeze,
ObjectPrototypeIsPrototypeOf, ObjectPrototypeIsPrototypeOf,
ObjectSetPrototypeOf, ObjectSetPrototypeOf,
PromisePrototypeThen, PromisePrototypeThen,
@ -50,7 +49,7 @@ import {
getNoColor, getNoColor,
inspectArgs, inspectArgs,
quoteString, quoteString,
setNoColor, setNoColorFn,
wrapConsole, wrapConsole,
} from "ext:deno_console/01_console.js"; } from "ext:deno_console/01_console.js";
import * as performance from "ext:deno_web/15_performance.js"; import * as performance from "ext:deno_web/15_performance.js";
@ -67,9 +66,7 @@ import * as webidl from "ext:deno_webidl/00_webidl.js";
import DOMException from "ext:deno_web/01_dom_exception.js"; import DOMException from "ext:deno_web/01_dom_exception.js";
import { import {
mainRuntimeGlobalProperties, mainRuntimeGlobalProperties,
setLanguage, memoizeLazy,
setNumCpus,
setUserAgent,
unstableWindowOrWorkerGlobalScope, unstableWindowOrWorkerGlobalScope,
windowOrWorkerGlobalScope, windowOrWorkerGlobalScope,
workerRuntimeGlobalProperties, workerRuntimeGlobalProperties,
@ -241,6 +238,11 @@ function opMainModule() {
return ops.op_main_module(); return ops.op_main_module();
} }
const opArgs = memoizeLazy(() => ops.op_bootstrap_args());
const opPid = memoizeLazy(() => ops.op_bootstrap_pid());
const opPpid = memoizeLazy(() => ops.op_ppid());
setNoColorFn(() => ops.op_bootstrap_no_color());
function formatException(error) { function formatException(error) {
if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, error)) { if (ObjectPrototypeIsPrototypeOf(ErrorPrototype, error)) {
return null; return null;
@ -327,10 +329,6 @@ function runtimeStart(
v8Version, v8Version,
tsVersion, tsVersion,
target, target,
logLevel,
noColor,
isTty,
source,
) { ) {
core.setMacrotaskCallback(timers.handleTimerMacrotask); core.setMacrotaskCallback(timers.handleTimerMacrotask);
core.setMacrotaskCallback(promiseRejectMacrotaskCallback); core.setMacrotaskCallback(promiseRejectMacrotaskCallback);
@ -343,8 +341,6 @@ function runtimeStart(
tsVersion, tsVersion,
); );
core.setBuildInfo(target); core.setBuildInfo(target);
util.setLogLevel(logLevel, source);
setNoColor(noColor || !isTty);
} }
const pendingRejections = []; const pendingRejections = [];
@ -461,25 +457,16 @@ function bootstrapMainRuntime(runtimeOptions) {
const nodeBootstrap = globalThis.nodeBootstrap; const nodeBootstrap = globalThis.nodeBootstrap;
const { const {
0: args, 0: denoVersion,
1: cpuCount, 1: location_,
2: logLevel, 2: tsVersion,
3: denoVersion, 3: unstableFlag,
4: locale, 4: unstableFeatures,
5: location_, 5: target,
6: noColor, 6: v8Version,
7: isTty, 7: inspectFlag,
8: tsVersion, 9: hasNodeModulesDir,
9: unstableFlag, 10: maybeBinaryNpmCommandName,
10: unstableFeatures,
11: pid,
12: target,
13: v8Version,
14: userAgent,
15: inspectFlag,
// 16: enableTestingFeaturesFlag
17: hasNodeModulesDir,
18: maybeBinaryNpmCommandName,
} = runtimeOptions; } = runtimeOptions;
performance.setTimeOrigin(DateNow()); performance.setTimeOrigin(DateNow());
@ -538,27 +525,13 @@ function bootstrapMainRuntime(runtimeOptions) {
v8Version, v8Version,
tsVersion, tsVersion,
target, target,
logLevel,
noColor,
isTty,
); );
setNumCpus(cpuCount);
setUserAgent(userAgent);
setLanguage(locale);
let ppid = undefined;
ObjectDefineProperties(finalDenoNs, { ObjectDefineProperties(finalDenoNs, {
pid: util.readOnly(pid), pid: util.getterOnly(opPid),
ppid: util.getterOnly(() => { ppid: util.getterOnly(opPpid),
// lazy because it's expensive noColor: util.getterOnly(getNoColor),
if (ppid === undefined) { args: util.getterOnly(opArgs),
ppid = ops.op_ppid();
}
return ppid;
}),
noColor: util.readOnly(noColor),
args: util.readOnly(ObjectFreeze(args)),
mainModule: util.getterOnly(opMainModule), mainModule: util.getterOnly(opMainModule),
}); });
@ -593,8 +566,6 @@ function bootstrapMainRuntime(runtimeOptions) {
// `Deno` with `Deno` namespace from "./deno.ts". // `Deno` with `Deno` namespace from "./deno.ts".
ObjectDefineProperty(globalThis, "Deno", util.readOnly(finalDenoNs)); ObjectDefineProperty(globalThis, "Deno", util.readOnly(finalDenoNs));
util.log("args", args);
if (nodeBootstrap) { if (nodeBootstrap) {
nodeBootstrap(hasNodeModulesDir, maybeBinaryNpmCommandName); nodeBootstrap(hasNodeModulesDir, maybeBinaryNpmCommandName);
} }
@ -612,25 +583,16 @@ function bootstrapWorkerRuntime(
const nodeBootstrap = globalThis.nodeBootstrap; const nodeBootstrap = globalThis.nodeBootstrap;
const { const {
0: args, 0: denoVersion,
1: cpuCount, 1: location_,
2: logLevel, 2: tsVersion,
3: denoVersion, 3: unstableFlag,
4: locale, 4: unstableFeatures,
5: location_, 5: target,
6: noColor, 6: v8Version,
7: isTty, 8: enableTestingFeaturesFlag,
8: tsVersion, 9: hasNodeModulesDir,
9: unstableFlag, 10: maybeBinaryNpmCommandName,
10: unstableFeatures,
11: pid,
12: target,
13: v8Version,
14: userAgent,
// 15: inspectFlag,
16: enableTestingFeaturesFlag,
17: hasNodeModulesDir,
18: maybeBinaryNpmCommandName,
} = runtimeOptions; } = runtimeOptions;
performance.setTimeOrigin(DateNow()); performance.setTimeOrigin(DateNow());
@ -686,18 +648,11 @@ function bootstrapWorkerRuntime(
v8Version, v8Version,
tsVersion, tsVersion,
target, target,
logLevel,
noColor,
isTty,
internalName ?? name, internalName ?? name,
); );
location.setLocationHref(location_); location.setLocationHref(location_);
setNumCpus(cpuCount);
setUserAgent(userAgent);
setLanguage(locale);
globalThis.pollForMessages = pollForMessages; globalThis.pollForMessages = pollForMessages;
// TODO(bartlomieju): deprecate --unstable // TODO(bartlomieju): deprecate --unstable
@ -710,9 +665,9 @@ function bootstrapWorkerRuntime(
} }
} }
ObjectDefineProperties(finalDenoNs, { ObjectDefineProperties(finalDenoNs, {
pid: util.readOnly(pid), pid: util.getterOnly(opPid),
noColor: util.readOnly(noColor), noColor: util.getterOnly(getNoColor),
args: util.readOnly(ObjectFreeze(args)), args: util.getterOnly(opArgs),
}); });
// Setup `Deno` global - we're actually overriding already // Setup `Deno` global - we're actually overriding already
// existing global `Deno` with `Deno` namespace from "./deno.ts". // existing global `Deno` with `Deno` namespace from "./deno.ts".

61
runtime/ops/bootstrap.rs Normal file
View file

@ -0,0 +1,61 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use deno_core::op2;
use deno_core::OpState;
use crate::BootstrapOptions;
deno_core::extension!(
deno_bootstrap,
ops = [
op_bootstrap_args,
op_bootstrap_pid,
op_bootstrap_numcpus,
op_bootstrap_user_agent,
op_bootstrap_language,
op_bootstrap_log_level,
op_bootstrap_no_color,
],
);
#[op2]
#[serde]
pub fn op_bootstrap_args(state: &mut OpState) -> Vec<String> {
state.borrow::<BootstrapOptions>().args.clone()
}
#[op2(fast)]
#[smi]
pub fn op_bootstrap_pid() -> u32 {
std::process::id()
}
#[op2(fast)]
#[smi]
pub fn op_bootstrap_numcpus(state: &mut OpState) -> u32 {
state.borrow::<BootstrapOptions>().cpu_count as u32
}
#[op2]
#[string]
pub fn op_bootstrap_user_agent(state: &mut OpState) -> String {
state.borrow::<BootstrapOptions>().user_agent.clone()
}
#[op2]
#[string]
pub fn op_bootstrap_language(state: &mut OpState) -> String {
state.borrow::<BootstrapOptions>().locale.clone()
}
#[op2(fast)]
#[smi]
pub fn op_bootstrap_log_level(state: &mut OpState) -> i32 {
state.borrow::<BootstrapOptions>().log_level as i32
}
#[op2(fast)]
pub fn op_bootstrap_no_color(state: &mut OpState) -> bool {
let options = state.borrow::<BootstrapOptions>();
options.no_color || !options.is_tty
}

View file

@ -1,5 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
pub mod bootstrap;
pub mod fs_events; pub mod fs_events;
pub mod http; pub mod http;
pub mod os; pub mod os;

View file

@ -476,6 +476,7 @@ impl WebWorker {
ops::signal::deno_signal::init_ops_and_esm(), ops::signal::deno_signal::init_ops_and_esm(),
ops::tty::deno_tty::init_ops_and_esm(), ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(), ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(),
deno_permissions_web_worker::init_ops_and_esm( deno_permissions_web_worker::init_ops_and_esm(
permissions, permissions,
enable_testing_features, enable_testing_features,
@ -608,6 +609,7 @@ impl WebWorker {
} }
pub fn bootstrap(&mut self, options: &BootstrapOptions) { pub fn bootstrap(&mut self, options: &BootstrapOptions) {
self.js_runtime.op_state().borrow_mut().put(options.clone());
// Instead of using name for log we use `worker-${id}` because // Instead of using name for log we use `worker-${id}` because
// WebWorkers can have empty string as name. // WebWorkers can have empty string as name.
{ {

View file

@ -264,7 +264,7 @@ impl MainWorker {
) -> Self { ) -> Self {
let bootstrap_options = options.bootstrap.clone(); let bootstrap_options = options.bootstrap.clone();
let mut worker = Self::from_options(main_module, permissions, options); let mut worker = Self::from_options(main_module, permissions, options);
worker.bootstrap(&bootstrap_options); worker.bootstrap(bootstrap_options);
worker worker
} }
@ -380,6 +380,7 @@ impl MainWorker {
ops::signal::deno_signal::init_ops_and_esm(), ops::signal::deno_signal::init_ops_and_esm(),
ops::tty::deno_tty::init_ops_and_esm(), ops::tty::deno_tty::init_ops_and_esm(),
ops::http::deno_http_runtime::init_ops_and_esm(), ops::http::deno_http_runtime::init_ops_and_esm(),
ops::bootstrap::deno_bootstrap::init_ops_and_esm(),
deno_permissions_worker::init_ops_and_esm( deno_permissions_worker::init_ops_and_esm(
permissions, permissions,
enable_testing_features, enable_testing_features,
@ -454,7 +455,6 @@ impl MainWorker {
let inspector = js_runtime.inspector(); let inspector = js_runtime.inspector();
op_state.borrow_mut().put(inspector); op_state.borrow_mut().put(inspector);
} }
let bootstrap_fn_global = { let bootstrap_fn_global = {
let context = js_runtime.main_context(); let context = js_runtime.main_context();
let scope = &mut js_runtime.handle_scope(); let scope = &mut js_runtime.handle_scope();
@ -486,7 +486,8 @@ impl MainWorker {
} }
} }
pub fn bootstrap(&mut self, options: &BootstrapOptions) { pub fn bootstrap(&mut self, options: BootstrapOptions) {
self.js_runtime.op_state().borrow_mut().put(options.clone());
let scope = &mut self.js_runtime.handle_scope(); let scope = &mut self.js_runtime.handle_scope();
let args = options.as_v8(scope); let args = options.as_v8(scope);
let bootstrap_fn = self.bootstrap_fn_global.take().unwrap(); let bootstrap_fn = self.bootstrap_fn_global.take().unwrap();

View file

@ -107,36 +107,20 @@ impl Default for BootstrapOptions {
/// Keep this in sync with `99_main.js`. /// Keep this in sync with `99_main.js`.
#[derive(Serialize)] #[derive(Serialize)]
struct BootstrapV8<'a>( struct BootstrapV8<'a>(
// args
&'a Vec<String>,
// cpu_count
i32,
// log_level
i32,
// runtime_version // runtime_version
&'a str, &'a str,
// locale
&'a str,
// location // location
Option<&'a str>, Option<&'a str>,
// no_color
bool,
// is_tty
bool,
// ts_version // ts_version
&'a str, &'a str,
// unstable // unstable
bool, bool,
// granular unstable flags // granular unstable flags
&'a [i32], &'a [i32],
// process_id
i32,
// env!("TARGET") // env!("TARGET")
&'a str, &'a str,
// v8_version // v8_version
&'a str, &'a str,
// user_agent
&'a str,
// inspect // inspect
bool, bool,
// enable_testing_features // enable_testing_features
@ -157,21 +141,13 @@ impl BootstrapOptions {
let ser = deno_core::serde_v8::Serializer::new(&scope); let ser = deno_core::serde_v8::Serializer::new(&scope);
let bootstrap = BootstrapV8( let bootstrap = BootstrapV8(
&self.args,
self.cpu_count as _,
self.log_level as _,
&self.runtime_version, &self.runtime_version,
&self.locale,
self.location.as_ref().map(|l| l.as_str()), self.location.as_ref().map(|l| l.as_str()),
self.no_color,
self.is_tty,
&self.ts_version, &self.ts_version,
self.unstable, self.unstable,
self.unstable_features.as_ref(), self.unstable_features.as_ref(),
std::process::id() as _,
env!("TARGET"), env!("TARGET"),
deno_core::v8_version(), deno_core::v8_version(),
&self.user_agent,
self.inspect, self.inspect,
self.enable_testing_features, self.enable_testing_features,
self.has_node_modules_dir, self.has_node_modules_dir,