Home | History | Annotate | Download | only in core
      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 // Static variables inside member functions below may be defined multiple times
     24 // if Skia is being used as a dynamic library. Instance counting should be on
     25 // only for static builds. See bug skia:2058.
     26 #if defined(SKIA_DLL)
     27 #error Instance counting works only when Skia is built as a static library.
     28 #endif
     29 
     30 #include "SkOnce.h"
     31 #include "SkTArray.h"
     32 #include "SkThread.h"
     33 extern bool gPrintInstCount;
     34 
     35 // The non-root classes just register themselves with their parent
     36 #define SK_DECLARE_INST_COUNT(className)                                    \
     37     SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
     38                                    INHERITED::AddInstChild(CheckInstanceCount);)
     39 
     40 // The root classes registers a function to print out the memory stats when
     41 // the app ends
     42 #define SK_DECLARE_INST_COUNT_ROOT(className)                               \
     43     SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);)
     44 
     45 #define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \
     46     class SkInstanceCountHelper {                                           \
     47     public:                                                                 \
     48         SkInstanceCountHelper() {                                           \
     49             SK_DECLARE_STATIC_ONCE(once);                                   \
     50             SkOnce(&once, init);                                            \
     51             sk_atomic_inc(GetInstanceCountPtr());                           \
     52         }                                                                   \
     53                                                                             \
     54         static void init() {                                                \
     55             initStep                                                        \
     56         }                                                                   \
     57                                                                             \
     58         SkInstanceCountHelper(const SkInstanceCountHelper&) {               \
     59             sk_atomic_inc(GetInstanceCountPtr());                           \
     60         }                                                                   \
     61                                                                             \
     62         ~SkInstanceCountHelper() {                                          \
     63             sk_atomic_dec(GetInstanceCountPtr());                           \
     64         }                                                                   \
     65                                                                             \
     66         static int32_t* GetInstanceCountPtr() {                             \
     67             static int32_t gInstanceCount;                                  \
     68             return &gInstanceCount;                                         \
     69         }                                                                   \
     70                                                                             \
     71         static SkTArray<int (*)(int, bool)>*& GetChildren() {               \
     72             static SkTArray<int (*)(int, bool)>* gChildren;                 \
     73             return gChildren;                                               \
     74         }                                                                   \
     75                                                                             \
     76         static void create_mutex(SkMutex** mutex) {                         \
     77             *mutex = SkNEW(SkMutex);                                        \
     78         }                                                                   \
     79         static SkBaseMutex& GetChildrenMutex() {                            \
     80             static SkMutex* childrenMutex;                                  \
     81             SK_DECLARE_STATIC_ONCE(once);                                   \
     82             SkOnce(&once, className::SkInstanceCountHelper::create_mutex, &childrenMutex);\
     83             return *childrenMutex;                                          \
     84         }                                                                   \
     85                                                                             \
     86     } fInstanceCountHelper;                                                 \
     87                                                                             \
     88     static int32_t GetInstanceCount() {                                     \
     89         return *SkInstanceCountHelper::GetInstanceCountPtr();               \
     90     }                                                                       \
     91                                                                             \
     92     static void exitPrint() {                                               \
     93         CheckInstanceCount(0, true);                                        \
     94     }                                                                       \
     95                                                                             \
     96     static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
     97         if (gPrintInstCount && 0 != GetInstanceCount()) {                   \
     98             SkDebugf("%*c Leaked %s: %d\n",                                 \
     99                      4*level, ' ', #className,                              \
    100                      GetInstanceCount());                                   \
    101         }                                                                   \
    102         if (NULL == SkInstanceCountHelper::GetChildren()) {                 \
    103             return GetInstanceCount();                                      \
    104         }                                                                   \
    105         SkTArray<int (*)(int, bool)>* children = \
    106             SkInstanceCountHelper::GetChildren();                           \
    107         int childCount = children->count();                                 \
    108         int count = GetInstanceCount();                                     \
    109         for (int i = 0; i < childCount; ++i) {                              \
    110             count -= (*(*children)[i])(level+1, cleanUp);                   \
    111         }                                                                   \
    112         SkASSERT(count >= 0);                                               \
    113         if (gPrintInstCount && childCount > 0 && count > 0) {               \
    114             SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count);    \
    115         }                                                                   \
    116         if (cleanUp) {                                                      \
    117             delete children;                                                \
    118             SkInstanceCountHelper::GetChildren() = NULL;                    \
    119         }                                                                   \
    120         return GetInstanceCount();                                          \
    121     }                                                                       \
    122                                                                             \
    123     static void AddInstChild(int (*childCheckInstCnt)(int, bool)) {         \
    124         if (CheckInstanceCount != childCheckInstCnt) {                      \
    125             SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \
    126             if (NULL == SkInstanceCountHelper::GetChildren()) {             \
    127                 SkInstanceCountHelper::GetChildren() =                      \
    128                     new SkTArray<int (*)(int, bool)>;                       \
    129             }                                                               \
    130             SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \
    131         }                                                                   \
    132     }
    133 
    134 #else
    135 // Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by
    136 // causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays
    137 // compiling.
    138 #define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); }
    139 #define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { }
    140 #endif
    141 
    142 // Following are deprecated. They are defined only for backwards API compatibility.
    143 #define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className)
    144 #define SK_DEFINE_INST_COUNT(className)
    145 #define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
    146 
    147 #endif // SkInstCnt_DEFINED
    148