Skip to content

Commit

Permalink
Implement Runtime.getHeapUsage for hermes chrome inspector (#33173)
Browse files Browse the repository at this point in the history
Summary:
Reland of #32895 with fix for optional params object.

Original description:

I was looking at the hermes chrome devtools integration and noticed requests to `Runtime.getHeapUsage` which was not implemented. When implemented it will show a summary of memory usage of the javascript instance in devtools.

<img width="325" alt="image" src="https://user-images.githubusercontent.com/2677334/149637113-e1d95d26-9e26-46c2-9be6-47d22284f15f.png">

## Changelog

[General] [Added] - Implement Runtime.getHeapUsage for hermes chrome inspector

Pull Request resolved: #33173

Test Plan:
I was able to reproduce the issue that caused the initial PR to be reverted using the resume request in Flipper. Pausing JS execution then resuming it will cause it to crash before this change, and works fine after.

Before

<img width="912" alt="image" src="https://user-images.githubusercontent.com/2677334/149637073-15f4e1fa-8183-42dc-8673-d4371731415c.png">

After

<img width="1076" alt="image" src="https://user-images.githubusercontent.com/2677334/149637085-579dee8f-5efb-4658-b0a8-2400bd119924.png">

Reviewed By: jpporto

Differential Revision: D34446672

Pulled By: ShikaSD

fbshipit-source-id: 6e26b8d53cd88cddded36437c72a01822551b9d0
  • Loading branch information
janicduplessis authored and facebook-github-bot committed Mar 1, 2022
1 parent 46bc521 commit cff9590
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 24 deletions.
18 changes: 18 additions & 0 deletions ReactCommon/hermes/inspector/chrome/Connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class Connection::Impl : public inspector::InspectorObserver,
void handle(const m::heapProfiler::GetHeapObjectIdRequest &req) override;
void handle(const m::runtime::CallFunctionOnRequest &req) override;
void handle(const m::runtime::EvaluateRequest &req) override;
void handle(const m::runtime::GetHeapUsageRequest &req) override;
void handle(const m::runtime::GetPropertiesRequest &req) override;
void handle(const m::runtime::RunIfWaitingForDebuggerRequest &req) override;

Expand Down Expand Up @@ -1348,6 +1349,23 @@ Connection::Impl::makePropsFromValue(
return result;
}

void Connection::Impl::handle(const m::runtime::GetHeapUsageRequest &req) {
auto resp = std::make_shared<m::runtime::GetHeapUsageResponse>();
resp->id = req.id;

inspector_
->executeIfEnabled(
"Runtime.getHeapUsage",
[this, req, resp](const debugger::ProgramState &state) {
auto heapInfo = getRuntime().instrumentation().getHeapInfo(false);
resp->usedSize = heapInfo["hermes_allocatedBytes"];
resp->totalSize = heapInfo["hermes_heapSize"];
})
.via(executor_.get())
.thenValue([this, resp](auto &&) { sendResponseToClient(*resp); })
.thenError<std::exception>(sendErrorToClient(req.id));
}

void Connection::Impl::handle(const m::runtime::GetPropertiesRequest &req) {
auto resp = std::make_shared<m::runtime::GetPropertiesResponse>();
resp->id = req.id;
Expand Down
86 changes: 76 additions & 10 deletions ReactCommon/hermes/inspector/chrome/MessageTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
makeUnique<heapProfiler::TakeHeapSnapshotRequest>},
{"Runtime.callFunctionOn", makeUnique<runtime::CallFunctionOnRequest>},
{"Runtime.evaluate", makeUnique<runtime::EvaluateRequest>},
{"Runtime.getHeapUsage", makeUnique<runtime::GetHeapUsageRequest>},
{"Runtime.getProperties", makeUnique<runtime::GetPropertiesRequest>},
{"Runtime.runIfWaitingForDebugger",
makeUnique<runtime::RunIfWaitingForDebuggerRequest>},
Expand Down Expand Up @@ -503,12 +504,22 @@ debugger::ResumeRequest::ResumeRequest(const dynamic &obj)
: Request("Debugger.resume") {
assign(id, obj, "id");
assign(method, obj, "method");

auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
assign(terminateOnResume, params, "terminateOnResume");
}
}

dynamic debugger::ResumeRequest::toDynamic() const {
dynamic params = dynamic::object;
put(params, "terminateOnResume", terminateOnResume);

dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "method", method);
put(obj, "params", std::move(params));
return obj;
}

Expand Down Expand Up @@ -817,8 +828,11 @@ heapProfiler::StartSamplingRequest::StartSamplingRequest(const dynamic &obj)
assign(id, obj, "id");
assign(method, obj, "method");

dynamic params = obj.at("params");
assign(samplingInterval, params, "samplingInterval");
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
assign(samplingInterval, params, "samplingInterval");
}
}

dynamic heapProfiler::StartSamplingRequest::toDynamic() const {
Expand All @@ -845,8 +859,11 @@ heapProfiler::StartTrackingHeapObjectsRequest::StartTrackingHeapObjectsRequest(
assign(id, obj, "id");
assign(method, obj, "method");

dynamic params = obj.at("params");
assign(trackAllocations, params, "trackAllocations");
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
assign(trackAllocations, params, "trackAllocations");
}
}

dynamic heapProfiler::StartTrackingHeapObjectsRequest::toDynamic() const {
Expand Down Expand Up @@ -894,15 +911,20 @@ heapProfiler::StopTrackingHeapObjectsRequest::StopTrackingHeapObjectsRequest(
assign(id, obj, "id");
assign(method, obj, "method");

dynamic params = obj.at("params");
assign(reportProgress, params, "reportProgress");
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
assign(reportProgress, params, "reportProgress");
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
assign(captureNumericValue, params, "captureNumericValue");
}
}

dynamic heapProfiler::StopTrackingHeapObjectsRequest::toDynamic() const {
dynamic params = dynamic::object;
put(params, "reportProgress", reportProgress);
put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots);
put(params, "captureNumericValue", captureNumericValue);

dynamic obj = dynamic::object;
put(obj, "id", id);
Expand All @@ -925,15 +947,20 @@ heapProfiler::TakeHeapSnapshotRequest::TakeHeapSnapshotRequest(
assign(id, obj, "id");
assign(method, obj, "method");

dynamic params = obj.at("params");
assign(reportProgress, params, "reportProgress");
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
assign(reportProgress, params, "reportProgress");
assign(treatGlobalObjectsAsRoots, params, "treatGlobalObjectsAsRoots");
assign(captureNumericValue, params, "captureNumericValue");
}
}

dynamic heapProfiler::TakeHeapSnapshotRequest::toDynamic() const {
dynamic params = dynamic::object;
put(params, "reportProgress", reportProgress);
put(params, "treatGlobalObjectsAsRoots", treatGlobalObjectsAsRoots);
put(params, "captureNumericValue", captureNumericValue);

dynamic obj = dynamic::object;
put(obj, "id", id);
Expand Down Expand Up @@ -1030,6 +1057,26 @@ void runtime::EvaluateRequest::accept(RequestHandler &handler) const {
handler.handle(*this);
}

runtime::GetHeapUsageRequest::GetHeapUsageRequest()
: Request("Runtime.getHeapUsage") {}

runtime::GetHeapUsageRequest::GetHeapUsageRequest(const dynamic &obj)
: Request("Runtime.getHeapUsage") {
assign(id, obj, "id");
assign(method, obj, "method");
}

dynamic runtime::GetHeapUsageRequest::toDynamic() const {
dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "method", method);
return obj;
}

void runtime::GetHeapUsageRequest::accept(RequestHandler &handler) const {
handler.handle(*this);
}

runtime::GetPropertiesRequest::GetPropertiesRequest()
: Request("Runtime.getProperties") {}

Expand Down Expand Up @@ -1284,6 +1331,25 @@ dynamic runtime::EvaluateResponse::toDynamic() const {
return obj;
}

runtime::GetHeapUsageResponse::GetHeapUsageResponse(const dynamic &obj) {
assign(id, obj, "id");

dynamic res = obj.at("result");
assign(usedSize, res, "usedSize");
assign(totalSize, res, "totalSize");
}

dynamic runtime::GetHeapUsageResponse::toDynamic() const {
dynamic res = dynamic::object;
put(res, "usedSize", usedSize);
put(res, "totalSize", totalSize);

dynamic obj = dynamic::object;
put(obj, "id", id);
put(obj, "result", std::move(res));
return obj;
}

runtime::GetPropertiesResponse::GetPropertiesResponse(const dynamic &obj) {
assign(id, obj, "id");

Expand Down
25 changes: 25 additions & 0 deletions ReactCommon/hermes/inspector/chrome/MessageTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ struct ExceptionDetails;
struct ExecutionContextCreatedNotification;
struct ExecutionContextDescription;
using ExecutionContextId = int;
struct GetHeapUsageRequest;
struct GetHeapUsageResponse;
struct GetPropertiesRequest;
struct GetPropertiesResponse;
struct InternalPropertyDescriptor;
Expand Down Expand Up @@ -127,6 +129,7 @@ struct RequestHandler {
virtual void handle(const heapProfiler::TakeHeapSnapshotRequest &req) = 0;
virtual void handle(const runtime::CallFunctionOnRequest &req) = 0;
virtual void handle(const runtime::EvaluateRequest &req) = 0;
virtual void handle(const runtime::GetHeapUsageRequest &req) = 0;
virtual void handle(const runtime::GetPropertiesRequest &req) = 0;
virtual void handle(const runtime::RunIfWaitingForDebuggerRequest &req) = 0;
};
Expand Down Expand Up @@ -162,6 +165,7 @@ struct NoopRequestHandler : public RequestHandler {
void handle(const heapProfiler::TakeHeapSnapshotRequest &req) override {}
void handle(const runtime::CallFunctionOnRequest &req) override {}
void handle(const runtime::EvaluateRequest &req) override {}
void handle(const runtime::GetHeapUsageRequest &req) override {}
void handle(const runtime::GetPropertiesRequest &req) override {}
void handle(const runtime::RunIfWaitingForDebuggerRequest &req) override {}
};
Expand Down Expand Up @@ -400,6 +404,8 @@ struct debugger::ResumeRequest : public Request {

folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override;

folly::Optional<bool> terminateOnResume;
};

struct debugger::SetBreakpointRequest : public Request {
Expand Down Expand Up @@ -548,6 +554,7 @@ struct heapProfiler::StopTrackingHeapObjectsRequest : public Request {

folly::Optional<bool> reportProgress;
folly::Optional<bool> treatGlobalObjectsAsRoots;
folly::Optional<bool> captureNumericValue;
};

struct heapProfiler::TakeHeapSnapshotRequest : public Request {
Expand All @@ -559,6 +566,7 @@ struct heapProfiler::TakeHeapSnapshotRequest : public Request {

folly::Optional<bool> reportProgress;
folly::Optional<bool> treatGlobalObjectsAsRoots;
folly::Optional<bool> captureNumericValue;
};

struct runtime::CallFunctionOnRequest : public Request {
Expand Down Expand Up @@ -596,6 +604,14 @@ struct runtime::EvaluateRequest : public Request {
folly::Optional<bool> awaitPromise;
};

struct runtime::GetHeapUsageRequest : public Request {
GetHeapUsageRequest();
explicit GetHeapUsageRequest(const folly::dynamic &obj);

folly::dynamic toDynamic() const override;
void accept(RequestHandler &handler) const override;
};

struct runtime::GetPropertiesRequest : public Request {
GetPropertiesRequest();
explicit GetPropertiesRequest(const folly::dynamic &obj);
Expand Down Expand Up @@ -709,6 +725,15 @@ struct runtime::EvaluateResponse : public Response {
folly::Optional<runtime::ExceptionDetails> exceptionDetails;
};

struct runtime::GetHeapUsageResponse : public Response {
GetHeapUsageResponse() = default;
explicit GetHeapUsageResponse(const folly::dynamic &obj);
folly::dynamic toDynamic() const override;

double usedSize{};
double totalSize{};
};

struct runtime::GetPropertiesResponse : public Response {
GetPropertiesResponse() = default;
explicit GetPropertiesResponse(const folly::dynamic &obj);
Expand Down
5 changes: 4 additions & 1 deletion ReactCommon/hermes/inspector/chrome/tests/MessageTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,10 @@ TEST(MessageTests, testResumeRequest) {
std::string message = R"(
{
"id": 10,
"method": "Debugger.resume"
"method": "Debugger.resume",
"params": {
"terminateOnResume": false
}
}
)";

Expand Down
1 change: 1 addition & 0 deletions ReactCommon/hermes/inspector/tools/message_types.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ Runtime.callFunctionOn
Runtime.consoleAPICalled
Runtime.evaluate
Runtime.executionContextCreated
Runtime.getHeapUsage
Runtime.getProperties
Runtime.runIfWaitingForDebugger
2 changes: 1 addition & 1 deletion ReactCommon/hermes/inspector/tools/msggen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"test": "jest"
},
"dependencies": {
"devtools-protocol": "0.0.730699",
"devtools-protocol": "0.0.959523",
"yargs": "^14.2.0"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,26 @@ export function emitRequestDef(stream: Writable, command: Command) {
assign(method, obj, "method");\n\n`);

if (props.length > 0) {
stream.write('dynamic params = obj.at("params");\n');
const optionalParams = props.every(p => p.optional);
if (optionalParams) {
stream.write(`
auto it = obj.find("params");
if (it != obj.items().end()) {
dynamic params = it->second;
`);
} else {
stream.write('dynamic params = obj.at("params");\n');
}

for (const prop of props) {
const id = prop.getCppIdentifier();
const name = prop.name;
stream.write(`assign(${id}, params, "${name}");\n`);
}

if (optionalParams) {
stream.write('}');
}
}

stream.write('}\n\n');
Expand Down
19 changes: 17 additions & 2 deletions ReactCommon/hermes/inspector/tools/msggen/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const proto = mergeDomains(standard, custom);
function parseDomains(
domainObjs: Array<any>,
ignoreExperimental: boolean,
includeExperimental: Set<string>,
): Descriptor {
const desc = {
types: [],
Expand All @@ -59,7 +60,12 @@ function parseDomains(
}

for (const commandObj of obj.commands || []) {
const command = Command.create(domain, commandObj, ignoreExperimental);
const command = Command.create(
domain,
commandObj,
!includeExperimental.has(`${domain}.${commandObj.name}`) &&
ignoreExperimental,
);
if (command) {
desc.commands.push(command);
}
Expand Down Expand Up @@ -199,18 +205,27 @@ function main() {
.boolean('e')
.alias('e', 'ignore-experimental')
.describe('e', 'ignore experimental commands, props, and types')
.alias('i', 'include-experimental')
.describe('i', 'experimental commands to include')
.alias('r', 'roots')
.describe('r', 'path to a file listing root types, events, and commands')
.nargs('r', 1)
.demandCommand(2, 2).argv;

const ignoreExperimental = !!args.e;
const includeExperimental = new Set(
typeof args.i === 'string' ? args.i.split(',') : [],
);
const [headerPath, implPath] = args._;

const headerStream = fs.createWriteStream(headerPath);
const implStream = fs.createWriteStream(implPath);

const desc = parseDomains(proto.domains, ignoreExperimental);
const desc = parseDomains(
proto.domains,
ignoreExperimental,
includeExperimental,
);
const graph = buildGraph(desc);
const roots = parseRoots(desc, String(args.roots));

Expand Down
8 changes: 4 additions & 4 deletions ReactCommon/hermes/inspector/tools/msggen/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2434,10 +2434,10 @@ detect-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==

[email protected].730699:
version "0.0.730699"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.730699.tgz#4d18f6a9b7fb7cf3f1ffe73bfe14aad66cf3b2ef"
integrity sha512-dprBpuPzVIIXXL6GevzhvWe2wg836h3d5hY+n6IzzHbKLsUh6QlVmcIy15za0J3MhDFbmEH60s6uYsrw/tgBbw==
[email protected].959523:
version "0.0.959523"
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.959523.tgz#a7ce62c6b88876081fe5bec866f70e467bc021ba"
integrity sha512-taOcAND/oJA5FhJD2I3RA+I8RPdrpPJWwvMBPzTq7Sugev1xTOG3lgtlSfkh5xkjTYw0Ti2CRQq016goFHMoPQ==

diff-sequences@^26.6.2:
version "26.6.2"
Expand Down
Loading

0 comments on commit cff9590

Please sign in to comment.