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#include "config.h" 27#include "WebMemorySampler.h" 28 29#if ENABLE(MEMORY_SAMPLER) 30 31#include <stdio.h> 32#include <unistd.h> 33#include <wtf/text/CString.h> 34#include <wtf/text/StringBuilder.h> 35 36using namespace WebCore; 37 38namespace WebKit { 39 40static const char separator = '\t'; 41 42WebMemorySampler* WebMemorySampler::shared() 43{ 44 static WebMemorySampler* sharedMemorySampler; 45 if (!sharedMemorySampler) 46 sharedMemorySampler = new WebMemorySampler(); 47 return sharedMemorySampler; 48} 49 50WebMemorySampler::WebMemorySampler() 51 : m_sampleTimer(this, &WebMemorySampler::sampleTimerFired) 52 , m_stopTimer(this, &WebMemorySampler::stopTimerFired) 53 , m_isRunning(false) 54 , m_runningTime(0) 55{ 56} 57 58void WebMemorySampler::start(const double interval) 59{ 60 if (m_isRunning) 61 return; 62 63 initializeTempLogFile(); 64 initializeTimers(interval); 65} 66 67void WebMemorySampler::start(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval) 68{ 69 if (m_isRunning) 70 return; 71 72 // If we are on a system without SandboxExtension the handle and filename will be empty 73 if (sampleLogFilePath.isEmpty()) { 74 start(interval); 75 return; 76 } 77 78 initializeSandboxedLogFile(sampleLogFileHandle, sampleLogFilePath); 79 initializeTimers(interval); 80 81} 82 83void WebMemorySampler::initializeTimers(double interval) 84{ 85 m_sampleTimer.startRepeating(1); 86 printf("Started memory sampler for process %s %d", processName().utf8().data(), getpid()); 87 if (interval > 0) { 88 m_stopTimer.startOneShot(interval); 89 printf(" for a interval of %g seconds", interval); 90 } 91 printf("; Sampler log file stored at: %s\n", m_sampleLogFilePath.utf8().data()); 92 m_runningTime = interval; 93 m_isRunning = true; 94} 95 96void WebMemorySampler::stop() 97{ 98 if (!m_isRunning) 99 return; 100 m_sampleTimer.stop(); 101 m_sampleLogFile = 0; 102 printf("Stopped memory sampler for process %s %d\n", processName().utf8().data(), getpid()); 103 // Flush stdout buffer so python script can be guaranteed to read up to this point. 104 fflush(stdout); 105 m_isRunning = false; 106 107 if (m_stopTimer.isActive()) 108 m_stopTimer.stop(); 109 110 if (m_sampleLogSandboxExtension) { 111 m_sampleLogSandboxExtension->revoke(); 112 m_sampleLogSandboxExtension = nullptr; 113 } 114} 115 116bool WebMemorySampler::isRunning() const 117{ 118 return m_isRunning; 119} 120 121void WebMemorySampler::initializeTempLogFile() 122{ 123 m_sampleLogFilePath = openTemporaryFile(processName(), m_sampleLogFile); 124 writeHeaders(); 125} 126 127void WebMemorySampler::initializeSandboxedLogFile(const SandboxExtension::Handle& sampleLogSandboxHandle, const String& sampleLogFilePath) 128{ 129 m_sampleLogSandboxExtension = SandboxExtension::create(sampleLogSandboxHandle); 130 if (m_sampleLogSandboxExtension) 131 m_sampleLogSandboxExtension->consume(); 132 m_sampleLogFilePath = sampleLogFilePath; 133 m_sampleLogFile = openFile(m_sampleLogFilePath, OpenForWrite); 134 writeHeaders(); 135} 136 137void WebMemorySampler::writeHeaders() 138{ 139 String processDetails = String::format("Process: %s Pid: %d\n", processName().utf8().data(), getpid()); 140 141 CString utf8String = processDetails.utf8(); 142 writeToFile(m_sampleLogFile, utf8String.data(), utf8String.length()); 143 144 StringBuilder header; 145 WebMemoryStatistics stats = sampleWebKit(); 146 if (!stats.keys.isEmpty()) { 147 for (size_t i = 0; i < stats.keys.size(); ++i) { 148 header.append(separator); 149 header.append(stats.keys[i]); 150 } 151 } 152 header.append('\n'); 153 utf8String = header.toString().utf8(); 154 writeToFile(m_sampleLogFile, utf8String.data(), utf8String.length()); 155} 156 157void WebMemorySampler::sampleTimerFired(Timer<WebMemorySampler>*) 158{ 159 sendMemoryPressureEvent(); 160 appendCurrentMemoryUsageToFile(m_sampleLogFile); 161} 162 163void WebMemorySampler::stopTimerFired(Timer<WebMemorySampler>*) 164{ 165 if (!m_isRunning) 166 return; 167 printf("%g seconds elapsed. Stopping memory sampler...\n", m_runningTime); 168 stop(); 169} 170 171void WebMemorySampler::appendCurrentMemoryUsageToFile(PlatformFileHandle&) 172{ 173 // Collect statistics from allocators and get RSIZE metric 174 StringBuilder statString; 175 WebMemoryStatistics memoryStats = sampleWebKit(); 176 177 if (!memoryStats.values.isEmpty()) { 178 statString.append(separator); 179 for (size_t i = 0; i < memoryStats.values.size(); ++i) { 180 statString.append(separator); 181 statString.appendNumber(memoryStats.values[i]); 182 } 183 } 184 statString.append('\n'); 185 186 CString utf8String = statString.toString().utf8(); 187 writeToFile(m_sampleLogFile, utf8String.data(), utf8String.length()); 188} 189 190} 191 192#endif 193