Skip to content

Commit 1e741d4

Browse files
authored
Merge pull request #1444 from asurdej-comcast/gc_heap_snapshot
wpe-2.38 Improve memory usage during GCHeap snapshot
2 parents 4978282 + 38ae47c commit 1e741d4

3 files changed

Lines changed: 84 additions & 10 deletions

File tree

Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,52 @@
3939

4040
namespace JSC {
4141

42+
namespace {
43+
44+
class FileOutputStingBuilder {
45+
WTF_MAKE_NONCOPYABLE(FileOutputStingBuilder);
46+
47+
FileSystem::PlatformFileHandle fileHandle;
48+
StringBuilder builder;
49+
50+
public:
51+
FileOutputStingBuilder(FileSystem::PlatformFileHandle fileHandle)
52+
: fileHandle(WTFMove(fileHandle))
53+
{
54+
}
55+
56+
~FileOutputStingBuilder()
57+
{
58+
flush(true);
59+
}
60+
61+
template<typename... StringTypes> void append(StringTypes... fragment)
62+
{
63+
builder.append(fragment...);
64+
flush();
65+
}
66+
67+
void appendQuotedJSONString(const String& string)
68+
{
69+
builder.appendQuotedJSONString(string);
70+
flush();
71+
}
72+
73+
void flush(bool force = false)
74+
{
75+
constexpr size_t kBufferLengthLimit = 4 * WTF::KB;
76+
if ((force && !builder.isEmpty()) || builder.length() >= kBufferLengthLimit)
77+
{
78+
CString utf8String = builder.toStringPreserveCapacity().utf8();
79+
FileSystem::writeToFile(fileHandle, utf8String.data(), utf8String.length());
80+
builder.clear();
81+
builder.reserveCapacity(kBufferLengthLimit);
82+
}
83+
}
84+
};
85+
86+
} // namespace
87+
4288
NodeIdentifier HeapSnapshotBuilder::nextAvailableObjectIdentifier = 1;
4389
NodeIdentifier HeapSnapshotBuilder::getNextObjectIdentifier() { return nextAvailableObjectIdentifier++; }
4490
void HeapSnapshotBuilder::resetNextAvailableObjectIdentifier() { HeapSnapshotBuilder::nextAvailableObjectIdentifier = 1; }
@@ -329,6 +375,20 @@ String HeapSnapshotBuilder::descriptionForCell(JSCell *cell) const
329375
}
330376

331377
String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowNodeCallback)
378+
{
379+
StringBuilder json;
380+
writeJson(WTFMove(allowNodeCallback), json);
381+
return json.toString();
382+
}
383+
384+
void HeapSnapshotBuilder::writeJsonToFile(FileSystem::PlatformFileHandle fileHandle)
385+
{
386+
FileOutputStingBuilder json(fileHandle);
387+
writeJson([] (const HeapSnapshotNode&) { return true; }, json);
388+
}
389+
390+
template<typename OutputStingBuilder>
391+
void HeapSnapshotBuilder::writeJson(Function<bool (const HeapSnapshotNode&)>&& allowNodeCallback, OutputStingBuilder &json)
332392
{
333393
VM& vm = m_profiler.vm();
334394
DeferGCForAWhile deferGC(vm);
@@ -350,7 +410,6 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
350410
HashMap<UniquedStringImpl*, unsigned> edgeNameIndexes;
351411
unsigned nextEdgeNameIndex = 0;
352412

353-
StringBuilder json;
354413

355414
auto appendNodeJSON = [&] (const HeapSnapshotNode& node) {
356415
// Let the client decide if they want to allow or disallow certain nodes.
@@ -615,7 +674,6 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
615674
}
616675

617676
json.append('}');
618-
return json.toString();
619677
}
620678

621679
} // namespace JSC

Source/JavaScriptCore/heap/HeapSnapshotBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <wtf/HashSet.h>
3232
#include <wtf/Lock.h>
3333
#include <wtf/Vector.h>
34+
#include <wtf/FileSystem.h>
3435

3536
namespace JSC {
3637

@@ -130,6 +131,7 @@ class JS_EXPORT_PRIVATE HeapSnapshotBuilder final : public HeapAnalyzer {
130131

131132
String json();
132133
String json(Function<bool (const HeapSnapshotNode&)> allowNodeCallback);
134+
void writeJsonToFile(FileSystem::PlatformFileHandle fileHandle);
133135

134136
private:
135137
static NodeIdentifier nextAvailableObjectIdentifier;
@@ -140,6 +142,9 @@ class JS_EXPORT_PRIVATE HeapSnapshotBuilder final : public HeapAnalyzer {
140142
bool previousSnapshotHasNodeForCell(JSCell*, NodeIdentifier&);
141143

142144
String descriptionForCell(JSCell*) const;
145+
146+
template<typename OutputStingBuilder>
147+
void writeJson(Function<bool (const HeapSnapshotNode&)>&& allowNodeCallback, OutputStingBuilder &json);
143148

144149
struct RootData {
145150
const char* reachabilityFromOpaqueRootReasons { nullptr };

Source/WebCore/bindings/js/GCController.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,26 @@ void GCController::deleteAllLinkedCode(DeleteAllCodeEffort effort)
140140

141141
void GCController::dumpHeap()
142142
{
143+
static const char* sHeapDumpDirOverride = []() {
144+
return getenv("WEBKIT_HEAP_SNAPSHOT_DIR");
145+
}();
146+
143147
FileSystem::PlatformFileHandle fileHandle;
144-
String tempFilePath = FileSystem::openTemporaryFile("GCHeap"_s, fileHandle);
148+
String tempFilePath;
149+
if (sHeapDumpDirOverride) {
150+
char buf[32];
151+
time_t now = time(nullptr);
152+
struct tm* tstruct = localtime(&now);
153+
std::strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", tstruct);
154+
155+
tempFilePath = WTF::String::fromUTF8(sHeapDumpDirOverride) + "/GCHeap_" + WTF::String::fromUTF8(buf);
156+
fileHandle = FileSystem::openFile(tempFilePath, FileSystem::FileOpenMode::ReadWrite);
157+
} else {
158+
tempFilePath = FileSystem::openTemporaryFile("GCHeap"_s, fileHandle);
159+
}
160+
145161
if (!FileSystem::isHandleValid(fileHandle)) {
146-
WTFLogAlways("Dumping GC heap failed to open temporary file");
162+
WTFLogAlways("Dumping GC heap failed to open temporary file: %s", tempFilePath.utf8().data());
147163
return;
148164
}
149165

@@ -152,19 +168,14 @@ void GCController::dumpHeap()
152168

153169
sanitizeStackForVM(vm);
154170

155-
String jsonData;
156171
{
157172
DeferGCForAWhile deferGC(vm); // Prevent concurrent GC from interfering with the full GC that the snapshot does.
158173

159174
HeapSnapshotBuilder snapshotBuilder(vm.ensureHeapProfiler(), HeapSnapshotBuilder::SnapshotType::GCDebuggingSnapshot);
160175
snapshotBuilder.buildSnapshot();
161-
162-
jsonData = snapshotBuilder.json();
176+
snapshotBuilder.writeJsonToFile(fileHandle);
163177
}
164178

165-
CString utf8String = jsonData.utf8();
166-
167-
FileSystem::writeToFile(fileHandle, utf8String.data(), utf8String.length());
168179
FileSystem::closeFile(fileHandle);
169180

170181
WTFLogAlways("Dumped GC heap to %s", tempFilePath.utf8().data());

0 commit comments

Comments
 (0)