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 #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:
     47         SkInstCount()                   { Inc(); }
     48         SkInstCount(const SkInstCount&) { Inc(); }
     49         ~SkInstCount()                  { sk_atomic_dec(&gCount); }
     50 
     51         SkInstCount& operator==(const SkInstCount&) { return *this; } // == can't change the count.
     52 
     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 
     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.
     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