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 #include "SkTArray.h"
     24 #include "SkThread_platform.h"
     25 
     26 extern 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