summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/heap/HeapStatistics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/heap/HeapStatistics.cpp')
-rw-r--r--Source/JavaScriptCore/heap/HeapStatistics.cpp258
1 files changed, 258 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/heap/HeapStatistics.cpp b/Source/JavaScriptCore/heap/HeapStatistics.cpp
new file mode 100644
index 000000000..68044e0b3
--- /dev/null
+++ b/Source/JavaScriptCore/heap/HeapStatistics.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HeapStatistics.h"
+
+#include "Heap.h"
+#include "JSObject.h"
+#include "Options.h"
+#include <stdlib.h>
+#if OS(UNIX)
+#include <sys/resource.h>
+#endif
+#include <wtf/CurrentTime.h>
+#include <wtf/DataLog.h>
+#include <wtf/Deque.h>
+
+namespace JSC {
+
+double HeapStatistics::s_startTime = 0.0;
+double HeapStatistics::s_endTime = 0.0;
+Deque<double>* HeapStatistics::s_pauseTimeStarts = 0;
+Deque<double>* HeapStatistics::s_pauseTimeEnds = 0;
+
+#if OS(UNIX)
+
+void HeapStatistics::initialize()
+{
+ ASSERT(Options::recordGCPauseTimes());
+ s_startTime = WTF::monotonicallyIncreasingTime();
+ s_pauseTimeStarts = new Deque<double>();
+ s_pauseTimeEnds = new Deque<double>();
+}
+
+void HeapStatistics::recordGCPauseTime(double start, double end)
+{
+ ASSERT(Options::recordGCPauseTimes());
+ ASSERT(s_pauseTimeStarts);
+ ASSERT(s_pauseTimeEnds);
+ s_pauseTimeStarts->append(start);
+ s_pauseTimeEnds->append(end);
+}
+
+void HeapStatistics::logStatistics()
+{
+ struct rusage usage;
+ getrusage(RUSAGE_SELF, &usage);
+#if USE(CF) || OS(UNIX)
+ char* vmName = getenv("JSVMName");
+ char* suiteName = getenv("JSSuiteName");
+ char* benchmarkName = getenv("JSBenchmarkName");
+#else
+#error "The HeapStatistics module is not supported on this platform."
+#endif
+ if (!vmName || !suiteName || !benchmarkName)
+ dataLog("HeapStatistics: {\"max_rss\": %ld", usage.ru_maxrss);
+ else
+ dataLog("HeapStatistics: {\"max_rss\": %ld, \"vm_name\": \"%s\", \"suite_name\": \"%s\", \"benchmark_name\": \"%s\"",
+ usage.ru_maxrss, vmName, suiteName, benchmarkName);
+
+ if (Options::recordGCPauseTimes()) {
+ dataLog(", \"pause_times\": [");
+ Deque<double>::iterator startIt = s_pauseTimeStarts->begin();
+ Deque<double>::iterator endIt = s_pauseTimeEnds->begin();
+ if (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
+ dataLog("[%f, %f]", *startIt, *endIt);
+ ++startIt;
+ ++endIt;
+ }
+ while (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
+ dataLog(", [%f, %f]", *startIt, *endIt);
+ ++startIt;
+ ++endIt;
+ }
+ dataLog("], \"start_time\": %f, \"end_time\": %f", s_startTime, s_endTime);
+ }
+ dataLog("}\n");
+}
+
+void HeapStatistics::exitWithFailure()
+{
+ ASSERT(Options::logHeapStatisticsAtExit());
+ s_endTime = WTF::monotonicallyIncreasingTime();
+ logStatistics();
+ exit(-1);
+}
+
+void HeapStatistics::reportSuccess()
+{
+ ASSERT(Options::logHeapStatisticsAtExit());
+ s_endTime = WTF::monotonicallyIncreasingTime();
+ logStatistics();
+}
+
+#else
+
+void HeapStatistics::initialize()
+{
+}
+
+void HeapStatistics::recordGCPauseTime(double, double)
+{
+}
+
+void HeapStatistics::logStatistics()
+{
+}
+
+void HeapStatistics::exitWithFailure()
+{
+}
+
+void HeapStatistics::reportSuccess()
+{
+}
+
+#endif // OS(UNIX)
+
+size_t HeapStatistics::usedJSHeap()
+{
+ JSGlobalData* globalData = &JSGlobalData::sharedInstance();
+ return globalData->heap.size();
+}
+
+size_t HeapStatistics::parseMemoryAmount(char* s)
+{
+ size_t multiplier = 1;
+ char* afterS;
+ size_t value = strtol(s, &afterS, 10);
+ char next = afterS[0];
+ switch (next) {
+ case 'K':
+ multiplier = KB;
+ break;
+ case 'M':
+ multiplier = MB;
+ break;
+ case 'G':
+ multiplier = GB;
+ break;
+ default:
+ break;
+ }
+ return value * multiplier;
+}
+
+class StorageStatistics : public MarkedBlock::VoidFunctor {
+public:
+ StorageStatistics();
+
+ void operator()(JSCell*);
+
+ size_t objectWithOutOfLineStorageCount();
+ size_t objectCount();
+
+ size_t storageSize();
+ size_t storageCapacity();
+
+private:
+ size_t m_objectWithOutOfLineStorageCount;
+ size_t m_objectCount;
+ size_t m_storageSize;
+ size_t m_storageCapacity;
+};
+
+inline StorageStatistics::StorageStatistics()
+ : m_objectWithOutOfLineStorageCount(0)
+ , m_objectCount(0)
+ , m_storageSize(0)
+ , m_storageCapacity(0)
+{
+}
+
+inline void StorageStatistics::operator()(JSCell* cell)
+{
+ if (!cell->isObject())
+ return;
+
+ JSObject* object = jsCast<JSObject*>(cell);
+ if (hasIndexedProperties(object->structure()->indexingType()))
+ return;
+
+ if (object->structure()->isUncacheableDictionary())
+ return;
+
+ ++m_objectCount;
+ if (!object->hasInlineStorage())
+ ++m_objectWithOutOfLineStorageCount;
+ m_storageSize += object->structure()->totalStorageSize() * sizeof(WriteBarrierBase<Unknown>);
+ m_storageCapacity += object->structure()->totalStorageCapacity() * sizeof(WriteBarrierBase<Unknown>);
+}
+
+inline size_t StorageStatistics::objectWithOutOfLineStorageCount()
+{
+ return m_objectWithOutOfLineStorageCount;
+}
+
+inline size_t StorageStatistics::objectCount()
+{
+ return m_objectCount;
+}
+
+inline size_t StorageStatistics::storageSize()
+{
+ return m_storageSize;
+}
+
+inline size_t StorageStatistics::storageCapacity()
+{
+ return m_storageCapacity;
+}
+
+void HeapStatistics::showObjectStatistics(Heap* heap)
+{
+ dataLog("\n=== Heap Statistics: ===\n");
+ dataLog("size: %ldkB\n", static_cast<long>(heap->m_sizeAfterLastCollect / KB));
+ dataLog("capacity: %ldkB\n", static_cast<long>(heap->capacity() / KB));
+ dataLog("pause time: %lfms\n\n", heap->m_lastGCLength);
+
+ StorageStatistics storageStatistics;
+ heap->m_objectSpace.forEachLiveCell(storageStatistics);
+ dataLog("wasted .property storage: %ldkB (%ld%%)\n",
+ static_cast<long>(
+ (storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB),
+ static_cast<long>(
+ (storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100
+ / storageStatistics.storageCapacity()));
+ dataLog("objects with out-of-line .property storage: %ld (%ld%%)\n",
+ static_cast<long>(
+ storageStatistics.objectWithOutOfLineStorageCount()),
+ static_cast<long>(
+ storageStatistics.objectWithOutOfLineStorageCount() * 100
+ / storageStatistics.objectCount()));
+}
+
+} // namespace JSC