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