0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 17:34:47 -05:00

perf(http): instantiate generic functions in deno_http, increase opt-level for some more hyper deps (#28317)

results on my machine (Macbook pro w/ M3 Max)

canary (hello world):
```
❯ oha -c 125 -n 4000000 --no-tui --disable-compression http://localhost:8000
Summary:
  Success rate: 100.00%
  Total:        31.0160 secs
  Slowest:      0.0083 secs
  Fastest:      0.0005 secs
  Average:      0.0010 secs
  Requests/sec: 128965.6454

  Total data:   49.59 MiB
  Size/request: 13 B
  Size/sec:     1.60 MiB
```

this PR (hello world):
```
❯ oha -c 125 -n 4000000 --no-tui --disable-compression http://localhost:8000
Summary:
  Success rate: 100.00%
  Total:        28.4050 secs
  Slowest:      0.0085 secs
  Fastest:      0.0001 secs
  Average:      0.0009 secs
  Requests/sec: 140820.2060

  Total data:   49.59 MiB
  Size/request: 13 B
  Size/sec:     1.75 MiB
```

---

Two changes here:
- use `opt-level` 3 for some of hyper's deps, since profile overrides
are not transitive
- As noted in the [cargo
reference](https://doc.rust-lang.org/cargo/reference/profiles.html#overrides-and-generics)
generic functions _may_ be optimized at the opt-level of the
_instantiating_ crate, rather than the defining crate. So currently it's
possible that some of the functions in `deno_http` are being compiled at
a lower optimization level. This PR ensures the generics are
instantiated in `deno_http`, which theoretically should guarantee they
actually use opt-level 3.

To allow embedders to still provide a custom property extractor, I put
this behind a feature flag.
This commit is contained in:
Nathan Whitaker 2025-02-27 10:07:11 -08:00 committed by GitHub
parent aa55efaa13
commit 69b59b2296
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 87 additions and 22 deletions

View file

@ -437,6 +437,16 @@ opt-level = 3
opt-level = 3
[profile.release.package.futures-util]
opt-level = 3
[profile.release.package.futures-io]
opt-level = 3
[profile.release.package.futures-channel]
opt-level = 3
[profile.release.package.futures-sink]
opt-level = 3
[profile.release.package.futures-task]
opt-level = 3
[profile.release.package.futures-core]
opt-level = 3
[profile.release.package.hyper]
opt-level = 3
[profile.release.package.miniz_oxide]
@ -463,3 +473,19 @@ opt-level = 3
opt-level = 3
[profile.release.package.zstd-sys]
opt-level = 3
[profile.release.package.http]
opt-level = 3
[profile.release.package.http-body]
opt-level = 3
[profile.release.package.httparse]
opt-level = 3
[profile.release.package.mio]
opt-level = 3
[profile.release.package.fnv]
opt-level = 3
[profile.release.package.hyper-util]
opt-level = 3
[profile.release.package.httpdate]
opt-level = 3
[profile.release.package.deno_unsync]
opt-level = 3

View file

@ -11,7 +11,9 @@ repository.workspace = true
description = "HTTP server implementation for Deno"
[features]
default = ["default_property_extractor"]
"__http_tracing" = []
default_property_extractor = []
[lib]
path = "lib.rs"

View file

@ -133,6 +133,7 @@ pub struct Options {
pub http1_builder_hook: Option<fn(http1::Builder) -> http1::Builder>,
}
#[cfg(not(feature = "default_property_extractor"))]
deno_core::extension!(
deno_http,
deps = [deno_web, deno_net, deno_fetch, deno_websocket],
@ -181,6 +182,54 @@ deno_core::extension!(
}
);
#[cfg(feature = "default_property_extractor")]
deno_core::extension!(
deno_http,
deps = [deno_web, deno_net, deno_fetch, deno_websocket],
ops = [
op_http_accept,
op_http_headers,
op_http_shutdown,
op_http_upgrade_websocket,
op_http_websocket_accept_header,
op_http_write_headers,
op_http_write_resource,
op_http_write,
http_next::op_http_close_after_finish,
http_next::op_http_get_request_header,
http_next::op_http_get_request_headers,
http_next::op_http_request_on_cancel,
http_next::op_http_get_request_method_and_url<DefaultHttpPropertyExtractor>,
http_next::op_http_get_request_cancelled,
http_next::op_http_read_request_body,
http_next::op_http_serve_on<DefaultHttpPropertyExtractor>,
http_next::op_http_serve<DefaultHttpPropertyExtractor>,
http_next::op_http_set_promise_complete,
http_next::op_http_set_response_body_bytes,
http_next::op_http_set_response_body_resource,
http_next::op_http_set_response_body_text,
http_next::op_http_set_response_header,
http_next::op_http_set_response_headers,
http_next::op_http_set_response_trailers,
http_next::op_http_upgrade_websocket_next,
http_next::op_http_upgrade_raw,
http_next::op_raw_write_vectored,
http_next::op_can_write_vectored,
http_next::op_http_try_wait,
http_next::op_http_wait,
http_next::op_http_close,
http_next::op_http_cancel,
http_next::op_http_metric_handle_otel_error,
],
esm = ["00_serve.ts", "01_http.js", "02_websocket.ts"],
options = {
options: Options,
},
state = |state, options| {
state.put::<Options>(options.options);
}
);
#[derive(Debug, thiserror::Error, deno_error::JsError)]
pub enum HttpError {
#[class(inherit)]

View file

@ -8,7 +8,6 @@ use std::sync::Arc;
use deno_core::snapshot::*;
use deno_core::v8;
use deno_core::Extension;
use deno_http::DefaultHttpPropertyExtractor;
use deno_resolver::npm::DenoInNpmPackageChecker;
use deno_resolver::npm::NpmResolver;
@ -61,9 +60,7 @@ pub fn create_runtime_snapshot(
deno_cron::local::LocalCronHandler::new(),
),
deno_napi::deno_napi::init_ops_and_esm::<Permissions>(),
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
deno_http::Options::default(),
),
deno_http::deno_http::init_ops_and_esm(deno_http::Options::default()),
deno_io::deno_io::init_ops_and_esm(Default::default()),
deno_fs::deno_fs::init_ops_and_esm::<Permissions>(fs.clone()),
deno_os::deno_os::init_ops_and_esm(Default::default()),

View file

@ -6,7 +6,6 @@ use std::path::PathBuf;
use std::sync::Arc;
use deno_core::Extension;
use deno_http::DefaultHttpPropertyExtractor;
use deno_io::fs::FsError;
use deno_permissions::PermissionCheckError;
use deno_resolver::npm::DenoInNpmPackageChecker;
@ -293,9 +292,7 @@ pub fn get_extensions_in_snapshot() -> Vec<Extension> {
),
deno_cron::deno_cron::init_ops(deno_cron::local::LocalCronHandler::new()),
deno_napi::deno_napi::init_ops::<Permissions>(),
deno_http::deno_http::init_ops::<DefaultHttpPropertyExtractor>(
deno_http::Options::default(),
),
deno_http::deno_http::init_ops(deno_http::Options::default()),
deno_io::deno_io::init_ops(Some(Default::default())),
deno_fs::deno_fs::init_ops::<Permissions>(fs.clone()),
deno_os::deno_os::init_ops(Default::default()),

View file

@ -39,7 +39,6 @@ use deno_core::RuntimeOptions;
use deno_core::SharedArrayBufferStore;
use deno_cron::local::LocalCronHandler;
use deno_fs::FileSystem;
use deno_http::DefaultHttpPropertyExtractor;
use deno_io::Stdio;
use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::ExtNodeSys;
@ -549,9 +548,7 @@ impl WebWorker {
),
deno_cron::deno_cron::init_ops_and_esm(LocalCronHandler::new()),
deno_napi::deno_napi::init_ops_and_esm::<PermissionsContainer>(),
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
deno_http::Options::default(),
),
deno_http::deno_http::init_ops_and_esm(deno_http::Options::default()),
deno_io::deno_io::init_ops_and_esm(Some(options.stdio)),
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
services.fs.clone(),

View file

@ -34,7 +34,6 @@ use deno_core::SharedArrayBufferStore;
use deno_core::SourceCodeCacheInfo;
use deno_cron::local::LocalCronHandler;
use deno_fs::FileSystem;
use deno_http::DefaultHttpPropertyExtractor;
use deno_io::Stdio;
use deno_kv::dynamic::MultiBackendDbHandler;
use deno_node::ExtNodeSys;
@ -449,9 +448,7 @@ impl MainWorker {
),
deno_cron::deno_cron::init_ops_and_esm(LocalCronHandler::new()),
deno_napi::deno_napi::init_ops_and_esm::<PermissionsContainer>(),
deno_http::deno_http::init_ops_and_esm::<DefaultHttpPropertyExtractor>(
deno_http::Options::default(),
),
deno_http::deno_http::init_ops_and_esm(deno_http::Options::default()),
deno_io::deno_io::init_ops_and_esm(Some(options.stdio)),
deno_fs::deno_fs::init_ops_and_esm::<PermissionsContainer>(
services.fs.clone(),
@ -563,12 +560,12 @@ impl MainWorker {
hasher.finish()
};
let data = cache
.get_sync(specifier, CodeCacheType::Script, source_hash)
.inspect(|_| {
// This log line is also used by tests.
log::debug!("V8 code cache hit for script: {specifier}, [{source_hash}]");
})
.map(Cow::Owned);
.get_sync(specifier, CodeCacheType::Script, source_hash)
.inspect(|_| {
// This log line is also used by tests.
log::debug!("V8 code cache hit for script: {specifier}, [{source_hash}]");
})
.map(Cow::Owned);
Ok(SourceCodeCacheInfo {
data,
hash: source_hash,