Skip to content
File

Blob: src/workerd/jsg/memory-test.c++

3.3 KB
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#include <workerd/jsg/memory.h>
6#include <workerd/jsg/setup.h>
7#include <workerd/jsg/type-wrapper.h>
8 
9#include <v8-profiler.h>
10 
11#include <kj/map.h>
12#include <kj/test.h>
13 
14namespace workerd::jsg::test {
15namespace {
16 
17V8System v8System;
18class ContextGlobalObject: public Object, public ContextGlobal {};
19 
20struct Foo: public Object {
21 kj::String bar = kj::str("test");
22 
23 JSG_RESOURCE_TYPE(Foo) {}
24 void visitForMemoryInfo(MemoryTracker& tracker) const {
25 tracker.trackField("bar", bar);
26 }
27};
28 
29struct MemoryTrackerContext: public ContextGlobalObject {
30 JSG_RESOURCE_TYPE(MemoryTrackerContext) {}
31};
32JSG_DECLARE_ISOLATE_TYPE(MemoryTrackerIsolate, MemoryTrackerContext, Foo);
33 
34void runTest(auto callback) {
35 MemoryTrackerIsolate isolate(v8System, kj::heap<jsg::IsolateObserver>());
36 isolate.runInLockScope([&](MemoryTrackerIsolate::Lock& lock) {
37 JSG_WITHIN_CONTEXT_SCOPE(lock, lock.newContext<MemoryTrackerContext>().getHandle(lock),
38 [&](jsg::Lock& js) { callback(js, lock.getTypeHandler<Ref<Foo>>()); });
39 });
40}
41 
42KJ_TEST("MemoryTracker test") {
43 // Verifies that workerd details are included in the heapsnapshot.
44 // This is not a comprehensive test of the heapsnapshot content,
45 // it is designed just to make sure that we are, in fact, publishing
46 // internal details to the snapshot.
47 
48 runTest([&](jsg::Lock& js, const TypeHandler<Ref<Foo>>& fooHandler) {
49 kj::Vector<char> serialized;
50 HeapSnapshotActivity activity([](auto, auto) { return true; });
51 HeapSnapshotWriter writer([&](kj::Maybe<kj::ArrayPtr<char>> maybeChunk) {
52 KJ_IF_SOME(chunk, maybeChunk) {
53 serialized.addAll(chunk);
54 }
55 return true;
56 });
57 
58 auto foo = fooHandler.wrap(js, js.alloc<Foo>());
59 KJ_ASSERT(foo->IsObject());
60 
61 auto profiler = js.v8Isolate->GetHeapProfiler();
62 
63 HeapSnapshotDeleter deleter;
64 
65 auto snapshot = kj::Own<const v8::HeapSnapshot>(
66 profiler->TakeHeapSnapshot(&activity, nullptr, true, true), deleter);
67 snapshot->Serialize(&writer, v8::HeapSnapshot::kJSON);
68 
69 auto parsed = js.parseJson(serialized.asPtr());
70 JsValue value = JsValue(parsed.getHandle(js));
71 KJ_ASSERT(value.isObject());
72 
73 JsObject obj = KJ_ASSERT_NONNULL(value.tryCast<JsObject>());
74 
75 auto strings = obj.get(js, "strings");
76 KJ_ASSERT(strings.isArray());
77 
78 JsArray array = KJ_ASSERT_NONNULL(strings.tryCast<JsArray>());
79 
80 size_t count = 0;
81 
82 kj::HashSet<kj::String> checks;
83 checks.insert(kj::str("workerd / IsolateBase"));
84 checks.insert(kj::str("workerd / kj::String"));
85 checks.insert(kj::str("workerd / HeapTracer"));
86 checks.insert(kj::str("workerd / CppgcShim"));
87 checks.insert(kj::str("workerd / MemoryTrackerContext"));
88 checks.insert(kj::str("workerd / Foo"));
89 
90 // Find what we're looking for... this is slow but, you know
91 for (size_t n = 0; n < array.size(); n++) {
92 JsValue check = array.get(js, n);
93 auto str = check.toString(js);
94 if (str.startsWith("workerd /")) {
95 count++;
96 KJ_ASSERT(checks.find(str) != kj::none);
97 }
98 }
99 KJ_ASSERT(count == checks.size());
100 });
101}
102 
103} // namespace
104} // namespace workerd::jsg::test