1/*
2 * Copyright (C) 2011 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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#pragma once
30
31#include <stdint.h>
32#include <wtf/Assertions.h>
33
34namespace JSC {
35
36// AbstractSamplingCounter:
37//
38// Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
39// See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
40class AbstractSamplingCounter {
41 friend class DeletableSamplingCounter;
42public:
43 void count(uint32_t count = 1)
44 {
45 m_counter += count;
46 }
47
48 JS_EXPORT_PRIVATE static void dump();
49
50 int64_t* addressOfCounter() { return &m_counter; }
51
52protected:
53 // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
54 void init(const char* name)
55 {
56 m_counter = 0;
57 m_name = name;
58
59 // Set m_next to point to the head of the chain, and inform whatever is
60 // currently at the head that this node will now hold the pointer to it.
61 m_next = s_abstractSamplingCounterChain;
62 s_abstractSamplingCounterChain->m_referer = &m_next;
63 // Add this node to the head of the list.
64 s_abstractSamplingCounterChain = this;
65 m_referer = &s_abstractSamplingCounterChain;
66 }
67
68 int64_t m_counter;
69 const char* m_name;
70 AbstractSamplingCounter* m_next;
71 // This is a pointer to the pointer to this node in the chain; used to
72 // allow fast linked list deletion.
73 AbstractSamplingCounter** m_referer;
74 // Null object used to detect end of static chain.
75 static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
76 JS_EXPORT_PRIVATE static AbstractSamplingCounter* s_abstractSamplingCounterChain;
77 static bool s_completed;
78};
79
80#if ENABLE(SAMPLING_COUNTERS)
81// SamplingCounter:
82//
83// This class is suitable and (hopefully!) convenient for cases where a counter is
84// required within the scope of a single function. It can be instantiated as a
85// static variable since it contains a constructor but not a destructor (static
86// variables in WebKit cannot have destructors).
87//
88// For example:
89//
90// void someFunction()
91// {
92// static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine.");
93// countMe.count();
94// // ...
95// }
96//
97class SamplingCounter : public AbstractSamplingCounter {
98public:
99 SamplingCounter(const char* name) { init(name); }
100};
101
102// GlobalSamplingCounter:
103//
104// This class is suitable for use where a counter is to be declared globally,
105// since it contains neither a constructor nor destructor. Instead, ensure
106// that 'name()' is called to provide the counter with a name (and also to
107// allow it to be printed out on exit).
108//
109// GlobalSamplingCounter globalCounter;
110//
111// void firstFunction()
112// {
113// // Put this within a function that is definitely called!
114// // (Or alternatively alongside all calls to 'count()').
115// globalCounter.name("I Name You Destroyer.");
116// globalCounter.count();
117// // ...
118// }
119//
120// void secondFunction()
121// {
122// globalCounter.count();
123// // ...
124// }
125//
126class GlobalSamplingCounter : public AbstractSamplingCounter {
127public:
128 void name(const char* name)
129 {
130 // Global objects should be mapped in zero filled memory, so this should
131 // be a safe (albeit not necessarily threadsafe) check for 'first call'.
132 if (!m_next)
133 init(name);
134 }
135};
136
137// DeletableSamplingCounter:
138//
139// The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
140// use within a global or static scope, and as such cannot have a destructor.
141// This means there is no convenient way for them to remove themselves from the
142// static list of counters, and should an instance of either class be freed
143// before 'dump()' has walked over the list it will potentially walk over an
144// invalid pointer.
145//
146// This class is intended for use where the counter may possibly be deleted before
147// the program exits. Should this occur, the counter will print it's value to
148// stderr, and remove itself from the static list. Example:
149//
150// DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
151// counter->count();
152// delete counter;
153//
154class DeletableSamplingCounter : public AbstractSamplingCounter {
155public:
156 DeletableSamplingCounter(const char* name) { init(name); }
157
158 ~DeletableSamplingCounter()
159 {
160 if (!s_completed)
161 dataFile("DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
162 // Our m_referer pointer should know where the pointer to this node is,
163 // and m_next should know that this node is the previous node in the list.
164 ASSERT(*m_referer == this);
165 ASSERT(m_next->m_referer == &m_next);
166 // Remove this node from the list, and inform m_next that we have done so.
167 m_next->m_referer = m_referer;
168 *m_referer = m_next;
169 }
170};
171#endif
172
173} // namespace JSC
174