blob: 5ae46e189a3fe636d9efb03bbd1baed5afc7070f [file] [log] [blame]
#ifndef _VKALLOCATIONCALLBACKUTIL_HPP
#define _VKALLOCATIONCALLBACKUTIL_HPP
/*-------------------------------------------------------------------------
* Vulkan CTS Framework
* --------------------
*
* Copyright (c) 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Memory allocation callback utilities.
*//*--------------------------------------------------------------------*/
#include "vkDefs.hpp"
#include "deAppendList.hpp"
#include <vector>
#include <ostream>
namespace tcu
{
class TestLog;
}
namespace vk
{
class AllocationCallbacks
{
public:
AllocationCallbacks (void);
virtual ~AllocationCallbacks (void);
virtual void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0;
virtual void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope) = 0;
virtual void free (void* mem) = 0;
virtual void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0;
virtual void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope) = 0;
const VkAllocationCallbacks* getCallbacks (void) const { return &m_callbacks; }
private:
const VkAllocationCallbacks m_callbacks;
};
struct AllocationCallbackRecord
{
enum Type
{
TYPE_ALLOCATION = 0, //! Call to pfnAllocation
TYPE_REALLOCATION, //! Call to pfnReallocation
TYPE_FREE, //! Call to pfnFree
TYPE_INTERNAL_ALLOCATION, //! Call to pfnInternalAllocation
TYPE_INTERNAL_FREE, //! Call to pfnInternalFree
TYPE_LAST
};
Type type;
union
{
struct
{
size_t size;
size_t alignment;
VkSystemAllocationScope scope;
void* returnedPtr;
} allocation;
struct
{
void* original;
size_t size;
size_t alignment;
VkSystemAllocationScope scope;
void* returnedPtr;
} reallocation;
struct
{
void* mem;
} free;
// \note Used for both INTERNAL_ALLOCATION and INTERNAL_FREE
struct
{
size_t size;
VkInternalAllocationType type;
VkSystemAllocationScope scope;
} internalAllocation;
} data;
AllocationCallbackRecord (void) : type(TYPE_LAST) {}
static AllocationCallbackRecord allocation (size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr);
static AllocationCallbackRecord reallocation (void* original, size_t size, size_t alignment, VkSystemAllocationScope scope, void* returnedPtr);
static AllocationCallbackRecord free (void* mem);
static AllocationCallbackRecord internalAllocation (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope);
static AllocationCallbackRecord internalFree (size_t size, VkInternalAllocationType type, VkSystemAllocationScope scope);
};
class ChainedAllocator : public AllocationCallbacks
{
public:
ChainedAllocator (const VkAllocationCallbacks* nextAllocator);
~ChainedAllocator (void);
void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
void free (void* mem);
void notifyInternalAllocation(size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
private:
const VkAllocationCallbacks* m_nextAllocator;
};
class AllocationCallbackRecorder : public ChainedAllocator
{
public:
AllocationCallbackRecorder (const VkAllocationCallbacks* allocator, deUint32 callCountHint = 1024);
~AllocationCallbackRecorder (void);
void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
void free (void* mem);
void notifyInternalAllocation (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
void notifyInternalFree (size_t size, VkInternalAllocationType allocationType, VkSystemAllocationScope allocationScope);
typedef de::AppendList<AllocationCallbackRecord>::const_iterator RecordIterator;
RecordIterator getRecordsBegin (void) const { return m_records.begin(); }
RecordIterator getRecordsEnd (void) const { return m_records.end(); }
std::size_t getNumRecords (void) const { return m_records.size(); }
private:
typedef de::AppendList<AllocationCallbackRecord> Records;
Records m_records;
};
//! Allocator that starts returning null after N allocs
class DeterministicFailAllocator : public ChainedAllocator
{
public:
enum Mode
{
MODE_DO_NOT_COUNT = 0, //!< Do not count allocations, all allocs will succeed
MODE_COUNT_AND_FAIL, //!< Count allocations, fail when reaching alloc N
MODE_LAST
};
DeterministicFailAllocator (const VkAllocationCallbacks* allocator, Mode mode, deUint32 numPassingAllocs);
~DeterministicFailAllocator (void);
void reset (Mode mode, deUint32 numPassingAllocs);
void* allocate (size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
void* reallocate (void* original, size_t size, size_t alignment, VkSystemAllocationScope allocationScope);
private:
Mode m_mode;
deUint32 m_numPassingAllocs;
volatile deUint32 m_allocationNdx;
};
struct AllocationCallbackViolation
{
enum Reason
{
REASON_DOUBLE_FREE = 0,
REASON_FREE_NOT_ALLOCATED_PTR,
REASON_REALLOC_NOT_ALLOCATED_PTR,
REASON_REALLOC_FREED_PTR,
REASON_NEGATIVE_INTERNAL_ALLOCATION_TOTAL,
REASON_INVALID_ALLOCATION_SCOPE,
REASON_INVALID_INTERNAL_ALLOCATION_TYPE,
REASON_INVALID_ALIGNMENT,
REASON_REALLOC_DIFFERENT_ALIGNMENT,
REASON_LAST
};
AllocationCallbackRecord record;
Reason reason;
AllocationCallbackViolation (void)
: reason(REASON_LAST)
{}
AllocationCallbackViolation (const AllocationCallbackRecord& record_, Reason reason_)
: record(record_)
, reason(reason_)
{}
};
struct AllocationCallbackValidationResults
{
std::vector<AllocationCallbackRecord> liveAllocations;
size_t internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST];
std::vector<AllocationCallbackViolation> violations;
AllocationCallbackValidationResults (void);
void clear (void);
};
void validateAllocationCallbacks (const AllocationCallbackRecorder& recorder, AllocationCallbackValidationResults* results);
bool checkAndLog (tcu::TestLog& log, const AllocationCallbackValidationResults& results, deUint32 allowedLiveAllocScopeBits);
bool validateAndLog (tcu::TestLog& log, const AllocationCallbackRecorder& recorder, deUint32 allowedLiveAllocScopeBits);
size_t getLiveSystemAllocationTotal (const AllocationCallbackValidationResults& validationResults);
std::ostream& operator<< (std::ostream& str, const AllocationCallbackRecord& record);
std::ostream& operator<< (std::ostream& str, const AllocationCallbackViolation& violation);
const VkAllocationCallbacks* getSystemAllocator (void);
} // vk
#endif // _VKALLOCATIONCALLBACKUTIL_HPP