reinstate aligned_allocator.h (required at work)
further fixes to preserve the last error while building error messages somewhat more accurate NUMA factor computation This was SVN commit r9545.
This commit is contained in:
parent
d7f4935dce
commit
f1a1f023df
147
source/lib/allocators/aligned_allocator.h
Normal file
147
source/lib/allocators/aligned_allocator.h
Normal file
@ -0,0 +1,147 @@
|
||||
/* Copyright (c) 2010 Wildfire Games
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* STL allocator for aligned memory
|
||||
*/
|
||||
|
||||
#ifndef ALIGNED_ALLOCATOR
|
||||
#define ALIGNED_ALLOCATOR
|
||||
|
||||
#include "lib/bits.h" // round_up
|
||||
#include "lib/sysdep/arch/x86_x64/cache.h"
|
||||
#include "lib/sysdep/rtl.h" // rtl_AllocateAligned
|
||||
|
||||
|
||||
/**
|
||||
* stateless STL allocator that aligns elements to the L1 cache line size.
|
||||
*
|
||||
* note: the alignment is hard-coded to avoid any allocator state.
|
||||
* this avoids portability problems, which is important since allocators
|
||||
* are rather poorly specified.
|
||||
*
|
||||
* references:
|
||||
* http://www.tantalon.com/pete/customallocators.ppt
|
||||
* http://www.flipcode.com/archives/Aligned_Block_Allocation.shtml
|
||||
* http://www.josuttis.com/cppcode/allocator.html
|
||||
*
|
||||
* derived from code that bears the following copyright notice:
|
||||
* (C) Copyright Nicolai M. Josuttis 1999.
|
||||
* Permission to copy, use, modify, sell and distribute this software
|
||||
* is granted provided this copyright notice appears in all copies.
|
||||
* This software is provided "as is" without express or implied
|
||||
* warranty, and with no claim as to its suitability for any purpose.
|
||||
**/
|
||||
template<class T>
|
||||
class AlignedAllocator
|
||||
{
|
||||
public:
|
||||
// type definitions
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
// rebind allocator to type U
|
||||
template <class U>
|
||||
struct rebind
|
||||
{
|
||||
typedef AlignedAllocator<U> other;
|
||||
};
|
||||
|
||||
pointer address(reference value) const
|
||||
{
|
||||
return &value;
|
||||
}
|
||||
|
||||
const_pointer address(const_reference value) const
|
||||
{
|
||||
return &value;
|
||||
}
|
||||
|
||||
AlignedAllocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
AlignedAllocator(const AlignedAllocator&) throw()
|
||||
{
|
||||
}
|
||||
|
||||
template <class U>
|
||||
AlignedAllocator (const AlignedAllocator<U>&) throw()
|
||||
{
|
||||
}
|
||||
|
||||
~AlignedAllocator() throw()
|
||||
{
|
||||
}
|
||||
|
||||
size_type max_size() const throw()
|
||||
{
|
||||
// maximum number of *elements* that can be allocated
|
||||
return std::numeric_limits<std::size_t>::max() / sizeof(T);
|
||||
}
|
||||
|
||||
// allocate uninitialized storage
|
||||
pointer allocate(size_type numElements)
|
||||
{
|
||||
const size_type alignment = x86_x64_Caches(L1D)->entrySize;
|
||||
const size_type elementSize = round_up(sizeof(T), alignment);
|
||||
const size_type size = numElements * elementSize;
|
||||
pointer p = (pointer)rtl_AllocateAligned(size, alignment);
|
||||
return p;
|
||||
}
|
||||
|
||||
// deallocate storage of elements that have been destroyed
|
||||
void deallocate(pointer p, size_type UNUSED(num))
|
||||
{
|
||||
rtl_FreeAligned((void*)p);
|
||||
}
|
||||
|
||||
void construct(pointer p, const T& value)
|
||||
{
|
||||
new((void*)p) T(value);
|
||||
}
|
||||
|
||||
void destroy(pointer p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
};
|
||||
|
||||
// indicate that all specializations of this allocator are interchangeable
|
||||
template <class T1, class T2>
|
||||
bool operator==(const AlignedAllocator<T1>&, const AlignedAllocator<T2>&) throw()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
bool operator!=(const AlignedAllocator<T1>&, const AlignedAllocator<T2>&) throw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // #ifndef ALIGNED_ALLOCATOR
|
@ -264,6 +264,15 @@ const wchar_t* debug_BuildErrorMessage(
|
||||
void* context, const wchar_t* lastFuncToSkip,
|
||||
ErrorMessageMem* emm)
|
||||
{
|
||||
// retrieve errno (might be relevant) before doing anything else
|
||||
// that might overwrite it.
|
||||
wchar_t description_buf[100] = L"?";
|
||||
wchar_t os_error[100] = L"?";
|
||||
Status errno_equiv = StatusFromErrno(); // NOWARN
|
||||
if(errno_equiv != ERR::FAIL) // meaningful translation
|
||||
StatusDescription(errno_equiv, description_buf, ARRAY_SIZE(description_buf));
|
||||
sys_StatusDescription(0, os_error, ARRAY_SIZE(os_error));
|
||||
|
||||
// rationale: see ErrorMessageMem
|
||||
emm->pa_mem = page_aligned_alloc(messageSize);
|
||||
wchar_t* const buf = (wchar_t*)emm->pa_mem;
|
||||
@ -298,10 +307,10 @@ fail:
|
||||
}
|
||||
else if(ret != INFO::OK)
|
||||
{
|
||||
wchar_t description_buf[100] = {'?'};
|
||||
wchar_t error_buf[100] = {'?'};
|
||||
if(!writer(
|
||||
L"(error while dumping stack: %ls)",
|
||||
StatusDescription(ret, description_buf, ARRAY_SIZE(description_buf))
|
||||
StatusDescription(ret, error_buf, ARRAY_SIZE(error_buf))
|
||||
))
|
||||
goto fail;
|
||||
}
|
||||
@ -310,14 +319,7 @@ fail:
|
||||
writer.CountAddedChars();
|
||||
}
|
||||
|
||||
// append OS error (just in case it happens to be relevant -
|
||||
// it's usually still set from unrelated operations)
|
||||
wchar_t description_buf[100] = L"?";
|
||||
Status errno_equiv = StatusFromErrno(); // NOWARN
|
||||
if(errno_equiv != ERR::FAIL) // meaningful translation
|
||||
StatusDescription(errno_equiv, description_buf, ARRAY_SIZE(description_buf));
|
||||
wchar_t os_error[100] = L"?";
|
||||
sys_StatusDescription(0, os_error, ARRAY_SIZE(os_error));
|
||||
// append errno
|
||||
if(!writer(
|
||||
L"\r\n"
|
||||
L"errno = %d (%ls)\r\n"
|
||||
|
@ -105,8 +105,7 @@ int ErrnoFromStatus(Status status)
|
||||
Status StatusFromErrno()
|
||||
{
|
||||
if(errno == 0)
|
||||
return ERR::FAIL;
|
||||
|
||||
return INFO::OK;
|
||||
const StatusDefinition* def = DefinitionFromErrno(errno);
|
||||
return def? def->status : ERR::FAIL;
|
||||
}
|
||||
@ -118,7 +117,7 @@ static const StatusDefinition statusDefs[] = {
|
||||
|
||||
// INFO::OK doesn't really need a string because calling StatusDescription(0)
|
||||
// should never happen, but we'll play it safe.
|
||||
{ INFO::OK, L"(but return value was 0 which indicates success)" },
|
||||
{ INFO::OK, L"No error reported here" },
|
||||
{ ERR::FAIL, L"Function failed (no details available)" },
|
||||
|
||||
{ INFO::CONTINUE, L"Continue (not an error)" },
|
||||
@ -176,4 +175,4 @@ static const StatusDefinition statusDefs[] = {
|
||||
{ ERR::_29, L"Case 29" }
|
||||
|
||||
};
|
||||
STATUS_ADD_DEFINITIONS(statusDefs)
|
||||
STATUS_ADD_DEFINITIONS(statusDefs);
|
||||
|
@ -213,7 +213,7 @@ LIB_API StatusDefinitionBucket* StatusAddDefinitions(StatusDefinitionBucket* buc
|
||||
* typically invoked at file scope.
|
||||
* @param definitions name (identifier) of the array
|
||||
**/
|
||||
#define STATUS_ADD_DEFINITIONS(definitions) static StatusDefinitionBucket definitions##_bucket = { definitions, ARRAY_SIZE(definitions), StatusAddDefinitions(&definitions##_bucket) };
|
||||
#define STATUS_ADD_DEFINITIONS(definitions) static StatusDefinitionBucket definitions##_bucket = { definitions, ARRAY_SIZE(definitions), StatusAddDefinitions(&definitions##_bucket) }
|
||||
|
||||
|
||||
/**
|
||||
|
@ -30,5 +30,5 @@ Status PollCompletionPort(HANDLE hIOCP, DWORD timeout, DWORD& bytesTransferred,
|
||||
const Status ret = StatusFromWin();
|
||||
if(ret == ERR::AGAIN || ret == ERR::ABORTED) // avoid polluting last error
|
||||
SetLastError(0);
|
||||
return StatusFromWin(); // NOWARN (let caller decide what to do)
|
||||
return ret; // NOWARN (let caller decide what to do)
|
||||
}
|
||||
|
@ -401,8 +401,9 @@ static double ReadRelativeDistanceFromSLIT(const SLIT* slit)
|
||||
// memory from each processor.
|
||||
static double MeasureRelativeDistance()
|
||||
{
|
||||
const size_t size = 16*MiB;
|
||||
const size_t size = 32*MiB;
|
||||
void* mem = page_aligned_alloc(size);
|
||||
ASSUME_ALIGNED(mem, pageSize);
|
||||
|
||||
const uintptr_t previousProcessorMask = os_cpu_SetThreadAffinityMask(os_cpu_ProcessorMask());
|
||||
|
||||
@ -446,7 +447,7 @@ static Status InitRelativeDistance()
|
||||
relativeDistance = MeasureRelativeDistance();
|
||||
|
||||
ENSURE(relativeDistance >= 1.0);
|
||||
ENSURE(relativeDistance <= 3.0); // (Microsoft guideline for NUMA systems)
|
||||
ENSURE(relativeDistance <= 4.0);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,8 @@ struct OvlAllocator // POD
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
ENSURE(extant == 0);
|
||||
if(extant != 0)
|
||||
debug_printf(L"waio: OvlAllocator::Shutdown with extant=%d\n", extant);
|
||||
|
||||
InterlockedFlushSList(&freelist);
|
||||
|
||||
|
@ -356,6 +356,10 @@ Status sys_StatusDescription(int user_err, wchar_t* buf, size_t max_chars)
|
||||
if(!charsWritten)
|
||||
WARN_RETURN(ERR::FAIL);
|
||||
ENSURE(charsWritten < max_chars);
|
||||
if(message[charsWritten-1] == '\n')
|
||||
message[charsWritten-1] = '\0';
|
||||
if(message[charsWritten-2] == '\r')
|
||||
message[charsWritten-2] = '\0';
|
||||
}
|
||||
|
||||
const int charsWritten = swprintf_s(buf, max_chars, L"%d (%ls)", err, message);
|
||||
|
Loading…
Reference in New Issue
Block a user