1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

perf(cli): faster standalone executable determination (#22717)

This was showing up on the flamegraph.

```
14:54 $ hyperfine -S none --warmup 25 '/tmp/deno run /tmp/empty.js' 'target/release/deno run /tmp/empty.js'
Benchmark 1: /tmp/deno run /tmp/empty.js
  Time (mean ± σ):      17.2 ms ±   4.7 ms    [User: 11.2 ms, System: 4.0 ms]
  Range (min … max):    15.1 ms …  72.9 ms    172 runs
 
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
 
Benchmark 2: target/release/deno run /tmp/empty.js
  Time (mean ± σ):      16.7 ms ±   1.1 ms    [User: 11.1 ms, System: 4.0 ms]
  Range (min … max):    15.0 ms …  20.1 ms    189 runs
 
Summary
  'target/release/deno run /tmp/empty.js' ran
    1.03 ± 0.29 times faster than '/tmp/deno run /tmp/empty.js'
✔ ~/Documents/github/deno/deno [faster_extract|…5⚑ 23] 
```
This commit is contained in:
Matt Mastracci 2024-03-05 15:14:49 -07:00 committed by GitHub
parent 3333d67335
commit 3fd4b882a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 54 additions and 41 deletions

View file

@ -322,13 +322,15 @@ pub fn main() {
// initialize the V8 platform on a parent thread of all threads that will spawn // initialize the V8 platform on a parent thread of all threads that will spawn
// V8 isolates. // V8 isolates.
let current_exe_path = current_exe().unwrap();
let standalone =
standalone::extract_standalone(&current_exe_path, args.clone());
let future = async move { let future = async move {
let current_exe_path = current_exe()?; let standalone_res = match standalone {
let standalone_res = Ok(Some(future)) => {
match standalone::extract_standalone(&current_exe_path, args.clone()) let (metadata, eszip) = future.await?;
.await standalone::run(eszip, metadata).await
{ }
Ok(Some((metadata, eszip))) => standalone::run(eszip, metadata).await,
Ok(None) => Ok(()), Ok(None) => Ok(()),
Err(err) => Err(err), Err(err) => Err(err),
}; };

View file

@ -69,11 +69,16 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let future = async move {
let current_exe_path = current_exe().unwrap(); let current_exe_path = current_exe().unwrap();
match standalone::extract_standalone(&current_exe_path, args).await { let standalone =
Ok(Some((metadata, eszip))) => standalone::run(eszip, metadata).await, standalone::extract_standalone(&current_exe_path, args.clone());
Ok(None) => Err(generic_error("No archive found.")), let future = async move {
match standalone {
Ok(Some(future)) => {
let (metadata, eszip) = future.await?;
standalone::run(eszip, metadata).await
}
Ok(None) => Ok(()),
Err(err) => Err(err), Err(err) => Err(err),
} }
}; };

View file

@ -3,6 +3,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::env::current_exe; use std::env::current_exe;
use std::fs; use std::fs;
use std::future::Future;
use std::io::Read; use std::io::Read;
use std::io::Seek; use std::io::Seek;
use std::io::SeekFrom; use std::io::SeekFrom;
@ -236,32 +237,36 @@ pub fn is_standalone_binary(exe_path: &Path) -> bool {
/// binary by skipping over the trailer width at the end of the file, /// binary by skipping over the trailer width at the end of the file,
/// then checking for the magic trailer string `d3n0l4nd`. If found, /// then checking for the magic trailer string `d3n0l4nd`. If found,
/// the bundle is executed. If not, this function exits with `Ok(None)`. /// the bundle is executed. If not, this function exits with `Ok(None)`.
pub async fn extract_standalone( pub fn extract_standalone(
exe_path: &Path, exe_path: &Path,
cli_args: Vec<String>, cli_args: Vec<String>,
) -> Result<Option<(Metadata, eszip::EszipV2)>, AnyError> { ) -> Result<
let file = std::fs::File::open(exe_path)?; Option<impl Future<Output = Result<(Metadata, eszip::EszipV2), AnyError>>>,
AnyError,
let mut bufreader = > {
deno_core::futures::io::BufReader::new(AllowStdIo::new(file)); // We do the first part sync so it can complete quickly
let mut file = std::fs::File::open(exe_path)?;
let _trailer_pos = bufreader file.seek(SeekFrom::End(-(TRAILER_SIZE as i64)))?;
.seek(SeekFrom::End(-(TRAILER_SIZE as i64)))
.await?;
let mut trailer = [0; TRAILER_SIZE]; let mut trailer = [0; TRAILER_SIZE];
bufreader.read_exact(&mut trailer).await?; file.read_exact(&mut trailer)?;
let trailer = match Trailer::parse(&trailer)? { let trailer = match Trailer::parse(&trailer)? {
None => return Ok(None), None => return Ok(None),
Some(trailer) => trailer, Some(trailer) => trailer,
}; };
bufreader.seek(SeekFrom::Start(trailer.eszip_pos)).await?; file.seek(SeekFrom::Start(trailer.eszip_pos))?;
// If we have an eszip, read it out
Ok(Some(async move {
let bufreader =
deno_core::futures::io::BufReader::new(AllowStdIo::new(file));
let (eszip, loader) = eszip::EszipV2::parse(bufreader) let (eszip, loader) = eszip::EszipV2::parse(bufreader)
.await .await
.context("Failed to parse eszip header")?; .context("Failed to parse eszip header")?;
let mut bufreader = loader.await.context("Failed to parse eszip archive")?; let mut bufreader =
loader.await.context("Failed to parse eszip archive")?;
bufreader bufreader
.seek(SeekFrom::Start(trailer.metadata_pos)) .seek(SeekFrom::Start(trailer.metadata_pos))
@ -278,7 +283,8 @@ pub async fn extract_standalone(
let mut metadata: Metadata = serde_json::from_str(&metadata).unwrap(); let mut metadata: Metadata = serde_json::from_str(&metadata).unwrap();
metadata.argv.append(&mut cli_args[1..].to_vec()); metadata.argv.append(&mut cli_args[1..].to_vec());
Ok(Some((metadata, eszip))) Ok((metadata, eszip))
}))
} }
const TRAILER_SIZE: usize = std::mem::size_of::<Trailer>() + 8; // 8 bytes for the magic trailer string const TRAILER_SIZE: usize = std::mem::size_of::<Trailer>() + 8; // 8 bytes for the magic trailer string