Web Inspector: Native Memory Instrumentation: reportLeaf method doesn't report the...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebCore / HeapGraphSerializerTest.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "WTFStringUtilities.h"
33 #include <gtest/gtest.h>
34
35 #include "HeapGraphSerializer.h"
36 #include "MemoryInstrumentationImpl.h"
37 #include <wtf/MemoryInstrumentation.h>
38 #include <wtf/MemoryInstrumentationHashSet.h>
39 #include <wtf/MemoryInstrumentationString.h>
40 #include <wtf/MemoryObjectInfo.h>
41
42 namespace TestWebKitAPI {
43
44 using namespace WebCore;
45
46 static WTF::MemoryObjectType g_defaultObjectType = "DefaultObjectType";
47
48 class HeapGraphReceiver : public HeapGraphSerializer::Client {
49 public:
50     HeapGraphReceiver() : m_serializer(this) { }
51
52     virtual void addNativeSnapshotChunk(PassRefPtr<TypeBuilder::Memory::HeapSnapshotChunk> heapSnapshotChunk) OVERRIDE
53     {
54         ASSERT(!m_heapSnapshotChunk);
55         m_heapSnapshotChunk = heapSnapshotChunk;
56         m_strings = chunkPart("strings");
57         m_edges = chunkPart("edges");
58         m_nodes = chunkPart("nodes");
59
60         // Reset platform depended size field values.
61         for (InspectorArray::iterator i = m_nodes->begin(); i != m_nodes->end(); i += s_nodeFieldCount)
62             *(i + s_sizeOffset) = InspectorBasicValue::create(0);
63
64         m_id2index.clear();
65
66         for (unsigned index = 0; index < m_nodes->length(); index += s_nodeFieldCount)
67             m_id2index.add(intValue(m_nodes.get(), index + s_idOffset), index);
68     }
69
70     void printGraph()
71     {
72         EXPECT_TRUE(m_heapSnapshotChunk);
73         int processedEdgesCount = 0;
74         for (unsigned index = 0; index < m_nodes->length(); index += s_nodeFieldCount)
75             processedEdgesCount += printNode(index, processedEdgesCount);
76     }
77
78     String dumpNodes() { return dumpPart("nodes"); }
79     String dumpEdges() { return dumpPart("edges"); }
80     String dumpBaseToRealNodeId() { return dumpPart("baseToRealNodeId"); }
81     String dumpStrings() { return dumpPart("strings"); }
82
83     HeapGraphSerializer* serializer() { return &m_serializer; }
84
85 private:
86     PassRefPtr<InspectorArray> chunkPart(String partName)
87     {
88         EXPECT_TRUE(m_heapSnapshotChunk);
89         RefPtr<InspectorObject> chunk = *reinterpret_cast<RefPtr<InspectorObject>*>(&m_heapSnapshotChunk);
90         RefPtr<InspectorValue> partValue = chunk->get(partName);
91         RefPtr<InspectorArray> partArray;
92         EXPECT_TRUE(partValue->asArray(&partArray));
93         return partArray.release();
94     }
95
96     String dumpPart(String partName)
97     {
98         return chunkPart(partName)->toJSONString().replace("\"", "'");
99     }
100
101     String stringValue(InspectorArray* array, int index)
102     {
103         RefPtr<InspectorValue> inspectorValue = array->get(index);
104         String value;
105         EXPECT_TRUE(inspectorValue->asString(&value));
106         return value;
107     }
108
109     int intValue(InspectorArray* array, int index)
110     {
111         RefPtr<InspectorValue> inspectorValue = array->get(index);
112         int value;
113         EXPECT_TRUE(inspectorValue->asNumber(&value));
114         return value;
115     }
116
117     String nodeToString(unsigned nodeIndex)
118     {
119         StringBuilder builder;
120         builder.append("node: ");
121         builder.appendNumber(intValue(m_nodes.get(), nodeIndex + s_idOffset));
122         builder.append(" with className:'");
123         builder.append(stringValue(m_strings.get(), intValue(m_nodes.get(), nodeIndex + s_classNameOffset)));
124         builder.append("' and name: '");
125         builder.append(stringValue(m_strings.get(), intValue(m_nodes.get(), nodeIndex + s_nameOffset)));
126         builder.append("'");
127         return builder.toString();
128     }
129
130     String edgeToString(unsigned edgeOrdinal)
131     {
132         unsigned edgeIndex = edgeOrdinal * s_edgeFieldCount;
133         StringBuilder builder;
134         builder.append("'");
135         builder.append(stringValue(m_strings.get(), intValue(m_edges.get(), edgeIndex + s_edgeTypeOffset)));
136         builder.append("' edge '");
137         builder.append(stringValue(m_strings.get(), intValue(m_edges.get(), edgeIndex + s_edgeNameOffset)));
138         builder.append("' points to ");
139         int nodeId = intValue(m_edges.get(), edgeIndex + s_toNodeIdOffset);
140         builder.append(nodeToString(m_id2index.get(nodeId)));
141         return builder.toString();
142     }
143
144     int printNode(unsigned nodeIndex, unsigned processedEdgesCount)
145     {
146         String nodeString = nodeToString(nodeIndex);
147         unsigned edgeCount = intValue(m_nodes.get(), nodeIndex + s_edgeCountOffset);
148
149         printf("%s\n", nodeString.utf8().data());
150         for (unsigned i = 0; i < edgeCount; ++i) {
151             String edgeText = edgeToString(i + processedEdgesCount);
152             printf("\thas %s\n", edgeText.utf8().data());
153         }
154         return edgeCount;
155     }
156
157     HeapGraphSerializer m_serializer;
158     RefPtr<TypeBuilder::Memory::HeapSnapshotChunk> m_heapSnapshotChunk;
159
160     RefPtr<InspectorArray> m_strings;
161     RefPtr<InspectorArray> m_nodes;
162     RefPtr<InspectorArray> m_edges;
163     HashMap<int, int> m_id2index;
164
165     static const int s_nodeFieldCount = 5;
166     static const int s_classNameOffset = 0;
167     static const int s_nameOffset = 1;
168     static const int s_idOffset = 2;
169     static const int s_sizeOffset = 3;
170     static const int s_edgeCountOffset = 4;
171
172     static const int s_edgeFieldCount = 3;
173     static const int s_edgeTypeOffset = 0;
174     static const int s_edgeNameOffset = 1;
175     static const int s_toNodeIdOffset = 2;
176 };
177
178 class Helper {
179 public:
180     Helper(HeapGraphSerializer* serializer) : m_serializer(serializer), m_currentPointer(0) { }
181     void* addNode(const char* className, const char* name, bool isRoot)
182     {
183         WTF::MemoryObjectInfo info(0, g_defaultObjectType, ++m_currentPointer);
184         info.setClassName(className);
185         info.setName(name);
186         if (isRoot)
187             info.markAsRoot();
188         m_serializer->reportNode(info);
189         return m_currentPointer;
190     }
191
192     void addEdge(void* to, const char* edgeName, WTF::MemberType memberType)
193     {
194         m_serializer->reportEdge(to, edgeName, memberType);
195     }
196
197     void done()
198     {
199         m_serializer->finish();
200     }
201
202 private:
203     HeapGraphSerializer* m_serializer;
204
205     class Object {
206     public:
207         Object() { m_data[0] = 0; }
208         char m_data[sizeof(void*)];
209     };
210     Object* m_currentPointer;
211 };
212
213 TEST(HeapGraphSerializerTest, snapshotWithoutUserObjects)
214 {
215     HeapGraphReceiver receiver;
216     Helper helper(receiver.serializer());
217     helper.done();
218     receiver.printGraph();
219     EXPECT_EQ(String("['','weak','ownRef','countRef','unknown','Root']"), receiver.dumpStrings());
220     EXPECT_EQ(String("[5,0,1,0,0]"), receiver.dumpNodes()); // Only Root object.
221     EXPECT_EQ(String("[]"), receiver.dumpEdges()); // No edges.
222     EXPECT_EQ(String("[]"), receiver.dumpBaseToRealNodeId()); // No id maps.
223 }
224
225 TEST(HeapGraphSerializerTest, oneRootUserObject)
226 {
227     HeapGraphReceiver receiver;
228     Helper helper(receiver.serializer());
229     helper.addNode("ClassName", "objectName", true);
230     helper.done();
231     receiver.printGraph();
232     EXPECT_EQ(String("['','weak','ownRef','countRef','unknown','ClassName','objectName','Root']"), receiver.dumpStrings());
233     EXPECT_EQ(String("[5,6,1,0,0,7,0,2,0,1]"), receiver.dumpNodes());
234     EXPECT_EQ(String("[1,0,1]"), receiver.dumpEdges());
235     EXPECT_EQ(String("[]"), receiver.dumpBaseToRealNodeId());
236 }
237
238 TEST(HeapGraphSerializerTest, twoUserObjectsWithEdge)
239 {
240     HeapGraphReceiver receiver;
241     Helper helper(receiver.serializer());
242     void* childObject = helper.addNode("Child", "child", false);
243     helper.addEdge(childObject, "pointerToChild", WTF::OwnPtrMember);
244     helper.addNode("Parent", "parent", true);
245     helper.done();
246     receiver.printGraph();
247     EXPECT_EQ(String("['','weak','ownRef','countRef','unknown','Child','child','pointerToChild','Parent','parent','Root']"), receiver.dumpStrings());
248     EXPECT_EQ(String("[5,6,1,0,0,8,9,2,0,1,10,0,3,0,1]"), receiver.dumpNodes());
249     EXPECT_EQ(String("[2,7,1,1,0,2]"), receiver.dumpEdges());
250     EXPECT_EQ(String("[]"), receiver.dumpBaseToRealNodeId());
251 }
252
253 class Owner {
254 public:
255     Owner()
256     {
257         m_strings.add("first element");
258         m_strings.add("second element");
259     }
260     void reportMemoryUsage(WTF::MemoryObjectInfo* memoryObjectInfo) const
261     {
262         WTF::MemoryClassInfo info(memoryObjectInfo, this, g_defaultObjectType);
263         info.addMember(m_strings, "strings");
264     }
265 private:
266     HashSet<String> m_strings;
267 };
268
269 TEST(HeapGraphSerializerTest, hashSetWithTwoStrings)
270 {
271     HeapGraphReceiver receiver;
272     MemoryInstrumentationClientImpl memoryInstrumentationClient(receiver.serializer());
273     MemoryInstrumentationImpl memoryInstrumentation(&memoryInstrumentationClient);
274
275     Owner owner;
276     memoryInstrumentation.addRootObject(&owner);
277     receiver.serializer()->finish();
278     receiver.printGraph();
279     EXPECT_EQ(String("[5,0,1,0,0,8,0,4,0,3,9,0,3,0,0,9,0,2,0,0,10,0,5,0,1]"), receiver.dumpNodes());
280     EXPECT_EQ(String("[2,6,1,1,7,2,1,7,3,1,0,4]"), receiver.dumpEdges());
281     EXPECT_EQ(String("[]"), receiver.dumpBaseToRealNodeId());
282 }
283
284 } // namespace