Skip to content

Commit 1913797

Browse files
DevmateUtgenCppGeneralFBOrg Botfacebook-github-bot
authored andcommitted
xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/jni/react/hermes/instrumentation/HermesSamplingProfiler.cpp
Reviewed By: cortinico Differential Revision: D114567246
1 parent d89c432 commit 1913797

1 file changed

Lines changed: 106 additions & 0 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "HermesSamplingProfiler.h"
9+
10+
#include <hermes/hermes.h>
11+
#include <jsi/jsi.h>
12+
13+
#include <gtest/gtest.h>
14+
15+
#include <cstdio>
16+
#include <fstream>
17+
#include <memory>
18+
#include <sstream>
19+
#include <string>
20+
#include <system_error>
21+
22+
namespace facebook::jsi::jni {
23+
namespace {
24+
25+
// The JNI entry points ignore their `jclass` argument, so a null alias_ref is
26+
// sufficient to drive them from a host unit test without a live JVM.
27+
jni::alias_ref<jclass> noClass() {
28+
return jni::alias_ref<jclass>{};
29+
}
30+
31+
// Creates a HermesRuntime that automatically registers itself with the global
32+
// sampling profiler. Without such a runtime the global profiler has nothing to
33+
// serialize.
34+
std::unique_ptr<facebook::hermes::HermesRuntime> makeProfilingRuntime() {
35+
auto config = ::hermes::vm::RuntimeConfig::Builder()
36+
.withEnableSampleProfiling(true)
37+
.build();
38+
auto* rootAPI = castInterface<facebook::hermes::IHermesRootAPI>(
39+
facebook::hermes::makeHermesRootAPI());
40+
return rootAPI->makeHermesRuntime(config);
41+
}
42+
43+
std::string readFile(const std::string& path) {
44+
std::ifstream stream(path, std::ios::binary);
45+
std::stringstream buffer;
46+
buffer << stream.rdbuf();
47+
return buffer.str();
48+
}
49+
50+
class HermesSamplingProfilerTest : public ::testing::Test {
51+
protected:
52+
std::string tracePath(const std::string& name) const {
53+
return ::testing::TempDir() + "HermesSamplingProfilerTest_" + name;
54+
}
55+
};
56+
57+
// Enabling the profiler, dumping while a runtime is registered, then disabling
58+
// should forward the requested filename all the way to Hermes and write a
59+
// well-formed Chrome trace document to exactly that path.
60+
TEST_F(HermesSamplingProfilerTest, dumpWhileProfilingWritesChromeTrace) {
61+
const std::string path = tracePath("profiling.json");
62+
std::remove(path.c_str());
63+
64+
HermesSamplingProfiler::enable(noClass());
65+
auto runtime = makeProfilingRuntime();
66+
HermesSamplingProfiler::dumpSampledTraceToFile(noClass(), path);
67+
HermesSamplingProfiler::disable(noClass());
68+
69+
const std::string contents = readFile(path);
70+
EXPECT_NE(contents.find("traceEvents"), std::string::npos);
71+
EXPECT_NE(contents.find("samples"), std::string::npos);
72+
EXPECT_NE(contents.find("stackFrames"), std::string::npos);
73+
74+
std::remove(path.c_str());
75+
}
76+
77+
// A destination that cannot be opened (its parent directory does not exist)
78+
// must surface the underlying I/O failure to the caller rather than being
79+
// swallowed.
80+
TEST_F(HermesSamplingProfilerTest, dumpToUnwritablePathThrows) {
81+
const std::string path = ::testing::TempDir() + "hsp_missing_dir/trace.json";
82+
83+
EXPECT_THROW(
84+
HermesSamplingProfiler::dumpSampledTraceToFile(noClass(), path),
85+
std::system_error);
86+
}
87+
88+
// With no runtime registered the global profiler has no data to serialize, but
89+
// the JNI entry point must still create the exact file it was asked to write.
90+
TEST_F(
91+
HermesSamplingProfilerTest,
92+
dumpWithoutRegisteredRuntimeCreatesEmptyFile) {
93+
const std::string path = tracePath("no_runtime.json");
94+
std::remove(path.c_str());
95+
96+
HermesSamplingProfiler::dumpSampledTraceToFile(noClass(), path);
97+
98+
std::ifstream stream(path, std::ios::binary);
99+
ASSERT_TRUE(stream.good());
100+
EXPECT_TRUE(readFile(path).empty());
101+
102+
std::remove(path.c_str());
103+
}
104+
105+
} // namespace
106+
} // namespace facebook::jsi::jni

0 commit comments

Comments
 (0)