Home | History | Annotate | Download | only in Shared
      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 
     33 using namespace WebCore;
     34 
     35 namespace WebKit {
     36 
     37 
     38 WebMemorySampler* WebMemorySampler::shared()
     39 {
     40     static WebMemorySampler* sharedMemorySampler;
     41     if (!sharedMemorySampler)
     42         sharedMemorySampler = new WebMemorySampler();
     43     return sharedMemorySampler;
     44 }
     45 
     46 WebMemorySampler::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 
     55 void WebMemorySampler::start(const double interval)
     56 {
     57     if (m_isRunning)
     58         return;
     59 
     60     initializeTempLogFile();
     61     initializeTimers(interval);
     62 }
     63 
     64 void 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 
     80 void 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 
     93 void 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 
    113 bool WebMemorySampler::isRunning() const
    114 {
    115     return m_isRunning;
    116 }
    117 
    118 void WebMemorySampler::initializeTempLogFile()
    119 {
    120     m_sampleLogFilePath = openTemporaryFile(processName(), m_sampleLogFile);
    121     writeHeaders();
    122 }
    123 
    124 void 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 
    134 void 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 
    153 void WebMemorySampler::sampleTimerFired(Timer<WebMemorySampler>*)
    154 {
    155     appendCurrentMemoryUsageToFile(m_sampleLogFile);
    156 }
    157 
    158 void 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 
    166 void 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