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