SkInstCnt.h revision 0e82c6729f7c3c822881cb241473a5498debf977
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 *   SK_DEFINE_INST_COUNT at the top of its .cpp file (for both kinds).
18 * At the end of an application a call to all the "root" objects'
19 * CheckInstanceCount methods should be made
20 */
21//#if defined SK_DEBUG && !defined SK_ENABLE_INST_COUNT
22//#define SK_ENABLE_INST_COUNT
23//#endif
24
25#ifdef SK_ENABLE_INST_COUNT
26#include <stdlib.h>
27#include "SkTArray.h"
28#include "SkThread_platform.h"
29
30extern bool gPrintInstCount;
31
32// The non-root classes just register themselves with their parent
33#define SK_DECLARE_INST_COUNT(className)                                    \
34    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
35                               INHERITED::AddInstChild(CheckInstanceCount);,\
36                               /**/)
37
38#define SK_DECLARE_INST_COUNT_TEMPLATE(className)                           \
39    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
40                              INHERITED::AddInstChild(CheckInstanceCount);, \
41                              typename)
42
43// The root classes registers a function to print out the memory stats when
44// the app ends
45#define SK_DECLARE_INST_COUNT_ROOT(className)                               \
46    SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);, /**/)
47
48#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep, templateType)   \
49    class SkInstanceCountHelper {                                           \
50    public:                                                                 \
51        typedef int (*PFCheckInstCnt)(int level, bool cleanUp);             \
52        SkInstanceCountHelper() {                                           \
53            if (!gInited) {                                                 \
54                initStep                                                    \
55                gChildren = new SkTArray<PFCheckInstCnt>;                   \
56                gInited = true;                                             \
57            }                                                               \
58            sk_atomic_inc(&gInstanceCount);                                 \
59        }                                                                   \
60                                                                            \
61        SkInstanceCountHelper(const SkInstanceCountHelper& other) {         \
62            sk_atomic_inc(&gInstanceCount);                                 \
63        }                                                                   \
64                                                                            \
65        ~SkInstanceCountHelper() {                                          \
66            sk_atomic_dec(&gInstanceCount);                                 \
67        }                                                                   \
68                                                                            \
69        static int32_t gInstanceCount;                                      \
70        static bool gInited;                                                \
71        static SkTArray<PFCheckInstCnt>* gChildren;                         \
72    } fInstanceCountHelper;                                                 \
73                                                                            \
74    static int32_t GetInstanceCount() {                                     \
75        return SkInstanceCountHelper::gInstanceCount;                       \
76    }                                                                       \
77                                                                            \
78    static void exitPrint() {                                               \
79        CheckInstanceCount(0, true);                                        \
80    }                                                                       \
81                                                                            \
82    static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
83        if (gPrintInstCount && 0 != SkInstanceCountHelper::gInstanceCount) {\
84            SkDebugf("%*c Leaked %s: %d\n",                                 \
85                     4*level, ' ', #className,                              \
86                     SkInstanceCountHelper::gInstanceCount);                \
87        }                                                                   \
88        if (NULL == SkInstanceCountHelper::gChildren) {                     \
89            return SkInstanceCountHelper::gInstanceCount;                   \
90        }                                                                   \
91        int childCount = SkInstanceCountHelper::gChildren->count();         \
92        int count = SkInstanceCountHelper::gInstanceCount;                  \
93        for (int i = 0; i < childCount; ++i) {                              \
94            count -= (*(*SkInstanceCountHelper::gChildren)[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 SkInstanceCountHelper::gChildren;                        \
102            SkInstanceCountHelper::gChildren = NULL;                        \
103        }                                                                   \
104        return SkInstanceCountHelper::gInstanceCount;                       \
105    }                                                                       \
106                                                                            \
107    static void AddInstChild(templateType SkInstanceCountHelper::PFCheckInstCnt \
108                                                       childCheckInstCnt) { \
109        if (CheckInstanceCount != childCheckInstCnt &&                      \
110            NULL != SkInstanceCountHelper::gChildren) {                     \
111            SkInstanceCountHelper::gChildren->push_back(childCheckInstCnt); \
112        }                                                                   \
113    }
114
115#define SK_DEFINE_INST_COUNT(className)                                     \
116    int32_t className::SkInstanceCountHelper::gInstanceCount = 0;           \
117    bool className::SkInstanceCountHelper::gInited = false;                 \
118    SkTArray<className::SkInstanceCountHelper::PFCheckInstCnt>*             \
119                        className::SkInstanceCountHelper::gChildren = NULL;
120
121#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)              \
122    templateInfo int32_t className::SkInstanceCountHelper::gInstanceCount = 0;\
123    templateInfo bool className::SkInstanceCountHelper::gInited = false;    \
124    templateInfo                                                            \
125        SkTArray<typename className::SkInstanceCountHelper::PFCheckInstCnt>*\
126                      className::SkInstanceCountHelper::gChildren = NULL;
127
128#else
129#define SK_DECLARE_INST_COUNT(className)
130#define SK_DECLARE_INST_COUNT_TEMPLATE(className)
131#define SK_DECLARE_INST_COUNT_ROOT(className)
132#define SK_DEFINE_INST_COUNT(className)
133#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
134#endif
135
136#endif // SkInstCnt_DEFINED
137