SkInstCnt.h revision b1aec17df6078115c797839c9646081ccba2bd09
16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Copyright 2012 Google Inc.
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Use of this source code is governed by a BSD-style license that can be
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * found in the LICENSE file.
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#ifndef SkInstCnt_DEFINED
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define SkInstCnt_DEFINED
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * The instance counting system consists of three macros that create the
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * instance counting machinery. A class is added to the system by adding:
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   SK_DECLARE_INST_COUNT at the top of its declaration for derived classes
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *   SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * At the end of an application a call to all the "root" objects'
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * CheckInstanceCount methods should be made
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "SkTypes.h"
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if SK_ENABLE_INST_COUNT
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Static variables inside member functions below may be defined multiple times
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// if Skia is being used as a dynamic library. Instance counting should be on
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// only for static builds. See bug skia:2058.
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if defined(SKIA_DLL)
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#error Instance counting works only when Skia is built as a static library.
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "SkOnce.h"
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "SkTArray.h"
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "../../src/core/SkThread.h"
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgextern bool gPrintInstCount;
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// The non-root classes just register themselves with their parent
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define SK_DECLARE_INST_COUNT(className)                                    \
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                   INHERITED::AddInstChild(CheckInstanceCount);)
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// The root classes registers a function to print out the memory stats when
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// the app ends
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define SK_DECLARE_INST_COUNT_ROOT(className)                               \
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);)
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    class SkInstanceCountHelper {                                           \
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    public:                                                                 \
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        SkInstanceCountHelper() {                                           \
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            SK_DECLARE_STATIC_ONCE(once);                                   \
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            SkOnce(&once, init, 0);                                         \
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sk_atomic_inc(GetInstanceCountPtr());                           \
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }                                                                   \
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                                            \
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        static void init(int) {                                             \
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            initStep                                                        \
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }                                                                   \
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                                            \
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        SkInstanceCountHelper(const SkInstanceCountHelper&) {               \
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sk_atomic_inc(GetInstanceCountPtr());                           \
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }                                                                   \
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                                            \
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        ~SkInstanceCountHelper() {                                          \
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            sk_atomic_dec(GetInstanceCountPtr());                           \
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }                                                                   \
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                                            \
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        static int32_t* GetInstanceCountPtr() {                             \
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            static int32_t gInstanceCount;                                  \
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return &gInstanceCount;                                         \
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }                                                                   \
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                                            \
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        static SkTArray<int (*)(int, bool)>*& GetChildren() {               \
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            static SkTArray<int (*)(int, bool)>* gChildren;                 \
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return gChildren;                                               \
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }                                                                   \
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                                                                            \
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        static SkBaseMutex& GetChildrenMutex() {                            \
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            SK_DECLARE_STATIC_MUTEX(childrenMutex);                         \
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return childrenMutex;                                           \
79        }                                                                   \
80                                                                            \
81    } fInstanceCountHelper;                                                 \
82                                                                            \
83    static int32_t GetInstanceCount() {                                     \
84        return *SkInstanceCountHelper::GetInstanceCountPtr();               \
85    }                                                                       \
86                                                                            \
87    static void exitPrint() {                                               \
88        CheckInstanceCount(0, true);                                        \
89    }                                                                       \
90                                                                            \
91    static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
92        if (gPrintInstCount && 0 != GetInstanceCount()) {                   \
93            SkDebugf("%*c Leaked %s: %d\n",                                 \
94                     4*level, ' ', #className,                              \
95                     GetInstanceCount());                                   \
96        }                                                                   \
97        if (NULL == SkInstanceCountHelper::GetChildren()) {                 \
98            return GetInstanceCount();                                      \
99        }                                                                   \
100        SkTArray<int (*)(int, bool)>* children = \
101            SkInstanceCountHelper::GetChildren();                           \
102        int childCount = children->count();                                 \
103        int count = GetInstanceCount();                                     \
104        for (int i = 0; i < childCount; ++i) {                              \
105            count -= (*(*children)[i])(level+1, cleanUp);                   \
106        }                                                                   \
107        SkASSERT(count >= 0);                                               \
108        if (gPrintInstCount && childCount > 0 && count > 0) {               \
109            SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count);    \
110        }                                                                   \
111        if (cleanUp) {                                                      \
112            delete children;                                                \
113            SkInstanceCountHelper::GetChildren() = NULL;                    \
114        }                                                                   \
115        return GetInstanceCount();                                          \
116    }                                                                       \
117                                                                            \
118    static void AddInstChild(int (*childCheckInstCnt)(int, bool)) {         \
119        if (CheckInstanceCount != childCheckInstCnt) {                      \
120            SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \
121            if (NULL == SkInstanceCountHelper::GetChildren()) {             \
122                SkInstanceCountHelper::GetChildren() =                      \
123                    new SkTArray<int (*)(int, bool)>;                       \
124            }                                                               \
125            SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \
126        }                                                                   \
127    }
128
129#else
130// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by
131// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays
132// compiling.
133#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); }
134#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { }
135#endif
136
137// Following are deprecated. They are defined only for backwards API compatibility.
138#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className)
139#define SK_DEFINE_INST_COUNT(className)
140#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
141
142#endif // SkInstCnt_DEFINED
143