diff options
author | James M Snell <jasnell@gmail.com> | 2021-01-29 03:34:27 +0300 |
---|---|---|
committer | James M Snell <jasnell@gmail.com> | 2021-02-22 19:46:11 +0300 |
commit | f3eb224c83f96cff9231f17b1c0a36b762942f48 (patch) | |
tree | 42b62cc1122ef355a47cfe49780a34465887810b /src/node_http2.cc | |
parent | 9f2efaa6f3878509a053a5aa9dab7b1b96d2add3 (diff) |
perf_hooks: complete overhaul of the implementation
* Update the user timing implementation to conform to
User Timing Level 3.
* Reimplement user timing and timerify with pure JavaScript
implementations
* Simplify the C++ implementation for gc and http2 perf
* Runtime deprecate additional perf entry properties
in favor of the standard detail argument
* Disable the `buffered` option on PerformanceObserver,
all entries are queued and dispatched on setImmediate.
Only entries with active observers are buffered.
* This does remove the user timing and timerify
trace events. Because the trace_events are still
considered experimental, those can be removed without
a deprecation cycle. They are removed to improve
performance and reduce complexity.
Old: `perf_hooks/usertiming.js n=100000: 92,378.01249733355`
New: perf_hooks/usertiming.js n=100000: 270,393.5280638482`
PR-URL: https://github.com/nodejs/node/pull/37136
Refs: https://github.com/nodejs/diagnostics/issues/464
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Diffstat (limited to 'src/node_http2.cc')
-rw-r--r-- | src/node_http2.cc | 161 |
1 files changed, 106 insertions, 55 deletions
diff --git a/src/node_http2.cc b/src/node_http2.cc index ccff6dc4ca6..112a3a336e0 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -40,7 +40,6 @@ using v8::Uint8Array; using v8::Undefined; using v8::Value; -using node::performance::PerformanceEntry; namespace http2 { namespace { @@ -466,6 +465,7 @@ Http2Session::Http2Session(Http2State* http2_state, session_type_(type), http2_state_(http2_state) { MakeWeak(); + statistics_.session_type = type; statistics_.start_time = uv_hrtime(); // Capture the configuration options for this session @@ -541,71 +541,121 @@ std::string Http2Session::diagnostic_name() const { std::to_string(static_cast<int64_t>(get_async_id())) + ")"; } +MaybeLocal<Object> Http2StreamPerformanceEntryTraits::GetDetails( + Environment* env, + const Http2StreamPerformanceEntry& entry) { + Local<Object> obj = Object::New(env->isolate()); + +#define SET(name, val) \ + if (!obj->Set( \ + env->context(), \ + env->name(), \ + Number::New( \ + env->isolate(), \ + static_cast<double>(entry.details.val))).IsJust()) { \ + return MaybeLocal<Object>(); \ + } + + SET(bytes_read_string, received_bytes) + SET(bytes_written_string, sent_bytes) + SET(id_string, id) +#undef SET + +#define SET(name, val) \ + if (!obj->Set( \ + env->context(), \ + env->name(), \ + Number::New( \ + env->isolate(), \ + (entry.details.val - entry.details.start_time) / 1e6)) \ + .IsJust()) { \ + return MaybeLocal<Object>(); \ + } + + SET(time_to_first_byte_string, first_byte) + SET(time_to_first_byte_sent_string, first_byte_sent) + SET(time_to_first_header_string, first_header) +#undef SET + + return obj; +} + +MaybeLocal<Object> Http2SessionPerformanceEntryTraits::GetDetails( + Environment* env, + const Http2SessionPerformanceEntry& entry) { + Local<Object> obj = Object::New(env->isolate()); + +#define SET(name, val) \ + if (!obj->Set( \ + env->context(), \ + env->name(), \ + Number::New( \ + env->isolate(), \ + static_cast<double>(entry.details.val))).IsJust()) { \ + return MaybeLocal<Object>(); \ + } + + SET(bytes_written_string, data_sent) + SET(bytes_read_string, data_received) + SET(frames_received_string, frame_count) + SET(frames_sent_string, frame_sent) + SET(max_concurrent_streams_string, max_concurrent_streams) + SET(ping_rtt_string, ping_rtt) + SET(stream_average_duration_string, stream_average_duration) + SET(stream_count_string, stream_count) + + if (!obj->Set( + env->context(), + env->type_string(), + OneByteString( + env->isolate(), + (entry.details.session_type == NGHTTP2_SESSION_SERVER) + ? "server" : "client")).IsJust()) { + return MaybeLocal<Object>(); + } + +#undef SET + return obj; +} + void Http2Stream::EmitStatistics() { CHECK_NOT_NULL(session()); - if (!HasHttp2Observer(env())) + if (LIKELY(!HasHttp2Observer(env()))) return; - auto entry = + + double start = statistics_.start_time / 1e6; + double duration = (PERFORMANCE_NOW() / 1e6) - start; + + std::unique_ptr<Http2StreamPerformanceEntry> entry = std::make_unique<Http2StreamPerformanceEntry>( - session()->http2_state(), id_, statistics_); + "Http2Stream", + start, + duration, + statistics_); + env()->SetImmediate([entry = move(entry)](Environment* env) { - if (!HasHttp2Observer(env)) - return; - HandleScope handle_scope(env->isolate()); - AliasedFloat64Array& buffer = entry->http2_state()->stream_stats_buffer; - buffer[IDX_STREAM_STATS_ID] = entry->id(); - if (entry->first_byte() != 0) { - buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTE] = - (entry->first_byte() - entry->startTimeNano()) / 1e6; - } else { - buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTE] = 0; - } - if (entry->first_header() != 0) { - buffer[IDX_STREAM_STATS_TIMETOFIRSTHEADER] = - (entry->first_header() - entry->startTimeNano()) / 1e6; - } else { - buffer[IDX_STREAM_STATS_TIMETOFIRSTHEADER] = 0; - } - if (entry->first_byte_sent() != 0) { - buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTESENT] = - (entry->first_byte_sent() - entry->startTimeNano()) / 1e6; - } else { - buffer[IDX_STREAM_STATS_TIMETOFIRSTBYTESENT] = 0; - } - buffer[IDX_STREAM_STATS_SENTBYTES] = - static_cast<double>(entry->sent_bytes()); - buffer[IDX_STREAM_STATS_RECEIVEDBYTES] = - static_cast<double>(entry->received_bytes()); - Local<Object> obj; - if (entry->ToObject().ToLocal(&obj)) entry->Notify(obj); + if (HasHttp2Observer(env)) + entry->Notify(env); }); } void Http2Session::EmitStatistics() { - if (!HasHttp2Observer(env())) + if (LIKELY(!HasHttp2Observer(env()))) return; - auto entry = std::make_unique<Http2SessionPerformanceEntry>( - http2_state(), statistics_, session_type_); + + double start = statistics_.start_time / 1e6; + double duration = (PERFORMANCE_NOW() / 1e6) - start; + + std::unique_ptr<Http2SessionPerformanceEntry> entry = + std::make_unique<Http2SessionPerformanceEntry>( + "Http2Session", + start, + duration, + statistics_); + env()->SetImmediate([entry = std::move(entry)](Environment* env) { - if (!HasHttp2Observer(env)) - return; - HandleScope handle_scope(env->isolate()); - AliasedFloat64Array& buffer = entry->http2_state()->session_stats_buffer; - buffer[IDX_SESSION_STATS_TYPE] = entry->type(); - buffer[IDX_SESSION_STATS_PINGRTT] = entry->ping_rtt() / 1e6; - buffer[IDX_SESSION_STATS_FRAMESRECEIVED] = entry->frame_count(); - buffer[IDX_SESSION_STATS_FRAMESSENT] = entry->frame_sent(); - buffer[IDX_SESSION_STATS_STREAMCOUNT] = entry->stream_count(); - buffer[IDX_SESSION_STATS_STREAMAVERAGEDURATION] = - entry->stream_average_duration(); - buffer[IDX_SESSION_STATS_DATA_SENT] = - static_cast<double>(entry->data_sent()); - buffer[IDX_SESSION_STATS_DATA_RECEIVED] = - static_cast<double>(entry->data_received()); - buffer[IDX_SESSION_STATS_MAX_CONCURRENT_STREAMS] = - static_cast<double>(entry->max_concurrent_streams()); - Local<Object> obj; - if (entry->ToObject().ToLocal(&obj)) entry->Notify(obj); + if (HasHttp2Observer(env)) + entry->Notify(env); }); } @@ -1884,6 +1934,7 @@ Http2Stream::Http2Stream(Http2Session* session, current_headers_category_(category) { MakeWeak(); StreamBase::AttachToObject(GetObject()); + statistics_.id = id; statistics_.start_time = uv_hrtime(); // Limit the number of header pairs |