Unreviewed, rolling out r209766.
[WebKit.git] / Source / JavaScriptCore / heap / HeapStatistics.cpp
1 /*
2  * Copyright (C) 2012, 2016 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 "MarkedSpaceInlines.h"
34 #include "Options.h"
35 #include <stdlib.h>
36 #include <wtf/CurrentTime.h>
37 #include <wtf/DataLog.h>
38 #include <wtf/StdLibExtras.h>
39
40 #if OS(UNIX)
41 #include <sys/resource.h>
42 #endif
43
44 namespace JSC {
45
46 double HeapStatistics::s_startTime = 0.0;
47 double HeapStatistics::s_endTime = 0.0;
48 Vector<double>* HeapStatistics::s_pauseTimeStarts = 0;
49 Vector<double>* HeapStatistics::s_pauseTimeEnds = 0;
50
51 #if OS(UNIX) 
52
53 void HeapStatistics::initialize()
54 {
55     ASSERT(Options::recordGCPauseTimes());
56     s_startTime = WTF::monotonicallyIncreasingTime();
57     s_pauseTimeStarts = new Vector<double>();
58     s_pauseTimeEnds = new Vector<double>();
59 }
60
61 void HeapStatistics::recordGCPauseTime(double start, double end)
62 {
63     ASSERT(Options::recordGCPauseTimes());
64     ASSERT(s_pauseTimeStarts);
65     ASSERT(s_pauseTimeEnds);
66     s_pauseTimeStarts->append(start);
67     s_pauseTimeEnds->append(end);
68 }
69
70 void HeapStatistics::logStatistics()
71 {
72     struct rusage usage;
73     getrusage(RUSAGE_SELF, &usage);
74 #if USE(CF) || OS(UNIX)
75     char* vmName = getenv("JSVMName");
76     char* suiteName = getenv("JSSuiteName");
77     char* benchmarkName = getenv("JSBenchmarkName");
78 #else
79 #error "The HeapStatistics module is not supported on this platform."
80 #endif
81     if (!vmName || !suiteName || !benchmarkName)
82         dataLogF("HeapStatistics: {\"max_rss\": %ld", usage.ru_maxrss);
83     else
84         dataLogF("HeapStatistics: {\"max_rss\": %ld, \"vm_name\": \"%s\", \"suite_name\": \"%s\", \"benchmark_name\": \"%s\"", 
85             usage.ru_maxrss, vmName, suiteName, benchmarkName); 
86
87     if (Options::recordGCPauseTimes()) {
88         dataLogF(", \"pause_times\": [");
89         Vector<double>::iterator startIt = s_pauseTimeStarts->begin();
90         Vector<double>::iterator endIt = s_pauseTimeEnds->begin();
91         if (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
92             dataLogF("[%f, %f]", *startIt, *endIt);
93             ++startIt;
94             ++endIt;
95         }
96         while (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
97             dataLogF(", [%f, %f]", *startIt, *endIt);
98             ++startIt;
99             ++endIt;
100         }
101         dataLogF("], \"start_time\": %f, \"end_time\": %f", s_startTime, s_endTime);
102     }
103     dataLogF("}\n");
104 }
105
106 void HeapStatistics::exitWithFailure()
107 {
108     ASSERT(Options::logHeapStatisticsAtExit());
109     s_endTime = WTF::monotonicallyIncreasingTime();
110     logStatistics();
111     exit(-1);
112 }
113
114 void HeapStatistics::reportSuccess()
115 {
116     ASSERT(Options::logHeapStatisticsAtExit());
117     s_endTime = WTF::monotonicallyIncreasingTime();
118     logStatistics();
119 }
120
121 #else
122
123 void HeapStatistics::initialize()
124 {
125 }
126
127 void HeapStatistics::recordGCPauseTime(double, double)
128 {
129 }
130
131 void HeapStatistics::logStatistics()
132 {
133 }
134
135 void HeapStatistics::exitWithFailure()
136 {
137     exit(-1);
138 }
139
140 void HeapStatistics::reportSuccess()
141 {
142 }
143
144 #endif // OS(UNIX)
145
146 class StorageStatistics : public MarkedBlock::VoidFunctor {
147 public:
148     StorageStatistics();
149
150     IterationStatus operator()(HeapCell*, HeapCell::Kind) const;
151
152     size_t objectWithOutOfLineStorageCount();
153     size_t objectCount();
154
155     size_t storageSize();
156     size_t storageCapacity();
157
158 private:
159     void visit(JSCell*);
160
161     size_t m_objectWithOutOfLineStorageCount;
162     size_t m_objectCount;
163     size_t m_storageSize;
164     size_t m_storageCapacity;
165 };
166
167 inline StorageStatistics::StorageStatistics()
168     : m_objectWithOutOfLineStorageCount(0)
169     , m_objectCount(0)
170     , m_storageSize(0)
171     , m_storageCapacity(0)
172 {
173 }
174
175 inline void StorageStatistics::visit(JSCell* cell)
176 {
177     if (!cell->isObject())
178         return;
179
180     JSObject* object = jsCast<JSObject*>(cell);
181     if (hasIndexedProperties(object->indexingType()))
182         return;
183
184     if (object->structure()->isUncacheableDictionary())
185         return;
186
187     ++m_objectCount;
188     if (!object->hasInlineStorage())
189         ++m_objectWithOutOfLineStorageCount;
190     m_storageSize += object->structure()->totalStorageSize() * sizeof(WriteBarrierBase<Unknown>);
191     m_storageCapacity += object->structure()->totalStorageCapacity() * sizeof(WriteBarrierBase<Unknown>); 
192 }
193
194 inline IterationStatus StorageStatistics::operator()(HeapCell* cell, HeapCell::Kind kind) const
195 {
196     if (kind == HeapCell::JSCell) {
197         // FIXME: This const_cast exists because this isn't a C++ lambda.
198         // https://bugs.webkit.org/show_bug.cgi?id=159644
199         const_cast<StorageStatistics*>(this)->visit(static_cast<JSCell*>(cell));
200     }
201     return IterationStatus::Continue;
202 }
203
204 inline size_t StorageStatistics::objectWithOutOfLineStorageCount()
205 {
206     return m_objectWithOutOfLineStorageCount;
207 }
208
209 inline size_t StorageStatistics::objectCount()
210 {
211     return m_objectCount;
212 }
213
214 inline size_t StorageStatistics::storageSize()
215 {
216     return m_storageSize;
217 }
218
219 inline size_t StorageStatistics::storageCapacity()
220 {
221     return m_storageCapacity;
222 }
223
224 void HeapStatistics::dumpObjectStatistics(Heap* heap)
225 {
226     dataLogF("\n=== Heap Statistics: ===\n");
227     dataLogF("size: %ldkB\n", static_cast<long>(heap->m_sizeAfterLastCollect / KB));
228     dataLogF("capacity: %ldkB\n", static_cast<long>(heap->capacity() / KB));
229     dataLogF("pause time: %lfs\n\n", heap->m_lastFullGCLength);
230
231     StorageStatistics storageStatistics;
232     {
233         HeapIterationScope iterationScope(*heap);
234         heap->m_objectSpace.forEachLiveCell(iterationScope, storageStatistics);
235     }
236     long wastedPropertyStorageBytes = 0;
237     long wastedPropertyStoragePercent = 0;
238     long objectWithOutOfLineStorageCount = 0;
239     long objectsWithOutOfLineStoragePercent = 0;
240     if ((storageStatistics.storageCapacity() > 0) && (storageStatistics.objectCount() > 0)) {
241         wastedPropertyStorageBytes = static_cast<long>((storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB);
242         wastedPropertyStoragePercent = static_cast<long>(
243             (storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100 / storageStatistics.storageCapacity());
244         objectWithOutOfLineStorageCount = static_cast<long>(storageStatistics.objectWithOutOfLineStorageCount());
245         objectsWithOutOfLineStoragePercent = objectWithOutOfLineStorageCount * 100 / storageStatistics.objectCount();
246     }
247     dataLogF("wasted .property storage: %ldkB (%ld%%)\n", wastedPropertyStorageBytes, wastedPropertyStoragePercent);
248     dataLogF("objects with out-of-line .property storage: %ld (%ld%%)\n", objectWithOutOfLineStorageCount, objectsWithOutOfLineStoragePercent);
249 }
250
251 } // namespace JSC