SkInstCnt.h revision 388695146469f09942e21a2d03d8ca0428f9489c
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 "SkTArray.h"
24#include "SkThread_platform.h"
25
26extern bool gPrintInstCount;
27
28// The non-root classes just register themselves with their parent
29#define SK_DECLARE_INST_COUNT(className)                                    \
30    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
31                                   INHERITED::AddInstChild(CheckInstanceCount);)
32
33// The root classes registers a function to print out the memory stats when
34// the app ends
35#define SK_DECLARE_INST_COUNT_ROOT(className)                               \
36    SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);)
37
38#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \
39    class SkInstanceCountHelper {                                           \
40    public:                                                                 \
41        typedef int (*PFCheckInstCnt)(int level, bool cleanUp);             \
42        SkInstanceCountHelper() {                                           \
43            static bool gInited;                                            \
44            if (!gInited) {                                                 \
45                initStep                                                    \
46                GetChildren() = new SkTArray<PFCheckInstCnt>;               \
47                gInited = true;                                             \
48            }                                                               \
49            sk_atomic_inc(GetInstanceCountPtr());                           \
50        }                                                                   \
51                                                                            \
52        SkInstanceCountHelper(const SkInstanceCountHelper&) {               \
53            sk_atomic_inc(GetInstanceCountPtr());                           \
54        }                                                                   \
55                                                                            \
56        ~SkInstanceCountHelper() {                                          \
57            sk_atomic_dec(GetInstanceCountPtr());                           \
58        }                                                                   \
59                                                                            \
60        static int32_t* GetInstanceCountPtr() {                             \
61            static int32_t gInstanceCount;                                  \
62            return &gInstanceCount;                                         \
63        }                                                                   \
64                                                                            \
65        static SkTArray<PFCheckInstCnt>*& GetChildren() {                   \
66            static SkTArray<PFCheckInstCnt>* gChildren;                     \
67            return gChildren;                                               \
68        }                                                                   \
69                                                                            \
70    } fInstanceCountHelper;                                                 \
71                                                                            \
72    static int32_t GetInstanceCount() {                                     \
73        return *SkInstanceCountHelper::GetInstanceCountPtr();               \
74    }                                                                       \
75                                                                            \
76    static void exitPrint() {                                               \
77        CheckInstanceCount(0, true);                                        \
78    }                                                                       \
79                                                                            \
80    static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
81        if (gPrintInstCount && 0 != GetInstanceCount()) {                   \
82            SkDebugf("%*c Leaked %s: %d\n",                                 \
83                     4*level, ' ', #className,                              \
84                     GetInstanceCount());                                   \
85        }                                                                   \
86        if (NULL == SkInstanceCountHelper::GetChildren()) {                 \
87            return GetInstanceCount();                                      \
88        }                                                                   \
89        SkTArray<int (*)(int, bool)>* children =                            \
90            SkInstanceCountHelper::GetChildren();                           \
91        int childCount = children->count();                                 \
92        int count = GetInstanceCount();                                     \
93        for (int i = 0; i < childCount; ++i) {                              \
94            count -= (*(*children)[i])(level+1, cleanUp);                   \
95        }                                                                   \
96        SkASSERT(count >= 0);                                               \
97        if (gPrintInstCount && childCount > 0 && count > 0) {               \
98            SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count);    \
99        }                                                                   \
100        if (cleanUp) {                                                      \
101            delete children;                                                \
102            SkInstanceCountHelper::GetChildren() = NULL;                    \
103        }                                                                   \
104        return GetInstanceCount();                                          \
105    }                                                                       \
106                                                                            \
107    static void AddInstChild(int (*childCheckInstCnt)(int, bool)) {         \
108        if (CheckInstanceCount != childCheckInstCnt &&                      \
109            NULL != SkInstanceCountHelper::GetChildren()) {                 \
110            SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \
111        }                                                                   \
112    }
113
114#else
115// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by
116// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays
117// compiling.
118#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); }
119#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { }
120#endif
121
122// Following are deprecated. They are defined only for backwards API compatibility.
123#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className)
124#define SK_DEFINE_INST_COUNT(className)
125#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
126
127#endif // SkInstCnt_DEFINED
128