diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index 2722ce3034234b122a18211bdbd0c2b13ff39c83..e772750ed83225ff6492f1667bded4e1af19c859 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,15 @@ +2011-01-07 Stephanie Lewis + + Reviewed by Geoff Garen. + + Migrate memory tracking from Safari to WebKit + https://bugs.webkit.org/show_bug.cgi?id=50799 Add Memory Sampler to WebKit + + Add a sampler for printing off process memory statistics. + Export file mode. + + * WebCore.exp.in: + 2011-01-06 Ryosuke Niwa Reviewed by Adam Barth. diff --git a/WebCore/WebCore.exp.in b/WebCore/WebCore.exp.in index baa6f7d1958bc7429318e94e07277b68d0d6169b..88ab671c3a0559cadc1dd4e5c2756d8eea29555c 100644 --- a/WebCore/WebCore.exp.in +++ b/WebCore/WebCore.exp.in @@ -769,6 +769,7 @@ __ZN7WebCore8FormDataD1Ev __ZN7WebCore8Gradient12addColorStopEfRKNS_5ColorE __ZN7WebCore8GradientC1ERKNS_10FloatPointES3_ __ZN7WebCore8IntPointC1ERK8_NSPoint +__ZN7WebCore8openFileERKN3WTF6StringENS_12FileOpenModeE __ZN7WebCore8PositionC1EN3WTF10PassRefPtrINS_4NodeEEEi __ZN7WebCore8Settings14setJavaEnabledEb __ZN7WebCore8Settings15setWebGLEnabledEb diff --git a/WebKit2/ChangeLog b/WebKit2/ChangeLog index 9a070e0cc8d0ab04b3cfca71df7b6a94972f1616..b7aefec953bb466a2baa5ec9e10847e579d8a13b 100644 --- a/WebKit2/ChangeLog +++ b/WebKit2/ChangeLog @@ -1,3 +1,79 @@ +2011-01-07 Stephanie Lewis + + Reviewed by Geoff Garen. + + Migrate memory tracking from Safari to WebKit + https://bugs.webkit.org/show_bug.cgi?id=50799 Add Memory Sampler to WebKit + + Add a sampler for printing off process memory statistics. + This tool can track: + + WebCore + - FastMalloc allocations bytes (in use or committed) + JavaScriptCore + - Garbage collector heap bytes (in use or committed) + - Stack bytes (committed only!) + - JIT Code bytes (committed only!) + Malloc zones + - In use bytes for the following zones: + * Default zone (in use or committed) + * DispCon zone (in use or committed) + * Purgable zone (in use or committed) + Task Info + - Resident size memory (RSIZE) + + Data collected is dumped to a temporary file. + + Create a sandbox for a temporary file. + * Shared/SandboxExtension.h: + (WebKit::SandboxExtension::createHandleForTemporaryFile): + * Shared/mac/SandboxExtensionMac.mm: + (WebKit::SandboxExtension::createHandleForTemporaryFile): + + Memory Sampler files + + * Shared/WebMemorySampler.cpp: Added. + (WebKit::WebMemorySampler::shared): + (WebKit::WebMemorySampler::WebMemorySampler): + (WebKit::WebMemorySampler::start): + (WebKit::WebMemorySampler::initializeTimers): + (WebKit::WebMemorySampler::stop): + (WebKit::WebMemorySampler::isRunning): + (WebKit::WebMemorySampler::initializeTempLogFile): + (WebKit::WebMemorySampler::initializeSandboxedLogFile): + (WebKit::WebMemorySampler::writeHeaders): + (WebKit::WebMemorySampler::sampleTimerFired): + (WebKit::WebMemorySampler::stopTimerFired): + (WebKit::WebMemorySampler::appendCurrentMemoryUsageToFile): + * Shared/WebMemorySampler.h: Added. + * Shared/mac/WebMemorySampler.mac.mm: Added. + (WebKit::WebMemorySampler::sampleSystemMalloc): + (WebKit::WebMemorySampler::sampleProcessCommittedBytes): + (WebKit::WebMemorySampler::processName): + (WebKit::WebMemorySampler::sampleWebKit): + + API to start and stop UIProcess and WebProcess sampling. + + * UIProcess/API/C/WKContext.cpp: + (WKContextStartMemorySampler): + (WKContextStopMemorySampler): + * UIProcess/API/C/WKContext.h: + + Send messages to WebProcess to start and stop memory sampling. + + * UIProcess/WebContext.cpp: + (WebKit::WebContext::WebContext): + (WebKit::WebContext::processDidFinishLaunching): + (WebKit::WebContext::startMemorySampler): + (WebKit::WebContext::stopMemorySampler): + * UIProcess/WebContext.h: + * WebKit2.xcodeproj/project.pbxproj: + * WebProcess/WebProcess.cpp: + (WebKit::WebProcess::startMemorySampler): + (WebKit::WebProcess::stopMemorySampler): + * WebProcess/WebProcess.h: + * WebProcess/WebProcess.messages.in: + 2011-01-07 Jessie Berlin Reviewed by Dan Bernstein. diff --git a/WebKit2/Shared/SandboxExtension.h b/WebKit2/Shared/SandboxExtension.h index ba674d455eaae5537eeb945816268bd90f4faeda..0dfcab08709fe07f124337dc1dd618c4b4898ccf 100644 --- a/WebKit2/Shared/SandboxExtension.h +++ b/WebKit2/Shared/SandboxExtension.h @@ -30,6 +30,7 @@ #include #include #include +#include #if ENABLE(WEB_PROCESS_SANDBOX) typedef struct __WKSandboxExtension* WKSandboxExtensionRef; @@ -69,6 +70,7 @@ public: static PassRefPtr create(const Handle&); static void createHandle(const String& path, Type type, Handle&); + static String createHandleForTemporaryFile(const String& prefix, Type type, Handle&); ~SandboxExtension(); bool invalidate(); @@ -90,6 +92,7 @@ inline void SandboxExtension::Handle::encode(CoreIPC::ArgumentEncoder*) const { inline bool SandboxExtension::Handle::decode(CoreIPC::ArgumentDecoder*, Handle&) { return true; } inline PassRefPtr SandboxExtension::create(const Handle&) { return 0; } inline void SandboxExtension::createHandle(const String& path, Type type, Handle&) { } +inline String SandboxExtension::createHandleForTemporaryFile(const String& prefix, Type type, Handle&) {return String();} inline SandboxExtension::~SandboxExtension() { } inline bool SandboxExtension::invalidate() { return true; } inline bool SandboxExtension::consume() { return true; } diff --git a/WebKit2/Shared/WebMemorySampler.cpp b/WebKit2/Shared/WebMemorySampler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b5c48720c8682dd35e9cbb087babe6711c7861b --- /dev/null +++ b/WebKit2/Shared/WebMemorySampler.cpp @@ -0,0 +1,184 @@ +/* + * 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. + * + */ + +#if ENABLE(MEMORY_SAMPLER) + +#include "WebMemorySampler.h" + +#include + +using namespace WebCore; + +namespace WebKit { + + +WebMemorySampler* WebMemorySampler::shared() +{ + static WebMemorySampler* sharedMemorySampler; + if (!sharedMemorySampler) + sharedMemorySampler = new WebMemorySampler(); + return sharedMemorySampler; +} + +WebMemorySampler::WebMemorySampler() + : m_separator(String("\t")) + , m_sampleTimer(this, &WebMemorySampler::sampleTimerFired) + , m_stopTimer(this, &WebMemorySampler::stopTimerFired) + , m_isRunning(false) + , m_runningTime(0) +{ +} + +void WebMemorySampler::start(const double interval) +{ + if (m_isRunning) + return; + + initializeTempLogFile(); + initializeTimers(interval); +} + +void WebMemorySampler::start(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval) +{ + if (m_isRunning) + return; + + // If we are on a system without SandboxExtension the handle and filename will be empty + if (sampleLogFilePath.isEmpty()) { + start(interval); + return; + } + + initializeSandboxedLogFile(sampleLogFileHandle, sampleLogFilePath); + initializeTimers(interval); + +} + +void WebMemorySampler::initializeTimers(double interval) +{ + m_sampleTimer.startRepeating(1); + printf("Started memory sampler for process %s", processName().utf8().data()); + if (interval > 0) { + m_stopTimer.startOneShot(interval); + printf(" for a interval of %g seconds", interval); + } + printf("; Sampler log file stored at: %s\n", m_sampleLogFilePath.utf8().data()); + m_runningTime = interval; + m_isRunning = true; +} + +void WebMemorySampler::stop() +{ + if (!m_isRunning) + return; + m_sampleTimer.stop(); + m_sampleLogFile = 0; + printf("Stopped memory sampler for process %s\n", processName().utf8().data()); + // Flush stdout buffer so python script can be guaranteed to read up to this point. + fflush(stdout); + m_isRunning = false; + + if(m_stopTimer.isActive()) + m_stopTimer.stop(); + + if (m_sampleLogSandboxExtension) { + m_sampleLogSandboxExtension->invalidate(); + m_sampleLogSandboxExtension = 0; + } +} + +bool WebMemorySampler::isRunning() const +{ + return m_isRunning; +} + +void WebMemorySampler::initializeTempLogFile() +{ + m_sampleLogFilePath = String((openTemporaryFile(processName().utf8().data(), m_sampleLogFile)).data()); + writeHeaders(); +} + +void WebMemorySampler::initializeSandboxedLogFile(const SandboxExtension::Handle& sampleLogSandboxHandle, const String& sampleLogFilePath) +{ + m_sampleLogSandboxExtension = SandboxExtension::create(sampleLogSandboxHandle); + if (m_sampleLogSandboxExtension) + m_sampleLogSandboxExtension->consume(); + m_sampleLogFilePath = sampleLogFilePath; + m_sampleLogFile = openFile(m_sampleLogFilePath, OpenForWrite); + writeHeaders(); +} + +void WebMemorySampler::writeHeaders() +{ + String processDetails = String("Process: "); + processDetails.append(processName()); + processDetails.append(String("\n")); + writeToFile(m_sampleLogFile, processDetails.utf8().data(), processDetails.utf8().length()); + + String header; + WebMemoryStatistics stats = sampleWebKit(); + if (!stats.keys.isEmpty()) { + for (size_t i = 0; i < stats.keys.size(); ++i) { + header.append(m_separator); + header.append(stats.keys[i].utf8().data()); + } + } + header.append(String("\n")); + writeToFile(m_sampleLogFile, header.utf8().data(), header.utf8().length()); +} + +void WebMemorySampler::sampleTimerFired(Timer*) +{ + appendCurrentMemoryUsageToFile(m_sampleLogFile); +} + +void WebMemorySampler::stopTimerFired(Timer*) +{ + if (!m_isRunning) + return; + printf("%g seconds elapsed. Stopping memory sampler...\n", m_runningTime); + stop(); +} + +void WebMemorySampler::appendCurrentMemoryUsageToFile(PlatformFileHandle& file) +{ + // Collect statistics from allocators and get RSIZE metric + String statString; + WebMemoryStatistics memoryStats = sampleWebKit(); + + if (!memoryStats.values.isEmpty()) { + statString.append(m_separator); + for (size_t i = 0; i < memoryStats.values.size(); ++i) { + statString.append(m_separator); + statString.append(String::format("%lu", memoryStats.values[i])); + } + } + statString.append(String("\n")); + writeToFile(m_sampleLogFile, statString.utf8().data(), statString.utf8().length()); +} + +} + +#endif diff --git a/WebKit2/Shared/WebMemorySampler.h b/WebKit2/Shared/WebMemorySampler.h new file mode 100644 index 0000000000000000000000000000000000000000..93254d984ab7e15f337c166aa58527f6f7396f8c --- /dev/null +++ b/WebKit2/Shared/WebMemorySampler.h @@ -0,0 +1,112 @@ +/* + * 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. + * + * The MemorySampler class samples a number of internal and external memory + * metrics every second while running. Sample data is written to a log file. + * Sampling occurs over a duration specified when started. If duration is set + * to 0 (default), the memory sampler will run indefinitely until the stop + * function is called. MemorySampler allows the option of sampling "in use" + * memory (committed memory minus free list byte count) or committed memory for + * any allocator which keeps a free list. This includes FastMalloc and the + * JavaScriptCore heap at this time. + * The following memory metrics are recorded: + * + * WebCore + * - FastMalloc allocations bytes (in use or committed) + * JavaScriptCore + * - Garbage collector heap bytes (in use or committed) + * - Stack bytes (committed only!) + * - JIT Code bytes (committed only!) + * Malloc zones + * - In use bytes for the following zones: + * * Default zone (in use or committed) + * * DispCon zone (in use or committed) + * * Purgable zone (in use or committed) + * Task Info + * - Resident size memory (RSIZE) + */ + +#ifndef WebMemorySampler_h +#define WebMemorySampler_h + +#if ENABLE(MEMORY_SAMPLER) + +#include "SandboxExtension.h" +#include +#include +#include +#include +#include +#include + +namespace WebKit { + +struct SystemMallocStats; + +struct WebMemoryStatistics +{ + Vector keys; + Vector values; +}; + +class WebMemorySampler : public Noncopyable { + +public: + static WebMemorySampler* shared(); + void start(const double interval=0); + void start(const SandboxExtension::Handle&, const String&, const double interval=0); + void stop(); + bool isRunning() const; + +private: + WebMemorySampler(); + ~WebMemorySampler(); + + void initializeTempLogFile(); + void initializeSandboxedLogFile(const SandboxExtension::Handle&, const String&); + void writeHeaders(); + void initializeTimers(double); + void sampleTimerFired(WebCore::Timer*); + void stopTimerFired(WebCore::Timer*); + void appendCurrentMemoryUsageToFile(WebCore::PlatformFileHandle&); + + SystemMallocStats sampleSystemMalloc() const; + size_t sampleProcessCommittedBytes() const; + WebMemoryStatistics sampleWebKit() const; + String processName() const; + + WebCore::PlatformFileHandle m_sampleLogFile; + String m_sampleLogFilePath; + String m_separator; + WebCore::Timer m_sampleTimer; + WebCore::Timer m_stopTimer; + bool m_isRunning; + double m_runningTime; + RefPtr m_sampleLogSandboxExtension; +}; + +} + +#endif + +#endif diff --git a/WebKit2/Shared/mac/SandboxExtensionMac.mm b/WebKit2/Shared/mac/SandboxExtensionMac.mm index 91ac733d0d39caa16a7efc8f869ef5435d90455f..68b5849b56c52e8f5ecd1c2097882cf9327550a6 100644 --- a/WebKit2/Shared/mac/SandboxExtensionMac.mm +++ b/WebKit2/Shared/mac/SandboxExtensionMac.mm @@ -114,6 +114,30 @@ void SandboxExtension::createHandle(const String& path, Type type, Handle& handl NSString *standardizedPath = [(NSString *)path stringByStandardizingPath]; handle.m_sandboxExtension = WKSandboxExtensionCreate([standardizedPath fileSystemRepresentation], wkSandboxExtensionType(type)); } + +String SandboxExtension::createHandleForTemporaryFile(const String& prefix, Type type, Handle& handle) +{ + ASSERT(!handle.m_sandboxExtension); + + Vector path(PATH_MAX); + if (!confstr(_CS_DARWIN_USER_TEMP_DIR, path.data(), path.size())) + return String(); + + // Shrink the vector. + path.shrink(strlen(path.data())); + ASSERT(path.last() == '/'); + + // Append the file name. + path.append(prefix.utf8().data(), prefix.length()); + path.append('\0'); + + handle.m_sandboxExtension = WKSandboxExtensionCreate(fileSystemRepresentation(path.data()).data(), wkSandboxExtensionType(type)); + + if (!handle.m_sandboxExtension) { + return String(); + } + return String(path.data()); +} SandboxExtension::SandboxExtension(const Handle& handle) : m_sandboxExtension(handle.m_sandboxExtension) diff --git a/WebKit2/Shared/mac/WebMemorySampler.mac.mm b/WebKit2/Shared/mac/WebMemorySampler.mac.mm new file mode 100644 index 0000000000000000000000000000000000000000..2b8e0b30f3ff26e4ea45be8336293a1de9647ab0 --- /dev/null +++ b/WebKit2/Shared/mac/WebMemorySampler.mac.mm @@ -0,0 +1,182 @@ +/* + * 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. + * + */ + +#if ENABLE(MEMORY_SAMPLER) + +#include "WebMemorySampler.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace WebCore; +using namespace JSC; +using namespace WTF; + +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(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(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(&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; + + FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics(); + size_t fastMallocBytesInUse = fastMallocStatistics.committedVMBytes - fastMallocStatistics.freeListBytes; + size_t fastMallocBytesCommitted = fastMallocStatistics.committedVMBytes; + totalBytesInUse += fastMallocBytesInUse; + totalBytesCommitted += fastMallocBytesCommitted; + + JSLock lock(SilenceAssertionsOnly); + Heap::Statistics heapMemoryStats = heapStatistics(JSDOMWindow::commonJSGlobalData()); + size_t jscHeapBytesInUse = heapMemoryStats.size - heapMemoryStats.free; + size_t jscHeapBytesCommitted = heapMemoryStats.size; + totalBytesInUse += jscHeapBytesInUse; + totalBytesCommitted += jscHeapBytesCommitted; + + GlobalMemoryStatistics globalMemoryStats = 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(); + + double now = currentTime(); + + webKitMemoryStats.keys.append(String("Timestamp")); + webKitMemoryStats.values.append(now); + 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; +} + +} + +#endif + diff --git a/WebKit2/UIProcess/API/C/WKContext.cpp b/WebKit2/UIProcess/API/C/WKContext.cpp index 53ad0f8463157199a72a8bde89ab92db0699e239..2e416e7b37a8ceb77c4d69b4a558fd54ed05b2c1 100644 --- a/WebKit2/UIProcess/API/C/WKContext.cpp +++ b/WebKit2/UIProcess/API/C/WKContext.cpp @@ -161,3 +161,13 @@ WKDatabaseManagerRef WKContextGetDatabaseManager(WKContextRef contextRef) { return toAPI(toImpl(contextRef)->databaseManagerProxy()); } + +void WKContextStartMemorySampler(WKContextRef contextRef, WKDoubleRef interval) +{ + toImpl(contextRef)->startMemorySampler(toImpl(interval)->value()); +} + +void WKContextStopMemorySampler(WKContextRef contextRef) +{ + toImpl(contextRef)->stopMemorySampler(); +} diff --git a/WebKit2/UIProcess/API/C/WKContext.h b/WebKit2/UIProcess/API/C/WKContext.h index 130090a95494df20744453ed15dda0a23f2266db..13762ad6b64550301932c63c24e872a7df25b3b8 100644 --- a/WebKit2/UIProcess/API/C/WKContext.h +++ b/WebKit2/UIProcess/API/C/WKContext.h @@ -119,6 +119,9 @@ WK_EXPORT WKCacheModel WKContextGetCacheModel(WKContextRef context); WK_EXPORT void WKContextClearResourceCaches(WKContextRef context); WK_EXPORT void WKContextClearApplicationCache(WKContextRef context); + +WK_EXPORT void WKContextStartMemorySampler(WKContextRef context, WKDoubleRef interval); +WK_EXPORT void WKContextStopMemorySampler(WKContextRef context); WK_EXPORT WKDatabaseManagerRef WKContextGetDatabaseManager(WKContextRef context); diff --git a/WebKit2/UIProcess/WebContext.cpp b/WebKit2/UIProcess/WebContext.cpp index c06b2c096f26978548b904f09b34fde4fb2f1a54..679ae2ee87f87a773f8f5de7b96e18e8cb9f1faf 100644 --- a/WebKit2/UIProcess/WebContext.cpp +++ b/WebKit2/UIProcess/WebContext.cpp @@ -29,6 +29,7 @@ #include "ImmutableArray.h" #include "InjectedBundleMessageKinds.h" #include "RunLoop.h" +#include "SandboxExtension.h" #include "TextChecker.h" #include "WKContextPrivate.h" #include "WebContextMessageKinds.h" @@ -36,12 +37,14 @@ #include "WebCoreArgumentCoders.h" #include "WebDatabaseManagerProxy.h" #include "WebPageGroup.h" +#include "WebMemorySampler.h" #include "WebProcessCreationParameters.h" #include "WebProcessManager.h" #include "WebProcessMessages.h" #include "WebProcessProxy.h" #include #include +#include #ifndef NDEBUG #include @@ -86,6 +89,8 @@ WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePa , m_cacheModel(CacheModelDocumentViewer) , m_clearResourceCachesForNewWebProcess(false) , m_clearApplicationCacheForNewWebProcess(false) + , m_memorySamplerEnabled(false) + , m_memorySamplerInterval(1400.0) , m_databaseManagerProxy(WebDatabaseManagerProxy::create(this)) #if PLATFORM(WIN) , m_shouldPaintNativeControls(true) @@ -198,6 +203,17 @@ void WebContext::processDidFinishLaunching(WebProcessProxy* process) ASSERT_UNUSED(process, process == m_process); m_visitedLinkProvider.processDidFinishLaunching(); + + // Sometimes the memorySampler gets initialized after process initialization has happened but before the process has finished launching + // so check if it needs to be started here + if(m_memorySamplerEnabled) { + SandboxExtension::Handle sampleLogSandboxHandle; + double now = WTF::currentTime(); + String sampleLogFilePath = String::format("WebProcess%llu", static_cast(now)); + sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::WriteOnly, sampleLogSandboxHandle); + + m_process->send(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, m_memorySamplerInterval), 0); + } } void WebContext::processDidClose(WebProcessProxy* process) @@ -532,5 +548,44 @@ void WebContext::clearApplicationCache() m_process->send(Messages::WebProcess::ClearApplicationCache(), 0); } + +void WebContext::startMemorySampler(const double interval) +{ + // For new WebProcesses we will also want to start the Memory Sampler + m_memorySamplerEnabled = true; + m_memorySamplerInterval = interval; + + // For UIProcess +#if ENABLE(MEMORY_SAMPLER) + WebMemorySampler::shared()->start(interval); +#endif + + if (!hasValidProcess()) + return; + + // For WebProcess + SandboxExtension::Handle sampleLogSandboxHandle; + double now = WTF::currentTime(); + String sampleLogFilePath = String::format("WebProcess%llu", static_cast(now)); + sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::WriteOnly, sampleLogSandboxHandle); + + m_process->send(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, interval), 0); +} + +void WebContext::stopMemorySampler() +{ + // For WebProcess + m_memorySamplerEnabled = false; + + // For UIProcess +#if ENABLE(MEMORY_SAMPLER) + WebMemorySampler::shared()->stop(); +#endif + + if (!hasValidProcess()) + return; + + m_process->send(Messages::WebProcess::StopMemorySampler(), 0); +} } // namespace WebKit diff --git a/WebKit2/UIProcess/WebContext.h b/WebKit2/UIProcess/WebContext.h index 6b56ad415313a7cc4d6b560d81a6402fa53d0c74..c45dc6284df9f401dbbac1af7dde696e9d0c6561 100644 --- a/WebKit2/UIProcess/WebContext.h +++ b/WebKit2/UIProcess/WebContext.h @@ -110,6 +110,9 @@ public: CacheModel cacheModel() const { return m_cacheModel; } void clearResourceCaches(); void clearApplicationCache(); + + void startMemorySampler(const double interval); + void stopMemorySampler(); #if PLATFORM(WIN) void setShouldPaintNativeControls(bool); @@ -188,6 +191,9 @@ private: bool m_clearResourceCachesForNewWebProcess; bool m_clearApplicationCacheForNewWebProcess; + + bool m_memorySamplerEnabled; + double m_memorySamplerInterval; RefPtr m_databaseManagerProxy; diff --git a/WebKit2/WebKit2.xcodeproj/project.pbxproj b/WebKit2/WebKit2.xcodeproj/project.pbxproj index 5483cedbc4cd6bc984017869485f2024b8e77c20..818858c6f5a67860413b557e6773617693e81b8f 100644 --- a/WebKit2/WebKit2.xcodeproj/project.pbxproj +++ b/WebKit2/WebKit2.xcodeproj/project.pbxproj @@ -269,6 +269,9 @@ 762B748D120BC75C00819339 /* WKPreferencesPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 762B7484120BBA2D00819339 /* WKPreferencesPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; + 909854EC12BC4E17000AD080 /* WebMemorySampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 905620E812BC248B000799B6 /* WebMemorySampler.cpp */; }; + 909854ED12BC4E18000AD080 /* WebMemorySampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 905620E912BC248B000799B6 /* WebMemorySampler.h */; }; + 909854EE12BC4E18000AD080 /* WebMemorySampler.mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 905620E512BC2476000799B6 /* WebMemorySampler.mac.mm */; }; 935EEB9B1277617C003322B8 /* WKBundleBackForwardListItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 935EEB981277616D003322B8 /* WKBundleBackForwardListItem.h */; settings = {ATTRIBUTES = (Private, ); }; }; 935EEB9E127761AC003322B8 /* WKBundleBackForwardList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 935EEB951277616D003322B8 /* WKBundleBackForwardList.cpp */; }; 935EEB9F127761AC003322B8 /* WKBundleBackForwardList.h in Headers */ = {isa = PBXBuildFile; fileRef = 935EEB961277616D003322B8 /* WKBundleBackForwardList.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -955,6 +958,9 @@ 762B7484120BBA2D00819339 /* WKPreferencesPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKPreferencesPrivate.h; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* WebKit2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WebKit2.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 905620E512BC2476000799B6 /* WebMemorySampler.mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebMemorySampler.mac.mm; sourceTree = ""; tabWidth = 8; usesTabs = 0; }; + 905620E812BC248B000799B6 /* WebMemorySampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebMemorySampler.cpp; sourceTree = ""; }; + 905620E912BC248B000799B6 /* WebMemorySampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMemorySampler.h; sourceTree = ""; }; 935EEB8F1277615D003322B8 /* InjectedBundleBackForwardList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleBackForwardList.cpp; sourceTree = ""; }; 935EEB901277615D003322B8 /* InjectedBundleBackForwardList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundleBackForwardList.h; sourceTree = ""; }; 935EEB911277615D003322B8 /* InjectedBundleBackForwardListItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleBackForwardListItem.cpp; sourceTree = ""; }; @@ -1678,6 +1684,8 @@ BCCF6ABA12C91EF9008F9C35 /* WebImage.cpp */, BCCF6ABB12C91EF9008F9C35 /* WebImage.h */, C0337DD2127A2A0E008FF4F4 /* WebKeyboardEvent.cpp */, + 905620E812BC248B000799B6 /* WebMemorySampler.cpp */, + 905620E912BC248B000799B6 /* WebMemorySampler.h */, C0337DAF127A28D0008FF4F4 /* WebMouseEvent.cpp */, BCF69F981176CED600471A52 /* WebNavigationDataStore.h */, BC33DD671238464600360F3F /* WebNumber.h */, @@ -2167,6 +2175,7 @@ BCE23262122C6CF300D5C35A /* WebCoreArgumentCodersMac.mm */, BC111B5B112F629800337BAB /* WebEventFactory.h */, BC111B5C112F629800337BAB /* WebEventFactory.mm */, + 905620E512BC2476000799B6 /* WebMemorySampler.mac.mm */, BCE231C0122C466E00D5C35A /* WebURLRequestMac.mm */, BC90A1D5122DD66A00CC8C50 /* WebURLResponseMac.mm */, 1AAB4AA91296F1540023952F /* SandboxExtensionMac.mm */, @@ -2844,6 +2853,7 @@ 1A4A9F3312B844E2008FE984 /* PluginQuirks.h in Headers */, BC858A2012C0357B00EDEB2E /* WebResourceLoadClient.h in Headers */, 1AA417CB12C00CCA002BE67B /* TextChecker.h in Headers */, + 909854ED12BC4E18000AD080 /* WebMemorySampler.h in Headers */, 1AA41AB512C02EC4002BE67B /* SelectionState.h in Headers */, BCCF672D12C7EDF7008F9C35 /* OriginAndDatabases.h in Headers */, BCCF6ABD12C91EF9008F9C35 /* WebImage.h in Headers */, @@ -3281,6 +3291,8 @@ 1A4A9C9A12B821CD008FE984 /* NetscapePluginModuleMac.mm in Sources */, BC858A2112C0357B00EDEB2E /* WebResourceLoadClient.cpp in Sources */, 1AA417EF12C00D87002BE67B /* TextCheckerMac.mm in Sources */, + 909854EC12BC4E17000AD080 /* WebMemorySampler.cpp in Sources */, + 909854EE12BC4E18000AD080 /* WebMemorySampler.mac.mm in Sources */, BCCF673312C7F15C008F9C35 /* OriginAndDatabases.cpp in Sources */, BCCF6ABC12C91EF9008F9C35 /* WebImage.cpp in Sources */, BCCF6AC212C91F34008F9C35 /* WKImage.cpp in Sources */, diff --git a/WebKit2/WebKit2Prefix.h b/WebKit2/WebKit2Prefix.h index 1e01a1ed496aeb113be58c5d41da21abd9ee19b2..19bee7fdb8922eb61f67eb623975842434c892fa 100644 --- a/WebKit2/WebKit2Prefix.h +++ b/WebKit2/WebKit2Prefix.h @@ -66,6 +66,10 @@ static const type& name() \ #define ENABLE_PLUGIN_PROCESS 1 +#if PLATFORM(MAC) +#define ENABLE_MEMORY_SAMPLER 1 +#endif + #import #ifdef __OBJC__ diff --git a/WebKit2/WebProcess/WebProcess.cpp b/WebKit2/WebProcess/WebProcess.cpp index 789da087e838f130dcba9298748abe8f94a37300..5da96020822bd0d461cb18c7897ca54dd2bf988c 100644 --- a/WebKit2/WebProcess/WebProcess.cpp +++ b/WebKit2/WebProcess/WebProcess.cpp @@ -31,10 +31,12 @@ #include "InjectedBundleMessageKinds.h" #include "InjectedBundleUserMessageCoders.h" #include "RunLoop.h" +#include "SandboxExtension.h" #include "WebContextMessages.h" #include "WebCoreArgumentCoders.h" #include "WebDatabaseManager.h" #include "WebFrame.h" +#include "WebMemorySampler.h" #include "WebPage.h" #include "WebPageCreationParameters.h" #include "WebPlatformStrategies.h" @@ -628,6 +630,20 @@ void WebProcess::cancelDownload(uint64_t downloadID) DownloadManager::shared().cancelDownload(downloadID); } +void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval) +{ +#if ENABLE(MEMORY_SAMPLER) + WebMemorySampler::shared()->start(sampleLogFileHandle, sampleLogFilePath, interval); +#endif +} + +void WebProcess::stopMemorySampler() +{ +#if ENABLE(MEMORY_SAMPLER) + WebMemorySampler::shared()->stop(); +#endif +} + void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState) { m_textCheckerState = textCheckerState; diff --git a/WebKit2/WebProcess/WebProcess.h b/WebKit2/WebProcess/WebProcess.h index b9bc8834beffc6ca88645b65a8c5b3ddcdb6b926..65c993fa661c2641ab7c24843e2a108a17b7c861 100644 --- a/WebKit2/WebProcess/WebProcess.h +++ b/WebKit2/WebProcess/WebProcess.h @@ -29,6 +29,7 @@ #include "CacheModel.h" #include "ChildProcess.h" #include "DrawingArea.h" +#include "SandboxExtension.h" #include "SharedMemory.h" #include "TextCheckerState.h" #include "VisitedLinkTable.h" @@ -137,6 +138,9 @@ private: void platformClearResourceCaches(); void clearApplicationCache(); + void startMemorySampler(const SandboxExtension::Handle&, const String&, const double); + void stopMemorySampler(); + void downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const WebCore::ResourceRequest&); void cancelDownload(uint64_t downloadID); diff --git a/WebKit2/WebProcess/WebProcess.messages.in b/WebKit2/WebProcess/WebProcess.messages.in index c5bace5ed3c139c4444124b740b6ed03425551fb..2ea923731b33323c2d94565e457f23754efaab9f 100644 --- a/WebKit2/WebProcess/WebProcess.messages.in +++ b/WebKit2/WebProcess/WebProcess.messages.in @@ -46,6 +46,9 @@ messages -> WebProcess { ClearResourceCaches(); ClearApplicationCache(); + + void StartMemorySampler(WebKit::SandboxExtension::Handle sampleLogFileHandle, WTF::String sampleLogFilePath, double interval); + void StopMemorySampler(); # Downloads. This should really be in a Download.messages.in, but it seemed unnecessary to create a new file just for # two messages.