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