Implement Runtime.getHeapUsage for hermes chrome inspector (#33173)
Summary: Reland of https://github.com/facebook/react-native/issues/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: https://github.com/facebook/react-native/pull/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
This commit is contained in:
Родитель
46bc521513
Коммит
cff9590864
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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>},
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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") {}
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
|
|
@ -59,6 +59,8 @@ struct ExceptionDetails;
|
|||
struct ExecutionContextCreatedNotification;
|
||||
struct ExecutionContextDescription;
|
||||
using ExecutionContextId = int;
|
||||
struct GetHeapUsageRequest;
|
||||
struct GetHeapUsageResponse;
|
||||
struct GetPropertiesRequest;
|
||||
struct GetPropertiesResponse;
|
||||
struct InternalPropertyDescriptor;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 {}
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
|
@ -692,7 +692,10 @@ TEST(MessageTests, testResumeRequest) {
|
|||
std::string message = R"(
|
||||
{
|
||||
"id": 10,
|
||||
"method": "Debugger.resume"
|
||||
"method": "Debugger.resume",
|
||||
"params": {
|
||||
"terminateOnResume": false
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
|
|
|
@ -32,5 +32,6 @@ Runtime.callFunctionOn
|
|||
Runtime.consoleAPICalled
|
||||
Runtime.evaluate
|
||||
Runtime.executionContextCreated
|
||||
Runtime.getHeapUsage
|
||||
Runtime.getProperties
|
||||
Runtime.runIfWaitingForDebugger
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"devtools-protocol": "0.0.730699",
|
||||
"devtools-protocol": "0.0.959523",
|
||||
"yargs": "^14.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -41,6 +41,7 @@ const proto = mergeDomains(standard, custom);
|
|||
function parseDomains(
|
||||
domainObjs: Array<any>,
|
||||
ignoreExperimental: boolean,
|
||||
includeExperimental: Set<string>,
|
||||
): Descriptor {
|
||||
const desc = {
|
||||
types: [],
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
|
|
@ -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==
|
||||
|
||||
devtools-protocol@0.0.730699:
|
||||
version "0.0.730699"
|
||||
resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.730699.tgz#4d18f6a9b7fb7cf3f1ffe73bfe14aad66cf3b2ef"
|
||||
integrity sha512-dprBpuPzVIIXXL6GevzhvWe2wg836h3d5hY+n6IzzHbKLsUh6QlVmcIy15za0J3MhDFbmEH60s6uYsrw/tgBbw==
|
||||
devtools-protocol@0.0.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"
|
||||
|
|
|
@ -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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче