1f6747b0b90b3a270ec7b7bdfdc211cf5c19f28c2robertphillips@google.com/*
2f6747b0b90b3a270ec7b7bdfdc211cf5c19f28c2robertphillips@google.com * Copyright 2012 Google Inc.
3f6747b0b90b3a270ec7b7bdfdc211cf5c19f28c2robertphillips@google.com *
4f6747b0b90b3a270ec7b7bdfdc211cf5c19f28c2robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be
5f6747b0b90b3a270ec7b7bdfdc211cf5c19f28c2robertphillips@google.com * found in the LICENSE file.
6977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com */
7977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
8977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
9977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#ifndef SkInstCnt_DEFINED
10977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#define SkInstCnt_DEFINED
11977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
12977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com/*
13fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com * The instance counting system consists of three macros that create the
14977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com * instance counting machinery. A class is added to the system by adding:
154d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com *   SK_DECLARE_INST_COUNT at the top of its declaration for derived classes
164d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com *   SK_DECLARE_INST_COUNT_ROOT at the top of its declaration for a root class
174d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com * At the end of an application a call to all the "root" objects'
184d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com * CheckInstanceCount methods should be made
19977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com */
204e23068b374023d43c4c725138d523721d975892bsalomon@google.com#include "SkTypes.h"
21594dd3cd78e2f970d53bb0934fbbb63b41e1d40ccaryclark@google.com
224e23068b374023d43c4c725138d523721d975892bsalomon@google.com#if SK_ENABLE_INST_COUNT
232ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org// Static variables inside member functions below may be defined multiple times
242ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org// if Skia is being used as a dynamic library. Instance counting should be on
252ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org// only for static builds. See bug skia:2058.
262ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org#if defined(SKIA_DLL)
272ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org#error Instance counting works only when Skia is built as a static library.
282ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org#endif
292ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org
302ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org#include "SkOnce.h"
314d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com#include "SkTArray.h"
3286b0de4745a8a8317b54f23878498633b9210a8fcommit-bot@chromium.org#include "SkThread.h"
33b74af872cc1ce45768df3ae03fa86ad3ed76b582robertphillips@google.comextern bool gPrintInstCount;
34b74af872cc1ce45768df3ae03fa86ad3ed76b582robertphillips@google.com
3597fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com// The non-root classes just register themselves with their parent
364d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com#define SK_DECLARE_INST_COUNT(className)                                    \
374d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com    SK_DECLARE_INST_COUNT_INTERNAL(className,                               \
38ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org                                   INHERITED::AddInstChild(CheckInstanceCount);)
394d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com
4097fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com// The root classes registers a function to print out the memory stats when
4197fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com// the app ends
424d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com#define SK_DECLARE_INST_COUNT_ROOT(className)                               \
43ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org    SK_DECLARE_INST_COUNT_INTERNAL(className, atexit(exitPrint);)
444d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com
45ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT_INTERNAL(className, initStep)                 \
464d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com    class SkInstanceCountHelper {                                           \
474d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com    public:                                                                 \
484d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        SkInstanceCountHelper() {                                           \
492ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            SK_DECLARE_STATIC_ONCE(once);                                   \
501b81877880253c75f835eede9a8ee21b9e7b584amtklein            SkOnce(&once, init);                                            \
51ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            sk_atomic_inc(GetInstanceCountPtr());                           \
524d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        }                                                                   \
534d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com                                                                            \
541b81877880253c75f835eede9a8ee21b9e7b584amtklein        static void init() {                                                \
552ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            initStep                                                        \
562ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org        }                                                                   \
572ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org                                                                            \
58e0e385c1d4171e065348ba17c546b3463a0bd651sugoi@google.com        SkInstanceCountHelper(const SkInstanceCountHelper&) {               \
59ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            sk_atomic_inc(GetInstanceCountPtr());                           \
604d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        }                                                                   \
614d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com                                                                            \
624d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        ~SkInstanceCountHelper() {                                          \
63ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            sk_atomic_dec(GetInstanceCountPtr());                           \
64ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        }                                                                   \
65ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org                                                                            \
66ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        static int32_t* GetInstanceCountPtr() {                             \
67ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            static int32_t gInstanceCount;                                  \
68ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            return &gInstanceCount;                                         \
69ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        }                                                                   \
70ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org                                                                            \
712ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org        static SkTArray<int (*)(int, bool)>*& GetChildren() {               \
722ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            static SkTArray<int (*)(int, bool)>* gChildren;                 \
73ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            return gChildren;                                               \
744d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        }                                                                   \
754d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com                                                                            \
762ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org        static SkBaseMutex& GetChildrenMutex() {                            \
772ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            SK_DECLARE_STATIC_MUTEX(childrenMutex);                         \
782ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            return childrenMutex;                                           \
792ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org        }                                                                   \
802ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org                                                                            \
814d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com    } fInstanceCountHelper;                                                 \
824d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com                                                                            \
834da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com    static int32_t GetInstanceCount() {                                     \
84ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        return *SkInstanceCountHelper::GetInstanceCountPtr();               \
854da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com    }                                                                       \
864da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com                                                                            \
8797fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com    static void exitPrint() {                                               \
8823579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com        CheckInstanceCount(0, true);                                        \
8997fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com    }                                                                       \
9097fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com                                                                            \
9123579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com    static int CheckInstanceCount(int level = 0, bool cleanUp = false) {    \
92ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        if (gPrintInstCount && 0 != GetInstanceCount()) {                   \
9373e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com            SkDebugf("%*c Leaked %s: %d\n",                                 \
9415e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.com                     4*level, ' ', #className,                              \
95ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org                     GetInstanceCount());                                   \
964d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        }                                                                   \
97ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        if (NULL == SkInstanceCountHelper::GetChildren()) {                 \
98ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            return GetInstanceCount();                                      \
9923579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com        }                                                                   \
1002ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org        SkTArray<int (*)(int, bool)>* children = \
101ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            SkInstanceCountHelper::GetChildren();                           \
102ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        int childCount = children->count();                                 \
103ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        int count = GetInstanceCount();                                     \
10473e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com        for (int i = 0; i < childCount; ++i) {                              \
105ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            count -= (*(*children)[i])(level+1, cleanUp);                   \
1064d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        }                                                                   \
10773e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com        SkASSERT(count >= 0);                                               \
108b74af872cc1ce45768df3ae03fa86ad3ed76b582robertphillips@google.com        if (gPrintInstCount && childCount > 0 && count > 0) {               \
10973e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com            SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count);    \
11073e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com        }                                                                   \
11123579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com        if (cleanUp) {                                                      \
112ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            delete children;                                                \
113ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            SkInstanceCountHelper::GetChildren() = NULL;                    \
11423579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com        }                                                                   \
115ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org        return GetInstanceCount();                                          \
1164d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com    }                                                                       \
1174d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com                                                                            \
118ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org    static void AddInstChild(int (*childCheckInstCnt)(int, bool)) {         \
1192ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org        if (CheckInstanceCount != childCheckInstCnt) {                      \
1202ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \
1212ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            if (NULL == SkInstanceCountHelper::GetChildren()) {             \
1222ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org                SkInstanceCountHelper::GetChildren() =                      \
1232ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org                    new SkTArray<int (*)(int, bool)>;                       \
1242ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org            }                                                               \
125ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org            SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \
1264d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com        }                                                                   \
127977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com    }
128977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
129977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#else
130ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by
131ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays
132ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// compiling.
133ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); }
134ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { }
135ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#endif
136ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org
137ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// Following are deprecated. They are defined only for backwards API compatibility.
138ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className)
1394d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com#define SK_DEFINE_INST_COUNT(className)
1404fa9c9f9b42c22bffff3b2eb3fcf7f16a2ab2948robertphillips@google.com#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className)
141977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
142977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#endif // SkInstCnt_DEFINED
143