[WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively
[WebKit-https.git] / Source / WTF / wtf / StackShotProfiler.h
1 /*
2  * Copyright (C) 2017 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include <wtf/DataLog.h>
29 #include <wtf/Locker.h>
30 #include <wtf/ProcessID.h>
31 #include <wtf/Spectrum.h>
32 #include <wtf/StackTrace.h>
33 #include <wtf/StackShot.h>
34 #include <wtf/Threading.h>
35 #include <wtf/WordLock.h>
36
37 namespace WTF {
38
39 class StackShotProfiler {
40 public:
41     StackShotProfiler(unsigned numFrames, unsigned framesToSkip, unsigned stacksToReport)
42         : m_numFrames(numFrames)
43         , m_framesToSkip(framesToSkip)
44         , m_stacksToReport(stacksToReport)
45     {
46         Thread::create("StackShotProfiler", [this] () { run(); });
47     }
48
49     // NEVER_INLINE so that framesToSkip is predictable.
50     NEVER_INLINE void profile()
51     {
52         auto locker = holdLock(m_lock);
53         m_profile.add(StackShot(m_numFrames + m_framesToSkip));
54         m_totalCount++;
55     }
56     
57 private:
58     NO_RETURN void run()
59     {
60         for (;;) {
61             sleep(1_s);
62             auto locker = holdLock(m_lock);
63             auto list = m_profile.buildList();
64             dataLog("\nHottest stacks in ", getCurrentProcessID(), ":\n");
65             for (size_t i = list.size(), count = 0; i-- && count < m_stacksToReport; count++) {
66                 auto& entry = list[i];
67                 dataLog("\nTop #", count + 1, " stack: ", entry.count * 100 / m_totalCount, "%\n");
68                 StackTrace trace(entry.key.array() + m_framesToSkip, entry.key.size() - m_framesToSkip);
69                 dataLog(trace);
70             }
71             dataLog("\n");
72         }
73     }
74     
75     WordLock m_lock;
76     Spectrum<StackShot, double> m_profile;
77     double m_totalCount { 0 };
78     unsigned m_numFrames;
79     unsigned m_framesToSkip;
80     unsigned m_stacksToReport;
81 };
82
83 #define STACK_SHOT_PROFILE(numFrames, framesToSkip, stacksToReport) do { \
84     static StackShotProfiler* stackShotProfiler; \
85     static std::once_flag stackShotProfilerOnceFlag; \
86     std::call_once(stackShotProfilerOnceFlag, [] { stackShotProfiler = new StackShotProfiler(numFrames, framesToSkip, stacksToReport); }); \
87     stackShotProfiler->profile(); \
88 } while (false)
89
90 } // namespace WTF
91