michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkInstCnt_DEFINED michael@0: #define SkInstCnt_DEFINED michael@0: michael@0: /* michael@0: * The instance counting system consists of three macros that create the michael@0: * instance counting machinery. A class is added to the system by adding: michael@0: * SK_DECLARE_INST_COUNT at the top of its declaration for derived classes michael@0: * SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class michael@0: * At the end of an application a call to all the "root" objects' michael@0: * CheckInstanceCount methods should be made michael@0: */ michael@0: #include "SkTypes.h" michael@0: michael@0: #if SK_ENABLE_INST_COUNT michael@0: // Static variables inside member functions below may be defined multiple times michael@0: // if Skia is being used as a dynamic library. Instance counting should be on michael@0: // only for static builds. See bug skia:2058. michael@0: #if defined(SKIA_DLL) michael@0: #error Instance counting works only when Skia is built as a static library. michael@0: #endif michael@0: michael@0: #include "SkOnce.h" michael@0: #include "SkTArray.h" michael@0: #include "SkThread.h" michael@0: extern bool gPrintInstCount; michael@0: michael@0: // The non-root classes just register themselves with their parent michael@0: #define SK_DECLARE_INST_COUNT(className) \ michael@0: SK_DECLARE_INST_COUNT_INTERNAL(className, \ michael@0: INHERITED::AddInstChild(CheckInstanceCount);) michael@0: michael@0: // The root classes registers a function to print out the memory stats when michael@0: // the app ends michael@0: #define SK_DECLARE_INST_COUNT_ROOT(className) \ michael@0: SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);) michael@0: michael@0: #define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep) \ michael@0: class SkInstanceCountHelper { \ michael@0: public: \ michael@0: SkInstanceCountHelper() { \ michael@0: SK_DECLARE_STATIC_ONCE(once); \ michael@0: SkOnce(&once, init, 0); \ michael@0: sk_atomic_inc(GetInstanceCountPtr()); \ michael@0: } \ michael@0: \ michael@0: static void init(int) { \ michael@0: initStep \ michael@0: } \ michael@0: \ michael@0: SkInstanceCountHelper(const SkInstanceCountHelper&) { \ michael@0: sk_atomic_inc(GetInstanceCountPtr()); \ michael@0: } \ michael@0: \ michael@0: ~SkInstanceCountHelper() { \ michael@0: sk_atomic_dec(GetInstanceCountPtr()); \ michael@0: } \ michael@0: \ michael@0: static int32_t* GetInstanceCountPtr() { \ michael@0: static int32_t gInstanceCount; \ michael@0: return &gInstanceCount; \ michael@0: } \ michael@0: \ michael@0: static SkTArray*& GetChildren() { \ michael@0: static SkTArray* gChildren; \ michael@0: return gChildren; \ michael@0: } \ michael@0: \ michael@0: static SkBaseMutex& GetChildrenMutex() { \ michael@0: SK_DECLARE_STATIC_MUTEX(childrenMutex); \ michael@0: return childrenMutex; \ michael@0: } \ michael@0: \ michael@0: } fInstanceCountHelper; \ michael@0: \ michael@0: static int32_t GetInstanceCount() { \ michael@0: return *SkInstanceCountHelper::GetInstanceCountPtr(); \ michael@0: } \ michael@0: \ michael@0: static void exitPrint() { \ michael@0: CheckInstanceCount(0, true); \ michael@0: } \ michael@0: \ michael@0: static int CheckInstanceCount(int level = 0, bool cleanUp = false) { \ michael@0: if (gPrintInstCount && 0 != GetInstanceCount()) { \ michael@0: SkDebugf("%*c Leaked %s: %d\n", \ michael@0: 4*level, ' ', #className, \ michael@0: GetInstanceCount()); \ michael@0: } \ michael@0: if (NULL == SkInstanceCountHelper::GetChildren()) { \ michael@0: return GetInstanceCount(); \ michael@0: } \ michael@0: SkTArray* children = \ michael@0: SkInstanceCountHelper::GetChildren(); \ michael@0: int childCount = children->count(); \ michael@0: int count = GetInstanceCount(); \ michael@0: for (int i = 0; i < childCount; ++i) { \ michael@0: count -= (*(*children)[i])(level+1, cleanUp); \ michael@0: } \ michael@0: SkASSERT(count >= 0); \ michael@0: if (gPrintInstCount && childCount > 0 && count > 0) { \ michael@0: SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count); \ michael@0: } \ michael@0: if (cleanUp) { \ michael@0: delete children; \ michael@0: SkInstanceCountHelper::GetChildren() = NULL; \ michael@0: } \ michael@0: return GetInstanceCount(); \ michael@0: } \ michael@0: \ michael@0: static void AddInstChild(int (*childCheckInstCnt)(int, bool)) { \ michael@0: if (CheckInstanceCount != childCheckInstCnt) { \ michael@0: SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \ michael@0: if (NULL == SkInstanceCountHelper::GetChildren()) { \ michael@0: SkInstanceCountHelper::GetChildren() = \ michael@0: new SkTArray; \ michael@0: } \ michael@0: SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \ michael@0: } \ michael@0: } michael@0: michael@0: #else michael@0: // Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by michael@0: // causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays michael@0: // compiling. michael@0: #define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); } michael@0: #define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { } michael@0: #endif michael@0: michael@0: // Following are deprecated. They are defined only for backwards API compatibility. michael@0: #define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className) michael@0: #define SK_DEFINE_INST_COUNT(className) michael@0: #define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className) michael@0: michael@0: #endif // SkInstCnt_DEFINED