blob: 2395805adec34c7f2f0add932e372f4ef91885c4 [file] [log] [blame]
/*
* 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) && !defined (__LB_SHELL__)
#include <sys/resource.h>
#endif
#include <wtf/CurrentTime.h>
#include <wtf/DataLog.h>
#include <wtf/Deque.h>
#if COMPILER(GHS)
#include "JSDestructibleObject.h"
#endif
namespace JSC {
double HeapStatistics::s_startTime = 0.0;
double HeapStatistics::s_endTime = 0.0;
Vector<double>* HeapStatistics::s_pauseTimeStarts = 0;
Vector<double>* HeapStatistics::s_pauseTimeEnds = 0;
#if OS(UNIX) && !defined (__LB_SHELL__)
void HeapStatistics::initialize()
{
ASSERT(Options::recordGCPauseTimes());
s_startTime = WTF::monotonicallyIncreasingTime();
s_pauseTimeStarts = new Vector<double>();
s_pauseTimeEnds = new Vector<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)
dataLogF("HeapStatistics: {\"max_rss\": %ld", usage.ru_maxrss);
else
dataLogF("HeapStatistics: {\"max_rss\": %ld, \"vm_name\": \"%s\", \"suite_name\": \"%s\", \"benchmark_name\": \"%s\"",
usage.ru_maxrss, vmName, suiteName, benchmarkName);
if (Options::recordGCPauseTimes()) {
dataLogF(", \"pause_times\": [");
Vector<double>::iterator startIt = s_pauseTimeStarts->begin();
Vector<double>::iterator endIt = s_pauseTimeEnds->begin();
if (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
dataLogF("[%f, %f]", *startIt, *endIt);
++startIt;
++endIt;
}
while (startIt != s_pauseTimeStarts->end() && endIt != s_pauseTimeEnds->end()) {
dataLogF(", [%f, %f]", *startIt, *endIt);
++startIt;
++endIt;
}
dataLogF("], \"start_time\": %f, \"end_time\": %f", s_startTime, s_endTime);
}
dataLogF("}\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()
{
exit(1);
}
void HeapStatistics::reportSuccess()
{
}
#endif // OS(UNIX)
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)
{
dataLogF("\n=== Heap Statistics: ===\n");
dataLogF("size: %ldkB\n", static_cast<long>(heap->m_sizeAfterLastCollect / KB));
dataLogF("capacity: %ldkB\n", static_cast<long>(heap->capacity() / KB));
dataLogF("pause time: %lfms\n\n", heap->m_lastGCLength);
StorageStatistics storageStatistics;
heap->m_objectSpace.forEachLiveCell(storageStatistics);
dataLogF("wasted .property storage: %ldkB (%ld%%)\n",
static_cast<long>(
(storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB),
static_cast<long>(
(storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100
/ storageStatistics.storageCapacity()));
dataLogF("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