blob: 627f40974461895cab376a1b6f9fd058eee977ad [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, uint32_t 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, uint32_t numPassingAllocs);
~DeterministicFailAllocator(void);
void reset(Mode mode, uint32_t 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;
uint32_t m_numPassingAllocs;
volatile uint32_t 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,
uint32_t allowedLiveAllocScopeBits);
bool validateAndLog(tcu::TestLog &log, const AllocationCallbackRecorder &recorder, uint32_t 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);
} // namespace vk
#endif // _VKALLOCATIONCALLBACKUTIL_HPP