1/*
2 * Copyright (C) 2012 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "HeapStatistics.h"
28
29#include "Heap.h"
30#include "HeapIterationScope.h"
31#include "JSCInlines.h"
32#include "JSObject.h"
33#include "Options.h"
34#include <stdlib.h>
35#include <wtf/CurrentTime.h>
36#include <wtf/DataLog.h>
37#include <wtf/StdLibExtras.h>
38
39#if OS(UNIX)
40#include <sys/resource.h>
41#endif
42
43namespace JSC {
44
45double HeapStatistics::s_startTime = 0.0;
46double HeapStatistics::s_endTime = 0.0;
47Vector<double>* HeapStatistics::s_pauseTimeStarts = 0;
48Vector<double>* HeapStatistics::s_pauseTimeEnds = 0;
49
50#if OS(UNIX)
51
52void HeapStatistics::initialize()
53{
54 ASSERT(Options::recordGCPauseTimes());
55 s_startTime = WTF::monotonicallyIncreasingTime();
56 s_pauseTimeStarts = new Vector<double>();
57 s_pauseTimeEnds = new Vector<double>();
58}
59
60void HeapStatistics::recordGCPauseTime(double start, double end)
61{
62 ASSERT(Options::recordGCPauseTimes());
63 ASSERT(s_pauseTimeStarts);
64 ASSERT(s_pauseTimeEnds);
65 s_pauseTimeStarts->append(start);
66 s_pauseTimeEnds->append(end);
67}
68
69void HeapStatistics::logStatistics()
70{
71 struct rusage usage;
72 getrusage(RUSAGE_SELF, &usage);
73#if USE(CF) || OS(UNIX)
74 char* vmName = getenv("JSVMName");
75 char* suiteName = getenv("JSSuiteName");
76 char* benchmarkName = getenv("JSBenchmarkName");
77#else
78#error "The HeapStatistics module is not supported on this platform."
79#endif
80 if (!vmName || !suiteName || !benchmarkName)
81 dataLogF("HeapStatistics: {\"max_rss\": %ld", usage.ru_maxrss);
82 else
83 dataLogF("HeapStatistics: {\"max_rss\": %ld, \"vm_name\": \"%s\", \"suite_name\": \"%s\", \"benchmark_name\": \"%s\"",
84 usage.ru_maxrss, vmName, suiteName, benchmarkName);
85
86 if (Options::recordGCPauseTimes()) {
87 dataLogF(", \"pause_times\": [");
88 Vector<double>::iterator startIt = s_pauseTimeStarts->begin();
89 Vector<double>::iterator endIt = s_pauseTimeEnds->begin();
90 if (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
91 dataLogF("[%f, %f]", *startIt, *endIt);
92 ++startIt;
93 ++endIt;
94 }
95 while (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
96 dataLogF(", [%f, %f]", *startIt, *endIt);
97 ++startIt;
98 ++endIt;
99 }
100 dataLogF("], \"start_time\": %f, \"end_time\": %f", s_startTime, s_endTime);
101 }
102 dataLogF("}\n");
103}
104
105void HeapStatistics::exitWithFailure()
106{
107 ASSERT(Options::logHeapStatisticsAtExit());
108 s_endTime = WTF::monotonicallyIncreasingTime();
109 logStatistics();
110 exit(-1);
111}
112
113void HeapStatistics::reportSuccess()
114{
115 ASSERT(Options::logHeapStatisticsAtExit());
116 s_endTime = WTF::monotonicallyIncreasingTime();
117 logStatistics();
118}
119
120#else
121
122void HeapStatistics::initialize()
123{
124}
125
126void HeapStatistics::recordGCPauseTime(double, double)
127{
128}
129
130void HeapStatistics::logStatistics()
131{
132}
133
134void HeapStatistics::exitWithFailure()
135{
136 exit(-1);
137}
138
139void HeapStatistics::reportSuccess()
140{
141}
142
143#endif // OS(UNIX)
144
145class StorageStatistics : public MarkedBlock::VoidFunctor {
146public:
147 StorageStatistics();
148
149 IterationStatus operator()(JSCell*);
150
151 size_t objectWithOutOfLineStorageCount();
152 size_t objectCount();
153
154 size_t storageSize();
155 size_t storageCapacity();
156
157private:
158 void visit(JSCell*);
159
160 size_t m_objectWithOutOfLineStorageCount;
161 size_t m_objectCount;
162 size_t m_storageSize;
163 size_t m_storageCapacity;
164};
165
166inline StorageStatistics::StorageStatistics()
167 : m_objectWithOutOfLineStorageCount(0)
168 , m_objectCount(0)
169 , m_storageSize(0)
170 , m_storageCapacity(0)
171{
172}
173
174inline void StorageStatistics::visit(JSCell* cell)
175{
176 if (!cell->isObject())
177 return;
178
179 JSObject* object = jsCast<JSObject*>(cell);
180 if (hasIndexedProperties(object->indexingType()))
181 return;
182
183 if (object->structure()->isUncacheableDictionary())
184 return;
185
186 ++m_objectCount;
187 if (!object->hasInlineStorage())
188 ++m_objectWithOutOfLineStorageCount;
189 m_storageSize += object->structure()->totalStorageSize() * sizeof(WriteBarrierBase<Unknown>);
190 m_storageCapacity += object->structure()->totalStorageCapacity() * sizeof(WriteBarrierBase<Unknown>);
191}
192
193inline IterationStatus StorageStatistics::operator()(JSCell* cell)
194{
195 visit(cell);
196 return IterationStatus::Continue;
197}
198
199inline size_t StorageStatistics::objectWithOutOfLineStorageCount()
200{
201 return m_objectWithOutOfLineStorageCount;
202}
203
204inline size_t StorageStatistics::objectCount()
205{
206 return m_objectCount;
207}
208
209inline size_t StorageStatistics::storageSize()
210{
211 return m_storageSize;
212}
213
214inline size_t StorageStatistics::storageCapacity()
215{
216 return m_storageCapacity;
217}
218
219void HeapStatistics::dumpObjectStatistics(Heap* heap)
220{
221 dataLogF("\n=== Heap Statistics: ===\n");
222 dataLogF("size: %ldkB\n", static_cast<long>(heap->m_sizeAfterLastCollect / KB));
223 dataLogF("capacity: %ldkB\n", static_cast<long>(heap->capacity() / KB));
224 dataLogF("pause time: %lfs\n\n", heap->m_lastFullGCLength);
225
226 StorageStatistics storageStatistics;
227 {
228 HeapIterationScope iterationScope(*heap);
229 heap->m_objectSpace.forEachLiveCell(iterationScope, storageStatistics);
230 }
231 long wastedPropertyStorageBytes = 0;
232 long wastedPropertyStoragePercent = 0;
233 long objectWithOutOfLineStorageCount = 0;
234 long objectsWithOutOfLineStoragePercent = 0;
235 if ((storageStatistics.storageCapacity() > 0) && (storageStatistics.objectCount() > 0)) {
236 wastedPropertyStorageBytes = static_cast<long>((storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB);
237 wastedPropertyStoragePercent = static_cast<long>(
238 (storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100 / storageStatistics.storageCapacity());
239 objectWithOutOfLineStorageCount = static_cast<long>(storageStatistics.objectWithOutOfLineStorageCount());
240 objectsWithOutOfLineStoragePercent = objectWithOutOfLineStorageCount * 100 / storageStatistics.objectCount();
241 }
242 dataLogF("wasted .property storage: %ldkB (%ld%%)\n", wastedPropertyStorageBytes, wastedPropertyStoragePercent);
243 dataLogF("objects with out-of-line .property storage: %ld (%ld%%)\n", objectWithOutOfLineStorageCount, objectsWithOutOfLineStoragePercent);
244}
245
246} // namespace JSC
247