This cl adds an API for getting an aligned pointer from a pointer to memory. Also adds a short-hand for creating scoped pointers of aligned memory.
BUG=N/A Review URL: https://webrtc-codereview.appspot.com/849006 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2851 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -11,15 +11,37 @@
|
||||
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_
|
||||
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_
|
||||
|
||||
// The functions declared here
|
||||
// 1) Allocates block of aligned memory.
|
||||
// 2) Re-calculates a pointer such that it is aligned to a higher or equal
|
||||
// address.
|
||||
// Note: alignment must be a power of two. The alignment is in bytes.
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace webrtc
|
||||
{
|
||||
void* AlignedMalloc(
|
||||
size_t size,
|
||||
size_t alignment);
|
||||
void AlignedFree(
|
||||
void* memBlock);
|
||||
}
|
||||
#include "system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Returns a pointer to the first boundry of |alignment| bytes following the
|
||||
// address of |ptr|.
|
||||
// Note that there is no guarantee that the memory in question is available.
|
||||
// |ptr| has no requirements other than it can't be NULL.
|
||||
void* GetRightAlign(const void* ptr, size_t alignment);
|
||||
|
||||
// Allocates memory of |size| bytes aligned on an |alignment| boundry.
|
||||
// The return value is a pointer to the memory. Note that the memory must
|
||||
// be de-allocated using AlignedFree.
|
||||
void* AlignedMalloc(size_t size, size_t alignment);
|
||||
// De-allocates memory created using the AlignedMalloc() API.
|
||||
void AlignedFree(void* memBlock);
|
||||
|
||||
// Scoped pointer to AlignedMalloc-memory.
|
||||
template<typename T>
|
||||
struct Allocator {
|
||||
typedef scoped_ptr_malloc<T, AlignedFree> scoped_ptr_aligned;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_
|
||||
|
||||
@@ -45,15 +45,43 @@ struct AlignedMemory
|
||||
void* memoryPointer;
|
||||
};
|
||||
|
||||
void* AlignedMalloc(size_t size, size_t alignment)
|
||||
uintptr_t GetRightAlign(uintptr_t startPos, size_t alignment)
|
||||
{
|
||||
if(alignment == 0)
|
||||
// The pointer should be aligned with |alignment| bytes. The - 1 guarantees
|
||||
// that it is aligned towards the closest higher (right) address.
|
||||
return (startPos + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
// Alignment must be an integer power of two.
|
||||
bool ValidAlignment(size_t alignment)
|
||||
{
|
||||
if (!alignment)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (alignment & (alignment - 1)) == 0;
|
||||
}
|
||||
|
||||
void* GetRightAlign(const void* ptr, size_t alignment)
|
||||
{
|
||||
if (!ptr)
|
||||
{
|
||||
// Don't allow alignment 0 since it's undefined.
|
||||
return NULL;
|
||||
}
|
||||
// Make sure that the alignment is an integer power of two or fail.
|
||||
if(alignment & (alignment - 1))
|
||||
if (!ValidAlignment(alignment))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
uintptr_t startPos = reinterpret_cast<uintptr_t> (ptr);
|
||||
return reinterpret_cast<void*> (GetRightAlign(startPos, alignment));
|
||||
}
|
||||
|
||||
void* AlignedMalloc(size_t size, size_t alignment)
|
||||
{
|
||||
if (size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (!ValidAlignment(alignment))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -80,19 +108,14 @@ void* AlignedMalloc(size_t size, size_t alignment)
|
||||
// in the same memory block.
|
||||
uintptr_t alignStartPos = (uintptr_t)returnValue->memoryPointer;
|
||||
alignStartPos += sizeof(uintptr_t);
|
||||
|
||||
// The buffer should be aligned with 'alignment' bytes. The - 1 guarantees
|
||||
// that we align towards the lowest address.
|
||||
uintptr_t alignedPos = (alignStartPos + alignment - 1) & ~(alignment - 1);
|
||||
|
||||
// alignedPos is the address sought for.
|
||||
returnValue->alignedBuffer = (void*)alignedPos;
|
||||
uintptr_t alignedPos = GetRightAlign(alignStartPos, alignment);
|
||||
returnValue->alignedBuffer = reinterpret_cast<void*> (alignedPos);
|
||||
|
||||
// Store the address to the AlignedMemory struct in the header so that a
|
||||
// it's possible to reclaim all memory.
|
||||
uintptr_t headerPos = alignedPos;
|
||||
headerPos -= sizeof(uintptr_t);
|
||||
void* headerPtr = (void*) headerPos;
|
||||
void* headerPtr = reinterpret_cast<void*> (headerPos);
|
||||
uintptr_t headerValue = (uintptr_t)returnValue;
|
||||
memcpy(headerPtr,&headerValue,sizeof(uintptr_t));
|
||||
|
||||
@@ -118,4 +141,4 @@ void AlignedFree(void* memBlock)
|
||||
}
|
||||
delete deleteMemory;
|
||||
}
|
||||
} // namespace webrtc
|
||||
} // namespace webrtc
|
||||
|
||||
77
src/system_wrappers/source/aligned_malloc_unittest.cc
Normal file
77
src/system_wrappers/source/aligned_malloc_unittest.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "system_wrappers/interface/aligned_malloc.h"
|
||||
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "typedefs.h" // NOLINT
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Returns true if |size| and |alignment| are valid combinations.
|
||||
bool CorrectUsage(size_t size, size_t alignment) {
|
||||
webrtc::Allocator<char>::scoped_ptr_aligned scoped(
|
||||
static_cast<char*> (webrtc::AlignedMalloc(size, alignment)));
|
||||
if (scoped.get() == NULL) {
|
||||
return false;
|
||||
}
|
||||
const uintptr_t scoped_address = reinterpret_cast<uintptr_t> (scoped.get());
|
||||
return 0u == scoped_address % alignment;
|
||||
}
|
||||
|
||||
TEST(AlignedMalloc, GetRightAlign) {
|
||||
const size_t size = 100;
|
||||
const size_t alignment = 32;
|
||||
const size_t left_missalignment = 8;
|
||||
webrtc::Allocator<char>::scoped_ptr_aligned scoped(
|
||||
static_cast<char*> (webrtc::AlignedMalloc(size, alignment)));
|
||||
EXPECT_TRUE(scoped.get() != NULL);
|
||||
const uintptr_t aligned_address = reinterpret_cast<uintptr_t> (scoped.get());
|
||||
const uintptr_t missaligned_address = aligned_address - left_missalignment;
|
||||
const void* missaligned_ptr = reinterpret_cast<void*> (missaligned_address);
|
||||
const void* realignedPtr = webrtc::GetRightAlign(
|
||||
missaligned_ptr, alignment);
|
||||
EXPECT_EQ(scoped.get(), realignedPtr);
|
||||
}
|
||||
|
||||
TEST(AlignedMalloc, IncorrectSize) {
|
||||
const size_t incorrect_size = 0;
|
||||
const size_t alignment = 64;
|
||||
EXPECT_FALSE(CorrectUsage(incorrect_size, alignment));
|
||||
}
|
||||
|
||||
TEST(AlignedMalloc, IncorrectAlignment) {
|
||||
const size_t size = 100;
|
||||
const size_t incorrect_alignment = 63;
|
||||
EXPECT_FALSE(CorrectUsage(size, incorrect_alignment));
|
||||
}
|
||||
|
||||
TEST(AlignedMalloc, AlignTo2Bytes) {
|
||||
size_t size = 100;
|
||||
size_t alignment = 2;
|
||||
EXPECT_TRUE(CorrectUsage(size, alignment));
|
||||
}
|
||||
|
||||
TEST(AlignedMalloc, AlignTo32Bytes) {
|
||||
size_t size = 100;
|
||||
size_t alignment = 32;
|
||||
EXPECT_TRUE(CorrectUsage(size, alignment));
|
||||
}
|
||||
|
||||
TEST(AlignedMalloc, AlignTo128Bytes) {
|
||||
size_t size = 100;
|
||||
size_t alignment = 128;
|
||||
EXPECT_TRUE(CorrectUsage(size, alignment));
|
||||
}
|
||||
@@ -202,6 +202,7 @@
|
||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||
],
|
||||
'sources': [
|
||||
'aligned_malloc_unittest.cc',
|
||||
'condition_variable_unittest.cc',
|
||||
'cpu_wrapper_unittest.cc',
|
||||
'cpu_measurement_harness.h',
|
||||
|
||||
Reference in New Issue
Block a user