| /* |
| * 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 |
| |