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 \ 76d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman static void create_mutex(SkMutex** mutex) { \ 77d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman *mutex = SkNEW(SkMutex); \ 78d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman } \ 792ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org static SkBaseMutex& GetChildrenMutex() { \ 80d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman static SkMutex* childrenMutex; \ 81d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman SK_DECLARE_STATIC_ONCE(once); \ 82d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman SkOnce(&once, className::SkInstanceCountHelper::create_mutex, &childrenMutex);\ 83d6aeb6dc8fe21066f1a2c4813a4256a3acd3edf5bungeman return *childrenMutex; \ 842ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org } \ 852ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org \ 864d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com } fInstanceCountHelper; \ 874d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com \ 884da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com static int32_t GetInstanceCount() { \ 89ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org return *SkInstanceCountHelper::GetInstanceCountPtr(); \ 904da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com } \ 914da34e36cb7a07c3a28ae2a135b1837c26fc7aeabsalomon@google.com \ 9297fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com static void exitPrint() { \ 9323579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com CheckInstanceCount(0, true); \ 9497fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com } \ 9597fafe1b5ec06b470d36ea5cd98fe7bf2c143491robertphillips@google.com \ 9623579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com static int CheckInstanceCount(int level = 0, bool cleanUp = false) { \ 97ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org if (gPrintInstCount && 0 != GetInstanceCount()) { \ 9873e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com SkDebugf("%*c Leaked %s: %d\n", \ 9915e9d3e66e161ce23df30bc13f8a0c87d196b463robertphillips@google.com 4*level, ' ', #className, \ 100ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org GetInstanceCount()); \ 1014d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com } \ 102ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org if (NULL == SkInstanceCountHelper::GetChildren()) { \ 103ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org return GetInstanceCount(); \ 10423579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com } \ 1052ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org SkTArray<int (*)(int, bool)>* children = \ 106ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org SkInstanceCountHelper::GetChildren(); \ 107ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org int childCount = children->count(); \ 108ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org int count = GetInstanceCount(); \ 10973e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com for (int i = 0; i < childCount; ++i) { \ 110ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org count -= (*(*children)[i])(level+1, cleanUp); \ 1114d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com } \ 11273e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com SkASSERT(count >= 0); \ 113b74af872cc1ce45768df3ae03fa86ad3ed76b582robertphillips@google.com if (gPrintInstCount && childCount > 0 && count > 0) { \ 11473e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com SkDebugf("%*c Leaked ???: %d\n", 4*(level + 1), ' ', count); \ 11573e19fb1ba2562048c6987272c8d73eee6a44242reed@google.com } \ 11623579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com if (cleanUp) { \ 117ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org delete children; \ 118ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org SkInstanceCountHelper::GetChildren() = NULL; \ 11923579275c7f544763d074d90563c4b1e567ab041robertphillips@google.com } \ 120ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org return GetInstanceCount(); \ 1214d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com } \ 1224d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com \ 123ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org static void AddInstChild(int (*childCheckInstCnt)(int, bool)) { \ 1242ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org if (CheckInstanceCount != childCheckInstCnt) { \ 1252ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org SkAutoMutexAcquire ama(SkInstanceCountHelper::GetChildrenMutex()); \ 1262ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org if (NULL == SkInstanceCountHelper::GetChildren()) { \ 1272ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org SkInstanceCountHelper::GetChildren() = \ 1282ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org new SkTArray<int (*)(int, bool)>; \ 1292ab1ba055536825552d6b49f0210c4e1531f02f0commit-bot@chromium.org } \ 130ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org SkInstanceCountHelper::GetChildren()->push_back(childCheckInstCnt); \ 1314d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com } \ 132977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com } 133977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com 134977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#else 135ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// Typically SK_ENABLE_INST_COUNT=0. Make sure the class declares public typedef INHERITED by 136ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// causing a compile-time error if the typedef is missing. This way SK_ENABLE_INST_COUNT=1 stays 137ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// compiling. 138ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT(className) static void AddInstChild() { INHERITED::AddInstChild(); } 139ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT_ROOT(className) static void AddInstChild() { } 140ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#endif 141ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org 142ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org// Following are deprecated. They are defined only for backwards API compatibility. 143ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org#define SK_DECLARE_INST_COUNT_TEMPLATE(className) SK_DECLARE_INST_COUNT(className) 1444d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com#define SK_DEFINE_INST_COUNT(className) 1454fa9c9f9b42c22bffff3b2eb3fcf7f16a2ab2948robertphillips@google.com#define SK_DEFINE_INST_COUNT_TEMPLATE(templateInfo, className) 146977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com 147977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#endif // SkInstCnt_DEFINED 148