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