Skip to content

Commit

Permalink
src: refactor V8ProfilerConnection::DispatchMessage()
Browse files Browse the repository at this point in the history
- Auto-generate the message id and return it for future use (we
  can always parse the response to find the message containing
  the profile instead of relying on the inspector connection being
  synchornous).
- Generate the message from method and parameter strings and create
  a `StringView` directly to avoid the unnecessary copy in
  `ToProtocolString()`.

PR-URL: nodejs#27535
Reviewed-By: Jan Krems <jan.krems@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
joyeecheung authored and Trott committed May 5, 2019
1 parent 3d98051 commit 0171bab
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 46 deletions.
74 changes: 29 additions & 45 deletions src/inspector_profiler.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "inspector_profiler.h"
#include <sstream>
#include "base_object-inl.h"
#include "debug_utils.h"
#include "node_file.h"
Expand Down Expand Up @@ -33,21 +34,34 @@ const char* const kPathSeparator = "/";
#define CWD_BUFSIZE (PATH_MAX)
#endif

std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
Local<Value> value) {
TwoByteValue buffer(isolate, value);
return StringBuffer::create(StringView(*buffer, buffer.length()));
}

V8ProfilerConnection::V8ProfilerConnection(Environment* env)
: session_(env->inspector_agent()->Connect(
std::make_unique<V8ProfilerConnection::V8ProfilerSessionDelegate>(
this),
false)),
env_(env) {}

void V8ProfilerConnection::DispatchMessage(Local<String> message) {
session_->Dispatch(ToProtocolString(env()->isolate(), message)->string());
size_t V8ProfilerConnection::DispatchMessage(const char* method,
const char* params) {
std::stringstream ss;
size_t id = next_id();
ss << R"({ "id": )" << id;
DCHECK(method != nullptr);
ss << R"(, "method": ")" << method << '"';
if (params != nullptr) {
ss << R"(, "params": )" << params;
}
ss << " }";
std::string message = ss.str();
const uint8_t* message_data =
reinterpret_cast<const uint8_t*>(message.c_str());
Debug(env(),
DebugCategory::INSPECTOR_PROFILER,
"Dispatching message %s\n",
message.c_str());
session_->Dispatch(StringView(message_data, message.length()));
// TODO(joyeecheung): use this to identify the ending message.
return id;
}

static void WriteResult(Environment* env,
Expand Down Expand Up @@ -202,34 +216,15 @@ std::string V8CoverageConnection::GetDirectory() const {
}

void V8CoverageConnection::Start() {
Debug(env(),
DebugCategory::INSPECTOR_PROFILER,
"Sending Profiler.startPreciseCoverage\n");
Isolate* isolate = env()->isolate();
Local<String> enable = FIXED_ONE_BYTE_STRING(
isolate, R"({"id": 1, "method": "Profiler.enable"})");
Local<String> start = FIXED_ONE_BYTE_STRING(isolate, R"({
"id": 2,
"method": "Profiler.startPreciseCoverage",
"params": { "callCount": true, "detailed": true }
})");
DispatchMessage(enable);
DispatchMessage(start);
DispatchMessage("Profiler.enable");
DispatchMessage("Profiler.startPreciseCoverage",
R"({ "callCount": true, "detailed": true })");
}

void V8CoverageConnection::End() {
CHECK_EQ(ending_, false);
ending_ = true;
Debug(env(),
DebugCategory::INSPECTOR_PROFILER,
"Sending Profiler.takePreciseCoverage\n");
Isolate* isolate = env()->isolate();
HandleScope scope(isolate);
Local<String> end = FIXED_ONE_BYTE_STRING(isolate, R"({
"id": 3,
"method": "Profiler.takePreciseCoverage"
})");
DispatchMessage(end);
DispatchMessage("Profiler.takePreciseCoverage");
}

std::string V8CpuProfilerConnection::GetDirectory() const {
Expand Down Expand Up @@ -257,25 +252,14 @@ MaybeLocal<Object> V8CpuProfilerConnection::GetProfile(Local<Object> result) {
}

void V8CpuProfilerConnection::Start() {
Debug(env(), DebugCategory::INSPECTOR_PROFILER, "Sending Profiler.start\n");
Isolate* isolate = env()->isolate();
Local<String> enable = FIXED_ONE_BYTE_STRING(
isolate, R"({"id": 1, "method": "Profiler.enable"})");
Local<String> start = FIXED_ONE_BYTE_STRING(
isolate, R"({"id": 2, "method": "Profiler.start"})");
DispatchMessage(enable);
DispatchMessage(start);
DispatchMessage("Profiler.enable");
DispatchMessage("Profiler.start");
}

void V8CpuProfilerConnection::End() {
CHECK_EQ(ending_, false);
ending_ = true;
Debug(env(), DebugCategory::INSPECTOR_PROFILER, "Sending Profiler.stop\n");
Isolate* isolate = env()->isolate();
HandleScope scope(isolate);
Local<String> end =
FIXED_ONE_BYTE_STRING(isolate, R"({"id": 3, "method": "Profiler.stop"})");
DispatchMessage(end);
DispatchMessage("Profiler.stop");
}

// For now, we only support coverage profiling, but we may add more
Expand Down
10 changes: 9 additions & 1 deletion src/inspector_profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ class V8ProfilerConnection {
virtual ~V8ProfilerConnection() = default;

Environment* env() const { return env_; }
void DispatchMessage(v8::Local<v8::String> message);

// Dispatch a protocol message, and returns the id of the message.
// `method` does not need to be surrounded by quotes.
// The optional `params` should be formatted in JSON.
// The strings should be in one byte characters - which is enough for
// the commands we use here.
size_t DispatchMessage(const char* method, const char* params = nullptr);

// Use DispatchMessage() to dispatch necessary inspector messages
// to start and end the profiling.
Expand All @@ -55,9 +61,11 @@ class V8ProfilerConnection {
v8::Local<v8::Object> result) = 0;

private:
size_t next_id() { return id_++; }
void WriteProfile(v8::Local<v8::String> message);
std::unique_ptr<inspector::InspectorSession> session_;
Environment* env_ = nullptr;
size_t id_ = 1;
};

class V8CoverageConnection : public V8ProfilerConnection {
Expand Down

0 comments on commit 0171bab

Please sign in to comment.