blob: 7d3a40430cd539a629d923996c5004fed3dfc17a [file] [log] [blame]
/*
* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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.
*
*/
#import "config.h"
#import "WebMemorySampler.h"
#if ENABLE(MEMORY_SAMPLER)
#import <JavaScriptCore/JSLock.h>
#import <JavaScriptCore/MemoryStatistics.h>
#import <JavaScriptCore/VM.h>
#import <WebCore/CommonVM.h>
#import <mach/mach.h>
#import <mach/mach_types.h>
#import <mach/task.h>
#import <malloc/malloc.h>
#import <notify.h>
#import <wtf/WallTime.h>
namespace WebKit {
struct SystemMallocStats {
malloc_statistics_t defaultMallocZoneStats;
malloc_statistics_t dispatchContinuationMallocZoneStats;
malloc_statistics_t purgeableMallocZoneStats;
};
SystemMallocStats WebMemorySampler::sampleSystemMalloc() const
{
static const char* defaultMallocZoneName = "DefaultMallocZone";
static const char* dispatchContinuationMallocZoneName = "DispatchContinuations";
static const char* purgeableMallocZoneName = "DefaultPurgeableMallocZone";
SystemMallocStats mallocStats;
vm_address_t* zones;
unsigned count;
// Zero out the structures in case a zone is missing
malloc_statistics_t stats;
stats.blocks_in_use = 0;
stats.size_in_use = 0;
stats.max_size_in_use = 0;
stats.size_allocated = 0;
mallocStats.defaultMallocZoneStats = stats;
mallocStats.dispatchContinuationMallocZoneStats = stats;
mallocStats.purgeableMallocZoneStats = stats;
malloc_get_all_zones(mach_task_self(), 0, &zones, &count);
for (unsigned i = 0; i < count; i++) {
if (const char* name = malloc_get_zone_name(reinterpret_cast<malloc_zone_t*>(zones[i]))) {
stats.blocks_in_use = 0;
stats.size_in_use = 0;
stats.max_size_in_use = 0;
stats.size_allocated = 0;
malloc_zone_statistics(reinterpret_cast<malloc_zone_t*>(zones[i]), &stats);
if (!strcmp(name, defaultMallocZoneName))
mallocStats.defaultMallocZoneStats = stats;
else if (!strcmp(name, dispatchContinuationMallocZoneName))
mallocStats.dispatchContinuationMallocZoneStats = stats;
else if (!strcmp(name, purgeableMallocZoneName))
mallocStats.purgeableMallocZoneStats = stats;
}
}
return mallocStats;
}
size_t WebMemorySampler::sampleProcessCommittedBytes() const
{
task_basic_info_64 taskInfo;
mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
task_info(mach_task_self(), TASK_BASIC_INFO_64, reinterpret_cast<task_info_t>(&taskInfo), &count);
return taskInfo.resident_size;
}
String WebMemorySampler::processName() const
{
NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
if (!appName)
appName = [[NSProcessInfo processInfo] processName];
return String(appName);
}
WebMemoryStatistics WebMemorySampler::sampleWebKit() const
{
size_t totalBytesInUse = 0, totalBytesCommitted = 0;
WebMemoryStatistics webKitMemoryStats;
auto fastMallocStatistics = WTF::fastMallocStatistics();
size_t fastMallocBytesInUse = fastMallocStatistics.committedVMBytes - fastMallocStatistics.freeListBytes;
size_t fastMallocBytesCommitted = fastMallocStatistics.committedVMBytes;
totalBytesInUse += fastMallocBytesInUse;
totalBytesCommitted += fastMallocBytesCommitted;
JSC::JSLockHolder lock(WebCore::commonVM());
size_t jscHeapBytesInUse = WebCore::commonVM().heap.size();
size_t jscHeapBytesCommitted = WebCore::commonVM().heap.capacity();
totalBytesInUse += jscHeapBytesInUse;
totalBytesCommitted += jscHeapBytesCommitted;
JSC::GlobalMemoryStatistics globalMemoryStats = JSC::globalMemoryStatistics();
totalBytesInUse += globalMemoryStats.stackBytes + globalMemoryStats.JITBytes;
totalBytesCommitted += globalMemoryStats.stackBytes + globalMemoryStats.JITBytes;
SystemMallocStats systemStats = sampleSystemMalloc();
size_t defaultMallocZoneBytesInUse = systemStats.defaultMallocZoneStats.size_in_use;
size_t dispatchContinuationMallocZoneBytesInUse = systemStats.dispatchContinuationMallocZoneStats.size_in_use;
size_t purgeableMallocZoneBytesInUse = systemStats.purgeableMallocZoneStats.size_in_use;
size_t defaultMallocZoneBytesCommitted = systemStats.defaultMallocZoneStats.size_allocated;
size_t dispatchContinuationMallocZoneBytesCommitted = systemStats.dispatchContinuationMallocZoneStats.size_allocated;
size_t purgeableMallocZoneBytesCommitted = systemStats.purgeableMallocZoneStats.size_allocated;
totalBytesInUse += defaultMallocZoneBytesInUse + dispatchContinuationMallocZoneBytesInUse + purgeableMallocZoneBytesInUse;
totalBytesCommitted += defaultMallocZoneBytesCommitted + dispatchContinuationMallocZoneBytesCommitted + purgeableMallocZoneBytesCommitted;
size_t residentSize = sampleProcessCommittedBytes();
WallTime now = WallTime::now();
webKitMemoryStats.keys.append(String("Timestamp"));
webKitMemoryStats.values.append(now.secondsSinceEpoch().seconds());
webKitMemoryStats.keys.append(String("Total Bytes of Memory In Use"));
webKitMemoryStats.values.append(totalBytesInUse);
webKitMemoryStats.keys.append(String("Fast Malloc Zone Bytes"));
webKitMemoryStats.values.append(fastMallocBytesInUse);
webKitMemoryStats.keys.append(String("Default Malloc Zone Bytes"));
webKitMemoryStats.values.append(defaultMallocZoneBytesInUse);
webKitMemoryStats.keys.append(String("Dispatch Continuation Malloc Zone Bytes"));
webKitMemoryStats.values.append(dispatchContinuationMallocZoneBytesInUse);
webKitMemoryStats.keys.append(String("Purgeable Malloc Zone Bytes"));
webKitMemoryStats.values.append(purgeableMallocZoneBytesInUse);
webKitMemoryStats.keys.append(String("JavaScript Heap Bytes"));
webKitMemoryStats.values.append(jscHeapBytesInUse);
webKitMemoryStats.keys.append(String("Total Bytes of Committed Memory"));
webKitMemoryStats.values.append(totalBytesCommitted);
webKitMemoryStats.keys.append(String("Fast Malloc Zone Bytes"));
webKitMemoryStats.values.append(fastMallocBytesCommitted);
webKitMemoryStats.keys.append(String("Default Malloc Zone Bytes"));
webKitMemoryStats.values.append(defaultMallocZoneBytesCommitted);
webKitMemoryStats.keys.append(String("Dispatch Continuation Malloc Zone Bytes"));
webKitMemoryStats.values.append(dispatchContinuationMallocZoneBytesCommitted);
webKitMemoryStats.keys.append(String("Purgeable Malloc Zone Bytes"));
webKitMemoryStats.values.append(purgeableMallocZoneBytesCommitted);
webKitMemoryStats.keys.append(String("JavaScript Heap Bytes"));
webKitMemoryStats.values.append(jscHeapBytesCommitted);
webKitMemoryStats.keys.append(String("JavaScript Stack Bytes"));
webKitMemoryStats.values.append(globalMemoryStats.stackBytes);
webKitMemoryStats.keys.append(String("JavaScript JIT Bytes"));
webKitMemoryStats.values.append(globalMemoryStats.JITBytes);
webKitMemoryStats.keys.append(String("Resident Size"));
webKitMemoryStats.values.append(residentSize);
return webKitMemoryStats;
}
void WebMemorySampler::sendMemoryPressureEvent()
{
// Free memory that could be released if we needed more.
// We want to track memory that cannot.
notify_post("org.WebKit.lowMemory");
}
}
#endif