6f07665768
This code requires fewer macros to use it (just one), has less code in macro definitions, and has simpler synchronization code (just atomic ints, no SkOnce, no SkMutex, etc.) A minor downside, we lose indentation and reverse-ordering in the final report: Leaked SkRefCntBase: 7 Leaked SkFontMgr: 1 Leaked SkWeakRefCnt: 1 Leaked SkTypeface: 1 Leaked SkFlattenable: 3 Leaked SkXfermode: 3 Leaked SkPathRef: 1 Leaked SkPixelRef: 1 Leaked SkMallocPixelRef: 1 becomes Leaked SkXfermode: 3 Leaked SkMallocPixelRef: 1 Leaked SkPixelRef: 1 Leaked SkPathRef: 1 Leaked SkFlattenable: 3 Leaked SkTypeface: 1 Leaked SkWeakRefCnt: 1 Leaked SkFontMgr: 1 Leaked SkRefCntBase: 7 This is motivated by wanting to land https://codereview.chromium.org/806473006/, which makes sure all static use of SkOnce are in global scope. The current implementation of SkInstCnt uses them in function scope, which isn't safe. BUG=skia: No public API changes. TBR=reed@google.com Review URL: https://codereview.chromium.org/841263004
243 lines
6.3 KiB
C++
243 lines
6.3 KiB
C++
/*
|
|
* Copyright 2011 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "Test.h"
|
|
// This is a GPU-backend specific test
|
|
#if SK_SUPPORT_GPU
|
|
#include "GrMemoryPool.h"
|
|
#include "SkInstCnt.h"
|
|
#include "SkRandom.h"
|
|
#include "SkTDArray.h"
|
|
#include "SkTemplates.h"
|
|
|
|
// A is the top of an inheritance tree of classes that overload op new and
|
|
// and delete to use a GrMemoryPool. The objects have values of different types
|
|
// that can be set and checked.
|
|
class A {
|
|
public:
|
|
A() {};
|
|
virtual void setValues(int v) {
|
|
fChar = static_cast<char>(v);
|
|
}
|
|
virtual bool checkValues(int v) {
|
|
return fChar == static_cast<char>(v);
|
|
}
|
|
virtual ~A() {};
|
|
|
|
void* operator new(size_t size) {
|
|
if (!gPool.get()) {
|
|
return ::operator new(size);
|
|
} else {
|
|
return gPool->allocate(size);
|
|
}
|
|
}
|
|
|
|
void operator delete(void* p) {
|
|
if (!gPool.get()) {
|
|
::operator delete(p);
|
|
} else {
|
|
return gPool->release(p);
|
|
}
|
|
}
|
|
|
|
SK_DECLARE_INST_COUNT(A);
|
|
|
|
static A* Create(SkRandom* r);
|
|
|
|
static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
|
|
#if SK_ENABLE_INST_COUNT
|
|
SkASSERT(0 == GetInstanceCount());
|
|
#endif
|
|
GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize);
|
|
gPool.reset(pool);
|
|
}
|
|
|
|
static void ResetAllocator() {
|
|
#if SK_ENABLE_INST_COUNT
|
|
SkASSERT(0 == GetInstanceCount());
|
|
#endif
|
|
gPool.reset(NULL);
|
|
}
|
|
|
|
private:
|
|
static SkAutoTDelete<GrMemoryPool> gPool;
|
|
char fChar;
|
|
};
|
|
|
|
SkAutoTDelete<GrMemoryPool> A::gPool;
|
|
|
|
class B : public A {
|
|
public:
|
|
B() {};
|
|
virtual void setValues(int v) {
|
|
fDouble = static_cast<double>(v);
|
|
this->INHERITED::setValues(v);
|
|
}
|
|
virtual bool checkValues(int v) {
|
|
return fDouble == static_cast<double>(v) &&
|
|
this->INHERITED::checkValues(v);
|
|
}
|
|
virtual ~B() {};
|
|
|
|
private:
|
|
double fDouble;
|
|
|
|
typedef A INHERITED;
|
|
};
|
|
|
|
class C : public A {
|
|
public:
|
|
C() {};
|
|
virtual void setValues(int v) {
|
|
fInt64 = static_cast<int64_t>(v);
|
|
this->INHERITED::setValues(v);
|
|
}
|
|
virtual bool checkValues(int v) {
|
|
return fInt64 == static_cast<int64_t>(v) &&
|
|
this->INHERITED::checkValues(v);
|
|
}
|
|
virtual ~C() {};
|
|
|
|
private:
|
|
int64_t fInt64;
|
|
|
|
typedef A INHERITED;
|
|
};
|
|
|
|
// D derives from C and owns a dynamically created B
|
|
class D : public C {
|
|
public:
|
|
D() {
|
|
fB = new B();
|
|
}
|
|
virtual void setValues(int v) {
|
|
fVoidStar = reinterpret_cast<void*>(v);
|
|
this->INHERITED::setValues(v);
|
|
fB->setValues(v);
|
|
}
|
|
virtual bool checkValues(int v) {
|
|
return fVoidStar == reinterpret_cast<void*>(v) &&
|
|
fB->checkValues(v) &&
|
|
this->INHERITED::checkValues(v);
|
|
}
|
|
virtual ~D() {
|
|
delete fB;
|
|
}
|
|
private:
|
|
void* fVoidStar;
|
|
B* fB;
|
|
|
|
typedef C INHERITED;
|
|
};
|
|
|
|
class E : public A {
|
|
public:
|
|
E() {}
|
|
virtual void setValues(int v) {
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) {
|
|
fIntArray[i] = v;
|
|
}
|
|
this->INHERITED::setValues(v);
|
|
}
|
|
virtual bool checkValues(int v) {
|
|
bool ok = true;
|
|
for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) {
|
|
if (fIntArray[i] != v) {
|
|
ok = false;
|
|
}
|
|
}
|
|
return ok && this->INHERITED::checkValues(v);
|
|
}
|
|
virtual ~E() {}
|
|
private:
|
|
int fIntArray[20];
|
|
|
|
typedef A INHERITED;
|
|
};
|
|
|
|
A* A::Create(SkRandom* r) {
|
|
switch (r->nextRangeU(0, 4)) {
|
|
case 0:
|
|
return new A;
|
|
case 1:
|
|
return new B;
|
|
case 2:
|
|
return new C;
|
|
case 3:
|
|
return new D;
|
|
case 4:
|
|
return new E;
|
|
default:
|
|
// suppress warning
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
struct Rec {
|
|
A* fInstance;
|
|
int fValue;
|
|
};
|
|
|
|
DEF_TEST(GrMemoryPool, reporter) {
|
|
// prealloc and min alloc sizes for the pool
|
|
static const size_t gSizes[][2] = {
|
|
{0, 0},
|
|
{10 * sizeof(A), 20 * sizeof(A)},
|
|
{100 * sizeof(A), 100 * sizeof(A)},
|
|
{500 * sizeof(A), 500 * sizeof(A)},
|
|
{10000 * sizeof(A), 0},
|
|
{1, 100 * sizeof(A)},
|
|
};
|
|
// different percentages of creation vs deletion
|
|
static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f};
|
|
// number of create/destroys per test
|
|
static const int kNumIters = 20000;
|
|
// check that all the values stored in A objects are correct after this
|
|
// number of iterations
|
|
static const int kCheckPeriod = 500;
|
|
|
|
SkRandom r;
|
|
for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) {
|
|
A::SetAllocator(gSizes[s][0], gSizes[s][1]);
|
|
for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) {
|
|
SkTDArray<Rec> instanceRecs;
|
|
for (int i = 0; i < kNumIters; ++i) {
|
|
float createOrDestroy = r.nextUScalar1();
|
|
if (createOrDestroy < gCreateFraction[c] ||
|
|
0 == instanceRecs.count()) {
|
|
Rec* rec = instanceRecs.append();
|
|
rec->fInstance = A::Create(&r);
|
|
rec->fValue = static_cast<int>(r.nextU());
|
|
rec->fInstance->setValues(rec->fValue);
|
|
} else {
|
|
int d = r.nextRangeU(0, instanceRecs.count() - 1);
|
|
Rec& rec = instanceRecs[d];
|
|
REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
|
|
delete rec.fInstance;
|
|
instanceRecs.removeShuffle(d);
|
|
}
|
|
if (0 == i % kCheckPeriod) {
|
|
for (int r = 0; r < instanceRecs.count(); ++r) {
|
|
Rec& rec = instanceRecs[r];
|
|
REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < instanceRecs.count(); ++i) {
|
|
Rec& rec = instanceRecs[i];
|
|
REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
|
|
delete rec.fInstance;
|
|
}
|
|
#if SK_ENABLE_INST_COUNT
|
|
REPORTER_ASSERT(reporter, !A::GetInstanceCount());
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|