SkInstCnt.h revision 469a9732c5e75c70e73f51a5e4e0657b0129fdc7
1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#ifndef SkInstCnt_DEFINED
10#define SkInstCnt_DEFINED
11
12/*
13 * The instance counting system consists of three macros that create the
14 * instance counting machinery. A class is added to the system by adding:
15 *   SK_DECLARE_INST_COUNT at the top of its declaration for derived classes
16 *   SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class
17 * At the end of an application a call to all the "root" objects'
18 * CheckInstanceCount methods should be made
19 */
20#include "SkTypes.h"
21
22#if SK_ENABLE_INST_COUNT
23#include "SkOnce.h"
24#include "SkTArray.h"
25#include "SkThread_platform.h"
26
27extern bool gPrintInstCount;
28
29// The non-root classes just register themselves with their parent
30#define SK_DECLARE_INST_COUNT(className)                                    \
31    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
32                                   INHERITED::AddInstChild(CheckInstanceCount);)
33
34// The root classes registers a function to print out the memory stats when
35// the app ends
36#define SK_DECLARE_INST_COUNT_ROOT(className)                               \
37    SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);)
38
39#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \
40    class SkInstanceCountHelper {                                           \
41    public:                                                                 \
42        typedef int (*PFCheckInstCnt)(int level, bool cleanUp);             \
43        SkInstanceCountHelper() {                                           \
44            SK_DECLARE_STATIC_ONCE(once);                                   \
45            SkOnce(&once, init, 0);                                         \
46            sk_atomic_inc(GetInstanceCountPtr());                           \
47        }                                                                   \
48                                                                            \
49        static void init(int) {                                             \
50            initStep                                                        \
51        }                                                                   \
52                                                                            \
53        SkInstanceCountHelper(const SkInstanceCountHelper&) {               \
54            sk_atomic_inc(GetInstanceCountPtr());                           \
55        }                                                                   \
56                                                                            \
57        ~SkInstanceCountHelper() {                                          \
58            sk_atomic_dec(GetInstanceCountPtr());                           \
59        }                                                                   \
60                                                                            \
61        static int32_t* GetInstanceCountPtr() {                             \
62            static int32_t gInstanceCount;                                  \
63            return &gInstanceCount;                                         \
64        }                                                                   \
65                                                                            \
66        static SkTArray<PFCheckInstCnt>*& GetChildren() {                   \
67            static SkTArray<PFCheckInstCnt>* gChildren;                     \
68            return gChildren;                                               \
69        }                                                                   \
70                                                                            \
71        static SkBaseMutex& GetChildrenMutex() {                            \
72            SK_DECLARE_STATIC_MUTEX(childrenMutex);                         \
73            return childrenMutex;                                           \
74        }                                                                   \
75                                                                            \
76    } fInstanceCountHelper;                                                 \
77                                                                            \
78    static int32_t GetInstanceCount() {                                     \
79        return *SkInstanceCountHelper::GetInstanceCountPtr();               \
80    }                                                                       \
81                                                                            \
82    static void exitPrint() {                                               \
83        CheckInstanceCount(0, true);                                        \
84    }                                                                       \
85                                                                            \
86    static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
87        if (gPrintInstCount && 0 != GetInstanceCount()) {                   \
88            SkDebugf("%*c Leaked %s: %d\n",                                 \
89                     4*level, ' ', #className,                              \
90                     GetInstanceCount());                                   \
91        }                                                                   \
92        if (NULL == SkInstanceCountHelper::GetChildren()) {                 \
93            return GetInstanceCount();                                      \
94        }                                                                   \
95        SkTArray<typename SkInstanceCountHelper::PFCheckInstCnt>* children = \
96            SkInstanceCountHelper::GetChildren();                           \
97        int childCount = children->count();                                 \
98        int count = GetInstanceCount();                                     \
99        for (int i = 0; i < childCount; ++i) {                              \
100            count -= (*(*children)[i])(level+1, cleanUp);                   \
101        }                                                                   \
102        SkASSERT(count >= 0);                                               \
103        if (gPrintInstCount && childCount > 0 && count > 0) {               \
104            SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count);    \
105        }                                                                   \
106        if (cleanUp) {                                                      \
107            delete children;                                                \
108            SkInstanceCountHelper::GetChildren() = NULL;                    \
109        }                                                                   \
110        return GetInstanceCount();                                          \
111    }                                                                       \
112                                                                            \
113    static void AddInstChild(int (*childCheckInstCnt)(int, bool)) {         \
114        if (CheckInstanceCount != childCheckInstCnt) {                      \
115            SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \
116            if (NULL == SkInstanceCountHelper::GetChildren()) {             \
117                SkInstanceCountHelper::GetChildren() =                      \
118                    new SkTArray<typename SkInstanceCountHelper::PFCheckInstCnt>; \
119            }                                                               \
120            SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \
121        }                                                                   \
122    }
123
124#else
125// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by
126// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays
127// compiling.
128#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); }
129#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { }
130#endif
131
132// Following are deprecated. They are defined only for backwards API compatibility.
133#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className)
134#define SK_DEFINE_INST_COUNT(className)
135#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
136
137#endif // SkInstCnt_DEFINED
138