Skip to content

Commit

Permalink
v8: implement v8.stopCoverage()
Browse files Browse the repository at this point in the history
Add a v8.stopCoverage() API to stop the coverage collection
started by NODE_V8_COVERAGE - this would be useful in
conjunction with v8.takeCoverage() if the user don't want
to emit the coverage at the process exit but still want
to collect it on demand at some point.

PR-URL: nodejs#33807
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Ben Coe <bencoe@gmail.com>
  • Loading branch information
joyeecheung authored and gengjiawen committed Oct 22, 2020
1 parent fc5636e commit 7945a2c
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 2 deletions.
16 changes: 14 additions & 2 deletions doc/api/v8.md
Expand Up @@ -227,7 +227,18 @@ be reset and a new coverage report will be written to the directory specified
by [`NODE_V8_COVERAGE`][].

When the process is about to exit, one last coverage will still be written to
disk.
disk, unless [`v8.stopCoverage()`][] is invoked before the process exits.

## `v8.stopCoverage()`

<!-- YAML
added: REPLACEME
-->

The `v8.stopCoverage()` method allows the user to stop the coverage collection
started by [`NODE_V8_COVERAGE`][], so that V8 can release the execution count
records and optimize code. This can be used in conjunction with
`v8.takeCoverage()` if the user wants to collect the coverage on demand.

## `v8.writeHeapSnapshot([filename])`
<!-- YAML
Expand Down Expand Up @@ -526,7 +537,7 @@ A subclass of [`Deserializer`][] corresponding to the format written by
[`Deserializer`]: #v8_class_v8_deserializer
[`Error`]: errors.md#errors_class_error
[`GetHeapSpaceStatistics`]: https://v8docs.nodesource.com/node-13.2/d5/dda/classv8_1_1_isolate.html#ac673576f24fdc7a33378f8f57e1d13a4
[`NODE_V8_COVERAGE`]: cli.html#cli_node_v8_coverage_dir
[`NODE_V8_COVERAGE`]: cli.md#cli_node_v8_coverage_dir
[`Serializer`]: #v8_class_v8_serializer
[`deserializer._readHostObject()`]: #v8_deserializer_readhostobject
[`deserializer.transferArrayBuffer()`]: #v8_deserializer_transferarraybuffer_id_arraybuffer
Expand All @@ -536,5 +547,6 @@ A subclass of [`Deserializer`][] corresponding to the format written by
[`serializer.releaseBuffer()`]: #v8_serializer_releasebuffer
[`serializer.transferArrayBuffer()`]: #v8_serializer_transferarraybuffer_id_arraybuffer
[`serializer.writeRawBytes()`]: #v8_serializer_writerawbytes_buffer
[`v8.stopCoverage()`]: #v8_v8_stopcoverage
[`vm.Script`]: vm.md#vm_new_vm_script_code_options
[worker threads]: worker_threads.md
1 change: 1 addition & 0 deletions lib/v8.js
Expand Up @@ -282,6 +282,7 @@ module.exports = {
DefaultDeserializer,
deserialize,
takeCoverage: profiler.takeCoverage,
stopCoverage: profiler.stopCoverage,
serialize,
writeHeapSnapshot,
};
20 changes: 20 additions & 0 deletions src/inspector_profiler.cc
Expand Up @@ -295,6 +295,10 @@ void V8CoverageConnection::TakeCoverage() {
DispatchMessage("Profiler.takePreciseCoverage", nullptr, true);
}

void V8CoverageConnection::StopCoverage() {
DispatchMessage("Profiler.stopPreciseCoverage");
}

void V8CoverageConnection::End() {
Debug(env_,
DebugCategory::INSPECTOR_PROFILER,
Expand Down Expand Up @@ -489,6 +493,21 @@ static void TakeCoverage(const FunctionCallbackInfo<Value>& args) {
}
}

static void StopCoverage(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
V8CoverageConnection* connection = env->coverage_connection();

Debug(env,
DebugCategory::INSPECTOR_PROFILER,
"StopCoverage, connection %s nullptr\n",
connection == nullptr ? "==" : "!=");

if (connection != nullptr) {
Debug(env, DebugCategory::INSPECTOR_PROFILER, "Stopping coverage\n");
connection->StopCoverage();
}
}

static void Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
Expand All @@ -497,6 +516,7 @@ static void Initialize(Local<Object> target,
env->SetMethod(target, "setCoverageDirectory", SetCoverageDirectory);
env->SetMethod(target, "setSourceMapCacheGetter", SetSourceMapCacheGetter);
env->SetMethod(target, "takeCoverage", TakeCoverage);
env->SetMethod(target, "stopCoverage", StopCoverage);
}

} // namespace profiler
Expand Down
1 change: 1 addition & 0 deletions src/inspector_profiler.h
Expand Up @@ -95,6 +95,7 @@ class V8CoverageConnection : public V8ProfilerConnection {
void WriteProfile(v8::Local<v8::Object> result) override;
void WriteSourceMapCache();
void TakeCoverage();
void StopCoverage();

private:
std::unique_ptr<inspector::InspectorSession> session_;
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/v8-coverage/stop-coverage.js
@@ -0,0 +1,3 @@
'use strict';
const v8 = require('v8');
v8.stopCoverage();
34 changes: 34 additions & 0 deletions test/parallel/test-v8-stop-coverage.js
@@ -0,0 +1,34 @@
'use strict';

if (!process.features.inspector) return;

require('../common');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const fs = require('fs');
const { spawnSync } = require('child_process');

tmpdir.refresh();
const intervals = 20;

{
const output = spawnSync(process.execPath, [
'-r',
fixtures.path('v8-coverage', 'stop-coverage'),
'-r',
fixtures.path('v8-coverage', 'take-coverage'),
fixtures.path('v8-coverage', 'interval'),
], {
env: {
...process.env,
NODE_V8_COVERAGE: tmpdir.path,
NODE_DEBUG_NATIVE: 'INSPECTOR_PROFILER',
TEST_INTERVALS: intervals
},
});
console.log(output.stderr.toString());
assert.strictEqual(output.status, 0);
const coverageFiles = fs.readdirSync(tmpdir.path);
assert.strictEqual(coverageFiles.length, 0);
}

0 comments on commit 7945a2c

Please sign in to comment.