WebMemorySampler.cpp 6.2 KB

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