#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 #include 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::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 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 liveAllocations; size_t internalAllocationTotal[VK_INTERNAL_ALLOCATION_TYPE_LAST][VK_SYSTEM_ALLOCATION_SCOPE_LAST]; std::vector 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