2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "WTFStringUtilities.h"
33 #include <gtest/gtest.h>
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>
42 namespace TestWebKitAPI {
44 using namespace WebCore;
46 static WTF::MemoryObjectType g_defaultObjectType = "DefaultObjectType";
48 class HeapGraphReceiver : public HeapGraphSerializer::Client {
50 HeapGraphReceiver() : m_serializer(this) { }
52 virtual void addNativeSnapshotChunk(PassRefPtr<TypeBuilder::Memory::HeapSnapshotChunk> heapSnapshotChunk) OVERRIDE
54 ASSERT(!m_heapSnapshotChunk);
55 m_heapSnapshotChunk = heapSnapshotChunk;
56 m_strings = chunkPart("strings");
57 m_edges = chunkPart("edges");
58 m_nodes = chunkPart("nodes");
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);
66 for (unsigned index = 0; index < m_nodes->length(); index += s_nodeFieldCount)
67 m_id2index.add(intValue(m_nodes.get(), index + s_idOffset), index);
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);
78 String dumpNodes() { return dumpPart("nodes"); }
79 String dumpEdges() { return dumpPart("edges"); }
80 String dumpBaseToRealNodeId() { return dumpPart("baseToRealNodeId"); }
81 String dumpStrings() { return dumpPart("strings"); }
83 HeapGraphSerializer* serializer() { return &m_serializer; }
86 PassRefPtr<InspectorArray> chunkPart(String partName)
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();
96 String dumpPart(String partName)
98 return chunkPart(partName)->toJSONString().replace("\"", "'");
101 String stringValue(InspectorArray* array, int index)
103 RefPtr<InspectorValue> inspectorValue = array->get(index);
105 EXPECT_TRUE(inspectorValue->asString(&value));
109 int intValue(InspectorArray* array, int index)
111 RefPtr<InspectorValue> inspectorValue = array->get(index);
113 EXPECT_TRUE(inspectorValue->asNumber(&value));
117 String nodeToString(unsigned nodeIndex)
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)));
127 return builder.toString();
130 String edgeToString(unsigned edgeOrdinal)
132 unsigned edgeIndex = edgeOrdinal * s_edgeFieldCount;
133 StringBuilder builder;
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();
144 int printNode(unsigned nodeIndex, unsigned processedEdgesCount)
146 String nodeString = nodeToString(nodeIndex);
147 unsigned edgeCount = intValue(m_nodes.get(), nodeIndex + s_edgeCountOffset);
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());
157 HeapGraphSerializer m_serializer;
158 RefPtr<TypeBuilder::Memory::HeapSnapshotChunk> m_heapSnapshotChunk;
160 RefPtr<InspectorArray> m_strings;
161 RefPtr<InspectorArray> m_nodes;
162 RefPtr<InspectorArray> m_edges;
163 HashMap<int, int> m_id2index;
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;
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;
180 Helper(HeapGraphSerializer* serializer) : m_serializer(serializer), m_currentPointer(0) { }
181 void* addNode(const char* className, const char* name, bool isRoot)
183 WTF::MemoryObjectInfo info(0, g_defaultObjectType, ++m_currentPointer);
184 info.setClassName(className);
188 m_serializer->reportNode(info);
189 return m_currentPointer;
192 void addEdge(void* to, const char* edgeName, WTF::MemberType memberType)
194 m_serializer->reportEdge(to, edgeName, memberType);
199 m_serializer->finish();
203 HeapGraphSerializer* m_serializer;
207 Object() { m_data[0] = 0; }
208 char m_data[sizeof(void*)];
210 Object* m_currentPointer;
213 TEST(HeapGraphSerializerTest, snapshotWithoutUserObjects)
215 HeapGraphReceiver receiver;
216 Helper helper(receiver.serializer());
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.
225 TEST(HeapGraphSerializerTest, oneRootUserObject)
227 HeapGraphReceiver receiver;
228 Helper helper(receiver.serializer());
229 helper.addNode("ClassName", "objectName", true);
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());
238 TEST(HeapGraphSerializerTest, twoUserObjectsWithEdge)
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);
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());
257 m_strings.add("first element");
258 m_strings.add("second element");
260 void reportMemoryUsage(WTF::MemoryObjectInfo* memoryObjectInfo) const
262 WTF::MemoryClassInfo info(memoryObjectInfo, this, g_defaultObjectType);
263 info.addMember(m_strings, "strings");
266 HashSet<String> m_strings;
269 TEST(HeapGraphSerializerTest, hashSetWithTwoStrings)
271 HeapGraphReceiver receiver;
272 MemoryInstrumentationClientImpl memoryInstrumentationClient(receiver.serializer());
273 MemoryInstrumentationImpl memoryInstrumentation(&memoryInstrumentationClient);
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());