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 SkBaseMutex& GetChildrenMutex() {                            \
     77             SK_DECLARE_STATIC_MUTEX(childrenMutex);                         \
     78             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