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 #ifndef SkInstCnt_DEFINED 9 #define SkInstCnt_DEFINED 10 11 /* To count all instances of T, including all subclasses of T, 12 * add SK_DECLARE_INST_COUNT(T) to T's class definition. 13 * If you want to print out counts of leaked instances, set gPrintInstCount to true in main(). 14 * 15 * E.g. 16 * struct Base { SK_DECLARE_INST_COUNT(Base) }; 17 * struct A : public Base {}; 18 * struct SubBase : public Base { SK_DECLARE_INST_COUNT(SubBase); } 19 * struct B : public SubBase {}; 20 * 21 * If gPrintInstCount is true, at the program exit you will see something like: 22 * Base: <N> leaked instances 23 * SubBase: <M> leaked instances 24 * where N >= M. Leaked instances of A count against Base; leaked instances of B count against 25 * both SubBase and Base. 26 * 27 * If SK_ENABLE_INST_COUNT is not defined or defined to 0, or we're in a shared library build, 28 * this entire system is compiled away to a noop. 29 */ 30 31 #include "SkTypes.h" 32 33 #if SK_ENABLE_INST_COUNT && !defined(SKIA_DLL) // See skia:2058 for why we noop on shared builds. 34 #include "SkThread.h" 35 #include <stdlib.h> 36 37 #define SK_DECLARE_INST_COUNT(T) \ 38 static const char* InstCountClassName() { return #T; } \ 39 SkInstCount<T, T::InstCountClassName> fInstCnt; \ 40 static int32_t GetInstanceCount() { return SkInstCount<T, InstCountClassName>::Count(); } 41 42 extern bool gPrintInstCount; 43 44 template <typename T, const char*(Name)()> 45 class SkInstCount { 46 public: SkInstCount()47 SkInstCount() { Inc(); } SkInstCount(const SkInstCount &)48 SkInstCount(const SkInstCount&) { Inc(); } ~SkInstCount()49 ~SkInstCount() { sk_atomic_dec(&gCount); } 50 51 SkInstCount& operator==(const SkInstCount&) { return *this; } // == can't change the count. 52 Inc()53 static void Inc() { 54 // If it's the first time we go from 0 to 1, register to print leaks at process exit. 55 if (0 == sk_atomic_inc(&gCount) && sk_atomic_cas(&gRegistered, 0, 1)) { 56 atexit(PrintAtExit); 57 } 58 } 59 PrintAtExit()60 static void PrintAtExit() { 61 int32_t leaks = Count(); 62 if (gPrintInstCount && leaks > 0) { 63 SkDebugf("Leaked %s: %d\n", Name(), leaks); 64 } 65 } 66 67 // FIXME: Used publicly by unit tests. Seems like a bad idea in a DM world. Count()68 static int32_t Count() { return sk_acquire_load(&gCount); } 69 70 private: 71 static int32_t gCount, gRegistered; 72 }; 73 // As template values, these will be deduplicated. (No one-definition rule problems.) 74 template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gCount = 0; 75 template <typename T, const char*(Name)()> int32_t SkInstCount<T, Name>::gRegistered = 0; 76 #else 77 #define SK_DECLARE_INST_COUNT(T) 78 #endif 79 80 void SkInstCountPrintLeaksOnExit(); 81 82 #endif // SkInstCnt_DEFINED 83