summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <lucacasonato@yahoo.com>2021-02-21 19:20:31 +0100
committerGitHub <noreply@github.com>2021-02-21 19:20:31 +0100
commit9d70ea2e9f03d7c12407f117cf11d2a99d55c8f8 (patch)
treeaf9699876b632ac452d0cd6214647cb3598eaec6
parentaf93256d05993b53debe0552828b6ae7df521750 (diff)
feat(unstable): per op metrics (#9240)
-rw-r--r--cli/dts/lib.deno.unstable.d.ts24
-rw-r--r--cli/ops/mod.rs4
-rw-r--r--cli/tests/unit/metrics_test.ts28
-rw-r--r--runtime/js/30_metrics.js6
-rw-r--r--runtime/metrics.rs52
-rw-r--r--runtime/ops/io.rs4
-rw-r--r--runtime/ops/mod.rs4
-rw-r--r--runtime/ops/plugin.rs11
-rw-r--r--runtime/ops/runtime.rs27
-rw-r--r--runtime/ops/timers.rs2
-rw-r--r--runtime/web_worker.rs6
-rw-r--r--runtime/worker.rs6
12 files changed, 122 insertions, 52 deletions
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts
index 1632d03be..a9353e2ff 100644
--- a/cli/dts/lib.deno.unstable.d.ts
+++ b/cli/dts/lib.deno.unstable.d.ts
@@ -850,13 +850,13 @@ declare namespace Deno {
| "TXT";
export interface ResolveDnsOptions {
- /** The name server to be used for lookups.
- * If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
+ /** The name server to be used for lookups.
+ * If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
nameServer?: {
/** The IP address of the name server */
ipAddr: string;
/** The port number the query will be sent to.
- * If not specified, defaults to 53. */
+ * If not specified, defaults to 53. */
port?: number;
};
}
@@ -1343,6 +1343,24 @@ declare namespace Deno {
* ```
*/
export function sleepSync(millis: number): Promise<void>;
+
+ export interface Metrics extends OpMetrics {
+ ops: Record<string, OpMetrics>;
+ }
+
+ export interface OpMetrics {
+ opsDispatched: number;
+ opsDispatchedSync: number;
+ opsDispatchedAsync: number;
+ opsDispatchedAsyncUnref: number;
+ opsCompleted: number;
+ opsCompletedSync: number;
+ opsCompletedAsync: number;
+ opsCompletedAsyncUnref: number;
+ bytesSentControl: number;
+ bytesSentData: number;
+ bytesReceived: number;
+ }
}
declare function fetch(
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs
index c46c5cd20..e47722198 100644
--- a/cli/ops/mod.rs
+++ b/cli/ops/mod.rs
@@ -21,7 +21,7 @@ where
F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
R: Future<Output = Result<Value, AnyError>> + 'static,
{
- rt.register_op(name, metrics_op(json_op_async(op_fn)));
+ rt.register_op(name, metrics_op(name, json_op_async(op_fn)));
}
pub fn reg_json_sync<F>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
@@ -29,5 +29,5 @@ where
F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, AnyError>
+ 'static,
{
- rt.register_op(name, metrics_op(json_op_sync(op_fn)));
+ rt.register_op(name, metrics_op(name, json_op_sync(op_fn)));
}
diff --git a/cli/tests/unit/metrics_test.ts b/cli/tests/unit/metrics_test.ts
index a60aae427..2f12ac90d 100644
--- a/cli/tests/unit/metrics_test.ts
+++ b/cli/tests/unit/metrics_test.ts
@@ -2,30 +2,40 @@
import { assert, unitTest } from "./test_util.ts";
unitTest(async function metrics(): Promise<void> {
+ // Write to stdout to ensure a "data" message gets sent instead of just
+ // control messages.
+ const dataMsg = new Uint8Array([13, 13, 13]); // "\r\r\r",
+ await Deno.stdout.write(dataMsg);
+
const m1 = Deno.metrics();
assert(m1.opsDispatched > 0);
- assert(m1.opsDispatchedSync > 0);
assert(m1.opsCompleted > 0);
- assert(m1.opsCompletedSync > 0);
assert(m1.bytesSentControl > 0);
assert(m1.bytesSentData >= 0);
assert(m1.bytesReceived > 0);
+ const m1OpWrite = m1.ops["op_write"];
+ assert(m1OpWrite.opsDispatchedAsync > 0);
+ assert(m1OpWrite.opsCompletedAsync > 0);
+ assert(m1OpWrite.bytesSentControl > 0);
+ assert(m1OpWrite.bytesSentData >= 0);
+ assert(m1OpWrite.bytesReceived > 0);
- // Write to stdout to ensure a "data" message gets sent instead of just
- // control messages.
- const dataMsg = new Uint8Array([13, 13, 13]); // "\r\r\r",
await Deno.stdout.write(dataMsg);
const m2 = Deno.metrics();
- assert(m2.opsDispatched > m1.opsDispatched);
- assert(m2.opsDispatchedSync > m1.opsDispatchedSync);
assert(m2.opsDispatchedAsync > m1.opsDispatchedAsync);
- assert(m2.opsCompleted > m1.opsCompleted);
- assert(m2.opsCompletedSync > m1.opsCompletedSync);
assert(m2.opsCompletedAsync > m1.opsCompletedAsync);
assert(m2.bytesSentControl > m1.bytesSentControl);
assert(m2.bytesSentData >= m1.bytesSentData + dataMsg.byteLength);
assert(m2.bytesReceived > m1.bytesReceived);
+ const m2OpWrite = m2.ops["op_write"];
+ assert(m2OpWrite.opsDispatchedAsync > m1OpWrite.opsDispatchedAsync);
+ assert(m2OpWrite.opsCompletedAsync > m1OpWrite.opsCompletedAsync);
+ assert(m2OpWrite.bytesSentControl > m1OpWrite.bytesSentControl);
+ assert(
+ m2OpWrite.bytesSentData >= m1OpWrite.bytesSentData + dataMsg.byteLength,
+ );
+ assert(m2OpWrite.bytesReceived > m1OpWrite.bytesReceived);
});
unitTest(
diff --git a/runtime/js/30_metrics.js b/runtime/js/30_metrics.js
index 30fa7cf80..ed062fce3 100644
--- a/runtime/js/30_metrics.js
+++ b/runtime/js/30_metrics.js
@@ -5,7 +5,11 @@
const core = window.Deno.core;
function metrics() {
- return core.jsonOpSync("op_metrics");
+ const { combined, ops } = core.jsonOpSync("op_metrics");
+ if (ops) {
+ combined.ops = ops;
+ }
+ return combined;
}
window.__bootstrap.metrics = {
diff --git a/runtime/metrics.rs b/runtime/metrics.rs
index b609f2466..58924f0cb 100644
--- a/runtime/metrics.rs
+++ b/runtime/metrics.rs
@@ -1,6 +1,36 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+use serde::Serialize;
+
#[derive(Default, Debug)]
-pub struct Metrics {
+pub struct RuntimeMetrics {
+ pub ops: HashMap<&'static str, OpMetrics>,
+}
+
+impl RuntimeMetrics {
+ pub fn combined_metrics(&self) -> OpMetrics {
+ let mut total = OpMetrics::default();
+
+ for metrics in self.ops.values() {
+ total.ops_dispatched += metrics.ops_dispatched;
+ total.ops_dispatched_sync += metrics.ops_dispatched_sync;
+ total.ops_dispatched_async += metrics.ops_dispatched_async;
+ total.ops_dispatched_async_unref += metrics.ops_dispatched_async_unref;
+ total.ops_completed += metrics.ops_completed;
+ total.ops_completed_sync += metrics.ops_completed_sync;
+ total.ops_completed_async += metrics.ops_completed_async;
+ total.ops_completed_async_unref += metrics.ops_completed_async_unref;
+ total.bytes_sent_control += metrics.bytes_sent_control;
+ total.bytes_sent_data += metrics.bytes_sent_data;
+ total.bytes_received += metrics.bytes_received;
+ }
+
+ total
+ }
+}
+
+#[derive(Default, Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct OpMetrics {
pub ops_dispatched: u64,
pub ops_dispatched_sync: u64,
pub ops_dispatched_async: u64,
@@ -14,7 +44,7 @@ pub struct Metrics {
pub bytes_received: u64,
}
-impl Metrics {
+impl OpMetrics {
fn op_dispatched(
&mut self,
bytes_sent_control: usize,
@@ -76,9 +106,10 @@ use deno_core::Op;
use deno_core::OpFn;
use deno_core::OpState;
use std::cell::RefCell;
+use std::collections::HashMap;
use std::rc::Rc;
-pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
+pub fn metrics_op(name: &'static str, op_fn: Box<OpFn>) -> Box<OpFn> {
Box::new(move |op_state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
// TODOs:
// * The 'bytes' metrics seem pretty useless, especially now that the
@@ -94,7 +125,14 @@ pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
let op_state_ = op_state.clone();
let mut s = op_state.borrow_mut();
- let metrics = s.borrow_mut::<Metrics>();
+ let runtime_metrics = s.borrow_mut::<RuntimeMetrics>();
+
+ let metrics = if let Some(metrics) = runtime_metrics.ops.get_mut(name) {
+ metrics
+ } else {
+ runtime_metrics.ops.insert(name, OpMetrics::default());
+ runtime_metrics.ops.get_mut(name).unwrap()
+ };
use deno_core::futures::future::FutureExt;
@@ -108,7 +146,8 @@ pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
let fut = fut
.inspect(move |buf| {
let mut s = op_state_.borrow_mut();
- let metrics = s.borrow_mut::<Metrics>();
+ let runtime_metrics = s.borrow_mut::<RuntimeMetrics>();
+ let metrics = runtime_metrics.ops.get_mut(name).unwrap();
metrics.op_completed_async(buf.len());
})
.boxed_local();
@@ -119,7 +158,8 @@ pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
let fut = fut
.inspect(move |buf| {
let mut s = op_state_.borrow_mut();
- let metrics = s.borrow_mut::<Metrics>();
+ let runtime_metrics = s.borrow_mut::<RuntimeMetrics>();
+ let metrics = runtime_metrics.ops.get_mut(name).unwrap();
metrics.op_completed_async_unref(buf.len());
})
.boxed_local();
diff --git a/runtime/ops/io.rs b/runtime/ops/io.rs
index 2ac8e1b78..bda8a51cb 100644
--- a/runtime/ops/io.rs
+++ b/runtime/ops/io.rs
@@ -105,8 +105,8 @@ lazy_static! {
}
pub fn init(rt: &mut JsRuntime) {
- rt.register_op("op_read", metrics_op(minimal_op(op_read)));
- rt.register_op("op_write", metrics_op(minimal_op(op_write)));
+ rt.register_op("op_read", metrics_op("op_read", minimal_op(op_read)));
+ rt.register_op("op_write", metrics_op("op_write", minimal_op(op_write)));
super::reg_json_async(rt, "op_shutdown", op_shutdown);
}
diff --git a/runtime/ops/mod.rs b/runtime/ops/mod.rs
index 3ead7efa2..e5dba723a 100644
--- a/runtime/ops/mod.rs
+++ b/runtime/ops/mod.rs
@@ -48,7 +48,7 @@ pub fn reg_json_async<F, V, R, RV>(
R: Future<Output = Result<RV, AnyError>> + 'static,
RV: Serialize,
{
- rt.register_op(name, metrics_op(json_op_async(op_fn)));
+ rt.register_op(name, metrics_op(name, json_op_async(op_fn)));
}
pub fn reg_json_sync<F, V, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
@@ -57,7 +57,7 @@ where
V: DeserializeOwned,
R: Serialize,
{
- rt.register_op(name, metrics_op(json_op_sync(op_fn)));
+ rt.register_op(name, metrics_op(name, json_op_sync(op_fn)));
}
/// `UnstableChecker` is a struct so it can be placed inside `GothamState`;
diff --git a/runtime/ops/plugin.rs b/runtime/ops/plugin.rs
index e972df046..424b1dca0 100644
--- a/runtime/ops/plugin.rs
+++ b/runtime/ops/plugin.rs
@@ -126,10 +126,13 @@ impl<'a> plugin_api::Interface for PluginInterface<'a> {
_ => unreachable!(),
}
};
- self
- .state
- .op_table
- .register_op(name, metrics_op(Box::new(plugin_op_fn)))
+ self.state.op_table.register_op(
+ name,
+ metrics_op(
+ Box::leak(Box::new(name.to_string())),
+ Box::new(plugin_op_fn),
+ ),
+ )
}
}
diff --git a/runtime/ops/runtime.rs b/runtime/ops/runtime.rs
index 77abc45b7..a2f377bed 100644
--- a/runtime/ops/runtime.rs
+++ b/runtime/ops/runtime.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
-use crate::metrics::Metrics;
+use crate::metrics::RuntimeMetrics;
+use crate::ops::UnstableChecker;
use crate::permissions::Permissions;
use deno_core::error::AnyError;
use deno_core::serde_json;
@@ -42,21 +43,15 @@ fn op_metrics(
_args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> {
- let m = state.borrow::<Metrics>();
-
- Ok(json!({
- "opsDispatched": m.ops_dispatched,
- "opsDispatchedSync": m.ops_dispatched_sync,
- "opsDispatchedAsync": m.ops_dispatched_async,
- "opsDispatchedAsyncUnref": m.ops_dispatched_async_unref,
- "opsCompleted": m.ops_completed,
- "opsCompletedSync": m.ops_completed_sync,
- "opsCompletedAsync": m.ops_completed_async,
- "opsCompletedAsyncUnref": m.ops_completed_async_unref,
- "bytesSentControl": m.bytes_sent_control,
- "bytesSentData": m.bytes_sent_data,
- "bytesReceived": m.bytes_received
- }))
+ let m = state.borrow::<RuntimeMetrics>();
+ let combined = m.combined_metrics();
+ let unstable_checker = state.borrow::<UnstableChecker>();
+ let maybe_ops = if unstable_checker.unstable {
+ Some(&m.ops)
+ } else {
+ None
+ };
+ Ok(json!({ "combined": combined, "ops": maybe_ops }))
}
pub fn ppid() -> Value {
diff --git a/runtime/ops/timers.rs b/runtime/ops/timers.rs
index a00b04ed0..783395cad 100644
--- a/runtime/ops/timers.rs
+++ b/runtime/ops/timers.rs
@@ -81,7 +81,7 @@ pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
super::reg_json_sync(rt, "op_global_timer_start", op_global_timer_start);
super::reg_json_async(rt, "op_global_timer", op_global_timer);
- rt.register_op("op_now", metrics_op(minimal_op(op_now)));
+ rt.register_op("op_now", metrics_op("op_now", minimal_op(op_now)));
super::reg_json_sync(rt, "op_sleep_sync", op_sleep_sync);
}
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index 0847059ac..082cf7267 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -4,7 +4,7 @@ use crate::colors;
use crate::inspector::DenoInspector;
use crate::inspector::InspectorServer;
use crate::js;
-use crate::metrics::Metrics;
+use crate::metrics::RuntimeMetrics;
use crate::ops;
use crate::permissions::Permissions;
use crate::tokio_util::create_basic_runtime;
@@ -209,9 +209,9 @@ impl WebWorker {
{
let op_state = js_runtime.op_state();
let mut op_state = op_state.borrow_mut();
- op_state.put::<Metrics>(Default::default());
+ op_state.put(RuntimeMetrics::default());
op_state.put::<Permissions>(permissions);
- op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
+ op_state.put(ops::UnstableChecker {
unstable: options.unstable,
});
}
diff --git a/runtime/worker.rs b/runtime/worker.rs
index dca01932d..0b3fe3e10 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -4,7 +4,7 @@ use crate::inspector::DenoInspector;
use crate::inspector::InspectorServer;
use crate::inspector::InspectorSession;
use crate::js;
-use crate::metrics::Metrics;
+use crate::metrics::RuntimeMetrics;
use crate::ops;
use crate::permissions::Permissions;
use deno_core::error::AnyError;
@@ -104,9 +104,9 @@ impl MainWorker {
{
let op_state = js_runtime.op_state();
let mut op_state = op_state.borrow_mut();
- op_state.put::<Metrics>(Default::default());
+ op_state.put(RuntimeMetrics::default());
op_state.put::<Permissions>(permissions);
- op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
+ op_state.put(ops::UnstableChecker {
unstable: options.unstable,
});
}