GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — src: report idle time correctly · nodejs/node@6aa1ed2

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • src
    • api
      • callback.cc
    • env.cc
    • env.h
  • test/parallel
    • test-inspector-has-idle.js
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/api/callback.cc‎

Copy file name to clipboardExpand all lines: src/api/callback.cc
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ InternalCallbackScope::InternalCallbackScope(Environment* env,
6161
// If you hit this assertion, you forgot to enter the v8::Context first.
6262
CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
6363

64+
env->isolate()->SetIdle(false);
65+
6466
env->async_hooks()->push_async_context(
6567
async_context_.async_id, async_context_.trigger_async_id, object);
6668

@@ -82,6 +84,8 @@ void InternalCallbackScope::Close() {
8284
if (closed_) return;
8385
closed_ = true;
8486

87+
auto idle = OnScopeLeave([&]() { env_->isolate()->SetIdle(true); });
88+
8589
if (!env_->can_call_into_js()) return;
8690
auto perform_stopping_check = [&]() {
8791
if (env_->is_stopping()) {
Collapse file

‎src/env.cc‎

Copy file name to clipboardExpand all lines: src/env.cc
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,13 @@ void Environment::InitializeLibuv() {
495495

496496
uv_check_start(immediate_check_handle(), CheckImmediate);
497497

498+
// Inform V8's CPU profiler when we're idle. The profiler is sampling-based
499+
// but not all samples are created equal; mark the wall clock time spent in
500+
// epoll_wait() and friends so profiling tools can filter it out. The samples
501+
// still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
502+
uv_prepare_init(event_loop(), &idle_prepare_handle_);
503+
uv_check_init(event_loop(), &idle_check_handle_);
504+
498505
uv_async_init(
499506
event_loop(),
500507
&task_queues_async_,
@@ -505,6 +512,8 @@ void Environment::InitializeLibuv() {
505512
Context::Scope context_scope(env->context());
506513
env->RunAndClearNativeImmediates();
507514
});
515+
uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
516+
uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
508517
uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
509518

510519
{
@@ -521,6 +530,8 @@ void Environment::InitializeLibuv() {
521530
// the one environment per process setup, but will be called in
522531
// FreeEnvironment.
523532
RegisterHandleCleanups();
533+
534+
StartProfilerIdleNotifier();
524535
}
525536

526537
void Environment::ExitEnv() {
@@ -548,6 +559,8 @@ void Environment::RegisterHandleCleanups() {
548559
register_handle(reinterpret_cast<uv_handle_t*>(timer_handle()));
549560
register_handle(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
550561
register_handle(reinterpret_cast<uv_handle_t*>(immediate_idle_handle()));
562+
register_handle(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
563+
register_handle(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
551564
register_handle(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
552565
}
553566

@@ -579,6 +592,17 @@ void Environment::CleanupHandles() {
579592
}
580593
}
581594

595+
void Environment::StartProfilerIdleNotifier() {
596+
uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
597+
Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
598+
env->isolate()->SetIdle(true);
599+
});
600+
uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
601+
Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
602+
env->isolate()->SetIdle(false);
603+
});
604+
}
605+
582606
void Environment::PrintSyncTrace() const {
583607
if (!trace_sync_io_) return;
584608

Collapse file

‎src/env.h‎

Copy file name to clipboardExpand all lines: src/env.h
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,8 @@ class Environment : public MemoryRetainer {
919919
inline void AssignToContext(v8::Local<v8::Context> context,
920920
const ContextInfo& info);
921921

922+
void StartProfilerIdleNotifier();
923+
922924
inline v8::Isolate* isolate() const;
923925
inline uv_loop_t* event_loop() const;
924926
inline void TryLoadAddon(
@@ -1252,6 +1254,8 @@ class Environment : public MemoryRetainer {
12521254
uv_timer_t timer_handle_;
12531255
uv_check_t immediate_check_handle_;
12541256
uv_idle_t immediate_idle_handle_;
1257+
uv_prepare_t idle_prepare_handle_;
1258+
uv_check_t idle_check_handle_;
12551259
uv_async_t task_queues_async_;
12561260
int64_t task_queues_async_refs_ = 0;
12571261

Collapse file

‎test/parallel/test-inspector-has-idle.js‎

Copy file name to clipboard
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
common.skipIfInspectorDisabled();
5+
6+
const assert = require('assert');
7+
const { Session } = require('inspector');
8+
const { promisify } = require('util');
9+
10+
const sleep = promisify(setTimeout);
11+
12+
async function test() {
13+
const inspector = new Session();
14+
inspector.connect();
15+
16+
inspector.post('Profiler.enable');
17+
inspector.post('Profiler.start');
18+
19+
await sleep(1000);
20+
21+
const { profile } = await new Promise((resolve, reject) => {
22+
inspector.post('Profiler.stop', (err, params) => {
23+
if (err) return reject(err);
24+
resolve(params);
25+
});
26+
});
27+
28+
let hasIdle = false;
29+
for (const node of profile.nodes) {
30+
if (node.callFrame.functionName === '(idle)') {
31+
hasIdle = true;
32+
break;
33+
}
34+
}
35+
assert(hasIdle);
36+
37+
inspector.post('Profiler.disable');
38+
inspector.disconnect();
39+
}
40+
41+
test().then(common.mustCall(() => {
42+
console.log('Done!');
43+
}));

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.