Commit ae8ef4dd authored by Brian Geffon's avatar Brian Geffon Committed by Commit Bot

base: Add IsAligned helpers to aligned_memory

Add IsAligned and IsPageAligned helpers to the aligned_memory file.
We need these helpers for another CL we're working on and this seems
like the best place for then.

- Add integral and pointer methods for IsAligned, which prefer
compiler builtins if available.
- Add an IsPageAligned which accepts integral or pointer types.
- Improve GetPageSize() on POSIX where it should use sysconf(_SC_PAGESIZE)
  if it's available and cache the value.


Bug:1067833

Change-Id: Ic7198873042c1ca8896b56449774dbf585d3a944
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2136466
Commit-Queue: Brian Geffon <bgeffon@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#756778}
parent f366516f
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "base/base_export.h" #include "base/base_export.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/process/process_metrics.h"
#include "build/build_config.h" #include "build/build_config.h"
#if defined(COMPILER_MSVC) #if defined(COMPILER_MSVC)
...@@ -55,6 +57,32 @@ struct AlignedFreeDeleter { ...@@ -55,6 +57,32 @@ struct AlignedFreeDeleter {
} }
}; };
#ifndef __has_builtin
#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
#endif
inline bool IsAligned(uintptr_t val, size_t alignment) {
// If the compiler supports builtin alignment checks prefer them.
#if __has_builtin(__builtin_is_aligned)
return __builtin_is_aligned(val, alignment);
#else
DCHECK(!((alignment - 1) & alignment))
<< alignment << " is not a power of two";
return (val & (alignment - 1)) == 0;
#endif
}
inline bool IsAligned(void* val, size_t alignment) {
return IsAligned(reinterpret_cast<uintptr_t>(val), alignment);
}
template <typename Type>
inline bool IsPageAligned(Type val) {
static_assert(std::is_integral<Type>::value || std::is_pointer<Type>::value,
"Integral or pointer type required");
return base::IsAligned(val, base::GetPageSize());
}
} // namespace base } // namespace base
#endif // BASE_MEMORY_ALIGNED_MEMORY_H_ #endif // BASE_MEMORY_ALIGNED_MEMORY_H_
...@@ -9,30 +9,27 @@ ...@@ -9,30 +9,27 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ALIGNED(ptr, align) \
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
namespace base { namespace base {
TEST(AlignedMemoryTest, DynamicAllocation) { TEST(AlignedMemoryTest, DynamicAllocation) {
void* p = AlignedAlloc(8, 8); void* p = AlignedAlloc(8, 8);
EXPECT_TRUE(p); EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 8); EXPECT_TRUE(IsAligned(p, 8));
AlignedFree(p); AlignedFree(p);
p = AlignedAlloc(8, 16); p = AlignedAlloc(8, 16);
EXPECT_TRUE(p); EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 16); EXPECT_TRUE(IsAligned(p, 16));
AlignedFree(p); AlignedFree(p);
p = AlignedAlloc(8, 256); p = AlignedAlloc(8, 256);
EXPECT_TRUE(p); EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 256); EXPECT_TRUE(IsAligned(p, 256));
AlignedFree(p); AlignedFree(p);
p = AlignedAlloc(8, 4096); p = AlignedAlloc(8, 4096);
EXPECT_TRUE(p); EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 4096); EXPECT_TRUE(IsAligned(p, 4096));
AlignedFree(p); AlignedFree(p);
} }
...@@ -40,7 +37,44 @@ TEST(AlignedMemoryTest, ScopedDynamicAllocation) { ...@@ -40,7 +37,44 @@ TEST(AlignedMemoryTest, ScopedDynamicAllocation) {
std::unique_ptr<float, AlignedFreeDeleter> p( std::unique_ptr<float, AlignedFreeDeleter> p(
static_cast<float*>(AlignedAlloc(8, 8))); static_cast<float*>(AlignedAlloc(8, 8)));
EXPECT_TRUE(p.get()); EXPECT_TRUE(p.get());
EXPECT_ALIGNED(p.get(), 8); EXPECT_TRUE(IsAligned(p.get(), 8));
}
TEST(AlignedMemoryTest, IsAligned) {
// Check alignment around powers of two.
for (int i = 0; i < 64; ++i) {
const uint64_t n = static_cast<uint64_t>(1) << i;
// Walk back down all lower powers of two checking alignment.
for (int j = i - 1; j >= 0; --j) {
// n is aligned on all powers of two less than or equal to 2^i.
EXPECT_TRUE(IsAligned(n, n >> j))
<< "Expected " << n << " to be " << (n >> j) << " aligned";
// Also, n - 1 should not be aligned on ANY lower power of two except 1
// (but since we're starting from i - 1 we don't test that case here.
EXPECT_FALSE(IsAligned(n - 1, n >> j))
<< "Expected " << (n - 1) << " to NOT be " << (n >> j) << " aligned";
}
}
// And a few hard coded smoke tests for completeness:
EXPECT_TRUE(IsAligned(4, 2));
EXPECT_TRUE(IsAligned(8, 4));
EXPECT_TRUE(IsAligned(8, 2));
EXPECT_TRUE(IsAligned(0x1000, 4 << 10));
EXPECT_TRUE(IsAligned(0x2000, 8 << 10));
EXPECT_TRUE(IsAligned(1, 1));
EXPECT_TRUE(IsAligned(7, 1));
EXPECT_TRUE(IsAligned(reinterpret_cast<void*>(0x1000), 4 << 10));
EXPECT_TRUE(IsAligned(reinterpret_cast<int*>(0x1000), 4 << 10));
EXPECT_FALSE(IsAligned(3, 2));
EXPECT_FALSE(IsAligned(7, 4));
EXPECT_FALSE(IsAligned(7, 2));
EXPECT_FALSE(IsAligned(0x1001, 4 << 10));
EXPECT_FALSE(IsAligned(0x999, 8 << 10));
EXPECT_FALSE(IsAligned(7, 8));
} }
} // namespace base } // namespace base
...@@ -102,7 +102,16 @@ void IncreaseFdLimitTo(unsigned int max_descriptors) { ...@@ -102,7 +102,16 @@ void IncreaseFdLimitTo(unsigned int max_descriptors) {
#endif // !defined(OS_FUCHSIA) #endif // !defined(OS_FUCHSIA)
size_t GetPageSize() { size_t GetPageSize() {
return getpagesize(); static const size_t pagesize = []() -> size_t {
// For more information see getpagesize(2). Portable applications should use
// sysconf(_SC_PAGESIZE) rather than getpagesize() if it's available.
#if defined(_SC_PAGESIZE)
return sysconf(_SC_PAGESIZE);
#else
return getpagesize();
#endif
}();
return pagesize;
} }
size_t ProcessMetrics::GetMallocUsage() { size_t ProcessMetrics::GetMallocUsage() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment