1/*
2 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 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'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 */
25
26#import "config.h"
27#import "WebMemorySampler.h"
28
29#if ENABLE(MEMORY_SAMPLER)
30
31#import <JavaScriptCore/MemoryStatistics.h>
32#import <mach/mach.h>
33#import <mach/task.h>
34#import <mach/mach_types.h>
35#import <malloc/malloc.h>
36#import <notify.h>
37#import <runtime/JSLock.h>
38#import <WebCore/JSDOMWindow.h>
39#import <wtf/CurrentTime.h>
40
41using namespace WebCore;
42using namespace JSC;
43using namespace WTF;
44
45namespace WebKit {
46
47struct SystemMallocStats {
48    malloc_statistics_t defaultMallocZoneStats;
49    malloc_statistics_t dispatchContinuationMallocZoneStats;
50    malloc_statistics_t purgeableMallocZoneStats;
51};
52
53SystemMallocStats WebMemorySampler::sampleSystemMalloc() const
54{
55    static const char* defaultMallocZoneName = "DefaultMallocZone";
56    static const char* dispatchContinuationMallocZoneName = "DispatchContinuations";
57    static const char* purgeableMallocZoneName = "DefaultPurgeableMallocZone";
58    SystemMallocStats mallocStats;
59    vm_address_t* zones;
60    unsigned count;
61
62    // Zero out the structures in case a zone is missing
63    malloc_statistics_t stats;
64    stats.blocks_in_use = 0;
65    stats.size_in_use = 0;
66    stats.max_size_in_use = 0;
67    stats.size_allocated = 0;
68    mallocStats.defaultMallocZoneStats = stats;
69    mallocStats.dispatchContinuationMallocZoneStats = stats;
70    mallocStats.purgeableMallocZoneStats = stats;
71
72    malloc_get_all_zones(mach_task_self(), 0, &zones, &count);
73    for (unsigned i = 0; i < count; i++) {
74        if (const char* name = malloc_get_zone_name(reinterpret_cast<malloc_zone_t*>(zones[i]))) {
75            stats.blocks_in_use = 0;
76            stats.size_in_use = 0;
77            stats.max_size_in_use = 0;
78            stats.size_allocated = 0;
79            malloc_zone_statistics(reinterpret_cast<malloc_zone_t*>(zones[i]), &stats);
80            if (!strcmp(name, defaultMallocZoneName))
81                mallocStats.defaultMallocZoneStats = stats;
82            else if (!strcmp(name, dispatchContinuationMallocZoneName))
83                mallocStats.dispatchContinuationMallocZoneStats = stats;
84            else if (!strcmp(name, purgeableMallocZoneName))
85                mallocStats.purgeableMallocZoneStats = stats;
86        }
87    }
88    return mallocStats;
89}
90
91size_t WebMemorySampler::sampleProcessCommittedBytes() const
92{
93    task_basic_info_64 taskInfo;
94    mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
95    task_info(mach_task_self(), TASK_BASIC_INFO_64, reinterpret_cast<task_info_t>(&taskInfo), &count);
96    return taskInfo.resident_size;
97}
98
99String WebMemorySampler::processName() const
100{
101    NSString *appName = [[NSBundle mainBundle] bundleIdentifier];
102    if (!appName)
103        appName = [[NSProcessInfo processInfo] processName];
104    return String(appName);
105}
106
107WebMemoryStatistics WebMemorySampler::sampleWebKit() const
108{
109    size_t totalBytesInUse = 0, totalBytesCommitted = 0;
110
111    WebMemoryStatistics webKitMemoryStats;
112
113    FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics();
114    size_t fastMallocBytesInUse = fastMallocStatistics.committedVMBytes - fastMallocStatistics.freeListBytes;
115    size_t fastMallocBytesCommitted = fastMallocStatistics.committedVMBytes;
116    totalBytesInUse += fastMallocBytesInUse;
117    totalBytesCommitted += fastMallocBytesCommitted;
118
119    JSLockHolder lock(JSDOMWindow::commonVM());
120    size_t jscHeapBytesInUse = JSDOMWindow::commonVM().heap.size();
121    size_t jscHeapBytesCommitted = JSDOMWindow::commonVM().heap.capacity();
122    totalBytesInUse += jscHeapBytesInUse;
123    totalBytesCommitted += jscHeapBytesCommitted;
124
125    GlobalMemoryStatistics globalMemoryStats = globalMemoryStatistics();
126    totalBytesInUse += globalMemoryStats.stackBytes + globalMemoryStats.JITBytes;
127    totalBytesCommitted += globalMemoryStats.stackBytes + globalMemoryStats.JITBytes;
128
129    SystemMallocStats systemStats = sampleSystemMalloc();
130
131    size_t defaultMallocZoneBytesInUse = systemStats.defaultMallocZoneStats.size_in_use;
132    size_t dispatchContinuationMallocZoneBytesInUse = systemStats.dispatchContinuationMallocZoneStats.size_in_use;
133    size_t purgeableMallocZoneBytesInUse = systemStats.purgeableMallocZoneStats.size_in_use;
134    size_t defaultMallocZoneBytesCommitted = systemStats.defaultMallocZoneStats.size_allocated;
135    size_t dispatchContinuationMallocZoneBytesCommitted = systemStats.dispatchContinuationMallocZoneStats.size_allocated;
136    size_t purgeableMallocZoneBytesCommitted = systemStats.purgeableMallocZoneStats.size_allocated;
137    totalBytesInUse += defaultMallocZoneBytesInUse + dispatchContinuationMallocZoneBytesInUse + purgeableMallocZoneBytesInUse;
138    totalBytesCommitted += defaultMallocZoneBytesCommitted + dispatchContinuationMallocZoneBytesCommitted + purgeableMallocZoneBytesCommitted;
139
140    size_t residentSize = sampleProcessCommittedBytes();
141
142    double now = currentTime();
143
144    webKitMemoryStats.keys.append(String("Timestamp"));
145    webKitMemoryStats.values.append(now);
146    webKitMemoryStats.keys.append(String("Total Bytes of Memory In Use"));
147    webKitMemoryStats.values.append(totalBytesInUse);
148    webKitMemoryStats.keys.append(String("Fast Malloc Zone Bytes"));
149    webKitMemoryStats.values.append(fastMallocBytesInUse);
150    webKitMemoryStats.keys.append(String("Default Malloc Zone Bytes"));
151    webKitMemoryStats.values.append(defaultMallocZoneBytesInUse);
152    webKitMemoryStats.keys.append(String("Dispatch Continuation Malloc Zone Bytes"));
153    webKitMemoryStats.values.append(dispatchContinuationMallocZoneBytesInUse);
154    webKitMemoryStats.keys.append(String("Purgeable Malloc Zone Bytes"));
155    webKitMemoryStats.values.append(purgeableMallocZoneBytesInUse);
156    webKitMemoryStats.keys.append(String("JavaScript Heap Bytes"));
157    webKitMemoryStats.values.append(jscHeapBytesInUse);
158    webKitMemoryStats.keys.append(String("Total Bytes of Committed Memory"));
159    webKitMemoryStats.values.append(totalBytesCommitted);
160    webKitMemoryStats.keys.append(String("Fast Malloc Zone Bytes"));
161    webKitMemoryStats.values.append(fastMallocBytesCommitted);
162    webKitMemoryStats.keys.append(String("Default Malloc Zone Bytes"));
163    webKitMemoryStats.values.append(defaultMallocZoneBytesCommitted);
164    webKitMemoryStats.keys.append(String("Dispatch Continuation Malloc Zone Bytes"));
165    webKitMemoryStats.values.append(dispatchContinuationMallocZoneBytesCommitted);
166    webKitMemoryStats.keys.append(String("Purgeable Malloc Zone Bytes"));
167    webKitMemoryStats.values.append(purgeableMallocZoneBytesCommitted);
168    webKitMemoryStats.keys.append(String("JavaScript Heap Bytes"));
169    webKitMemoryStats.values.append(jscHeapBytesCommitted);
170    webKitMemoryStats.keys.append(String("JavaScript Stack Bytes"));
171    webKitMemoryStats.values.append(globalMemoryStats.stackBytes);
172    webKitMemoryStats.keys.append(String("JavaScript JIT Bytes"));
173    webKitMemoryStats.values.append(globalMemoryStats.JITBytes);
174    webKitMemoryStats.keys.append(String("Resident Size"));
175    webKitMemoryStats.values.append(residentSize);
176
177    return webKitMemoryStats;
178}
179
180void WebMemorySampler::sendMemoryPressureEvent()
181{
182    // Free memory that could be released if we needed more.
183    // We want to track memory that cannot.
184    notify_post("org.WebKit.lowMemory");
185}
186
187}
188
189#endif
190
191