Skip to content

Commit

Permalink
Implement Runtime.getHeapUsage for hermes chrome inspector (#32895)
Browse files Browse the repository at this point in the history
Summary:
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: #32895

Test Plan:
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: christophpurrer

Differential Revision: D33616658

Pulled By: ShikaSD

fbshipit-source-id: 49d863e6a58d4a92d4c86f9a288ac33ed8d2cb0d
  • Loading branch information
janicduplessis authored and facebook-github-bot committed Feb 2, 2022
1 parent a86cae7 commit 3568a72
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 12 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
51 changes: 51 additions & 0 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,19 @@ debugger::ResumeRequest::ResumeRequest(const dynamic &obj)
: Request("Debugger.resume") {
assign(id, obj, "id");
assign(method, obj, "method");

dynamic params = obj.at("params");
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 @@ -897,12 +905,14 @@ heapProfiler::StopTrackingHeapObjectsRequest::StopTrackingHeapObjectsRequest(
dynamic params = obj.at("params");
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 @@ -928,12 +938,14 @@ heapProfiler::TakeHeapSnapshotRequest::TakeHeapSnapshotRequest(
dynamic params = obj.at("params");
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 +1042,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 +1316,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
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
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
11 changes: 6 additions & 5 deletions ReactCommon/hermes/inspector/tools/run_msggen
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@

set -e

DIR=$(dirname "${BASH_SOURCE[0]}")
DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd)
cd "${DIR}/msggen"

yarn install
yarn build

FBSOURCE=$(hg root)
MSGTYPES_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/tools/message_types.txt"
HEADER_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/chrome/MessageTypes.h"
CPP_PATH="${FBSOURCE}/xplat/js/react-native-github/ReactCommon/hermes/inspector/chrome/MessageTypes.cpp"
MSGTYPES_PATH="${DIR}/message_types.txt"
HEADER_PATH="${DIR}/../chrome/MessageTypes.h"
CPP_PATH="${DIR}/../chrome/MessageTypes.cpp"

node bin/index.js \
--ignore-experimental \
--include-experimental=Runtime.getHeapUsage \
--roots "$MSGTYPES_PATH" \
"$HEADER_PATH" "$CPP_PATH"

clang-format -i --style=file "$HEADER_PATH"
clang-format -i --style=file "$CPP_PATH"

FBSOURCE=$(hg root)
"${FBSOURCE}/tools/signedsource" sign "$HEADER_PATH"
"${FBSOURCE}/tools/signedsource" sign "$CPP_PATH"

0 comments on commit 3568a72

Please sign in to comment.