Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/perfetto/ext/base/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ inline constexpr size_t AlignDown(size_t size, size_t alignment) {
return size & ~(alignment - 1);
}

template <typename T>
inline constexpr bool IsPowerOfTwo(T x) {
static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>,
"T must be an unsigned integer");
return x != 0 && (x & (x - 1)) == 0;
}

// TODO(primiano): clean this up and move all existing usages to the constexpr
// version above.
template <size_t alignment>
Expand Down
15 changes: 15 additions & 0 deletions src/base/utils_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/

#include "perfetto/ext/base/utils.h"
#include <cstdint>
#include <limits>

#include "perfetto/base/build_config.h"

Expand Down Expand Up @@ -193,6 +195,19 @@ TEST(UtilsTest, EintrWrapper) {
}
#endif // LINUX | ANDROID | APPLE

TEST(UtilsTest, IsPowerOfTwo) {
EXPECT_FALSE(IsPowerOfTwo(0u));
EXPECT_TRUE(IsPowerOfTwo(1u));
EXPECT_TRUE(IsPowerOfTwo(2u));
EXPECT_FALSE(IsPowerOfTwo(3u));
EXPECT_TRUE(IsPowerOfTwo(4u));

constexpr uint64_t max_pow2 = static_cast<uint64_t>(1) << 63;
EXPECT_FALSE(IsPowerOfTwo(max_pow2 - 1));
EXPECT_TRUE(IsPowerOfTwo(max_pow2));
EXPECT_FALSE(IsPowerOfTwo(max_pow2 + 1));
}

TEST(UtilsTest, AlignUp) {
EXPECT_EQ(0u, AlignUp<4>(0));
EXPECT_EQ(4u, AlignUp<4>(1));
Expand Down
8 changes: 3 additions & 5 deletions src/profiling/memory/malloc_interceptor_glibc_preload.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <unistd.h>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/heap_profile.h"
#include "src/profiling/memory/wrap_allocators.h"

Expand All @@ -29,10 +30,6 @@ namespace {
uint32_t g_heap_id = AHeapProfile_registerHeap(AHeapInfo_create("libc.malloc"));
#pragma GCC diagnostic pop

bool IsPowerOfTwo(size_t v) {
return (v != 0 && ((v & (v - 1)) == 0));
}

// The code inside the perfetto::profiling::wrap_ functions has been designed to
// avoid calling malloc/free functions, but, in some rare cases, this happens
// anyway inside glibc. The code belows prevents this reentrancy with a thread
Expand Down Expand Up @@ -134,7 +131,8 @@ void* realloc(void* ptr, size_t size) {
}

int posix_memalign(void** memptr, size_t alignment, size_t size) {
if (alignment % sizeof(void*) || !IsPowerOfTwo(alignment / sizeof(void*))) {
if (alignment % sizeof(void*) ||
!perfetto::base::IsPowerOfTwo(alignment / sizeof(void*))) {
return EINVAL;
}

Expand Down
5 changes: 1 addition & 4 deletions src/profiling/memory/scoped_spinlock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,12 @@
#include "perfetto/ext/base/utils.h"

namespace {
constexpr bool IsPowerOfTwo(size_t v) {
return (v != 0 && ((v & (v - 1)) == 0));
}
// Wait for ~1s before timing out (+- spurious wakeups from the sleeps).
constexpr unsigned kSleepAttempts = 1000;
constexpr unsigned kLockAttemptsPerSleep = 1024;
constexpr unsigned kSleepDurationUs = 1000;

static_assert(IsPowerOfTwo(kLockAttemptsPerSleep),
static_assert(perfetto::base::IsPowerOfTwo(kLockAttemptsPerSleep),
"lock attempts of power of 2 produce faster code.");
} // namespace

Expand Down
8 changes: 2 additions & 6 deletions src/profiling/perf/event_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,14 @@ TargetFilter ParseTargetFilter(
return filter;
}

constexpr bool IsPowerOfTwo(size_t v) {
return (v != 0 && ((v & (v - 1)) == 0));
}

// returns |std::nullopt| if the input is invalid.
std::optional<uint32_t> ChooseActualRingBufferPages(uint32_t config_value) {
if (!config_value) {
static_assert(IsPowerOfTwo(kDefaultDataPagesPerRingBuffer));
static_assert(base::IsPowerOfTwo(kDefaultDataPagesPerRingBuffer));
return std::make_optional(kDefaultDataPagesPerRingBuffer);
}

if (!IsPowerOfTwo(config_value)) {
if (!base::IsPowerOfTwo(config_value)) {
PERFETTO_ELOG("kernel buffer size must be a power of two pages");
return std::nullopt;
}
Expand Down
7 changes: 2 additions & 5 deletions src/profiling/perf/event_config_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <optional>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/utils.h"
#include "test/gtest_and_gmock.h"

#include "protos/perfetto/common/perf_events.gen.h"
Expand All @@ -34,10 +35,6 @@ namespace perfetto {
namespace profiling {
namespace {

bool IsPowerOfTwo(size_t v) {
return (v != 0 && ((v & (v - 1)) == 0));
}

std::optional<EventConfig> CreateEventConfig(
const protos::gen::PerfEventConfig& perf_cfg,
const EventConfig::tracepoint_id_fn_t& tracepoint_id_lookup =
Expand All @@ -64,7 +61,7 @@ TEST(EventConfigTest, RingBufferPagesValidated) {

ASSERT_TRUE(event_config.has_value());
ASSERT_GT(event_config->ring_buffer_pages(), 0u);
ASSERT_TRUE(IsPowerOfTwo(event_config->ring_buffer_pages()));
ASSERT_TRUE(base::IsPowerOfTwo(event_config->ring_buffer_pages()));
}
{ // power of two pages accepted
uint32_t num_pages = 128;
Expand Down
8 changes: 2 additions & 6 deletions src/profiling/perf/event_reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ const char* ReadValues(T* out, const char* ptr, size_t num_values) {
return ptr + sz;
}

bool IsPowerOfTwo(size_t v) {
return (v != 0 && ((v & (v - 1)) == 0));
}

static int perf_event_open(perf_event_attr* attr,
pid_t pid,
int cpu,
Expand Down Expand Up @@ -117,7 +113,7 @@ PerfRingBuffer::~PerfRingBuffer() {
std::optional<PerfRingBuffer> PerfRingBuffer::Allocate(int perf_fd,
size_t data_page_count) {
// perf_event_open requires the ring buffer to be a power of two in size.
PERFETTO_DCHECK(IsPowerOfTwo(data_page_count));
PERFETTO_DCHECK(base::IsPowerOfTwo(data_page_count));

PerfRingBuffer ret;

Expand All @@ -139,7 +135,7 @@ std::optional<PerfRingBuffer> PerfRingBuffer::Allocate(int perf_fd,
PERFETTO_CHECK(ret.metadata_page_->data_offset == base::GetSysPageSize());
PERFETTO_CHECK(ret.metadata_page_->data_size == ret.data_buf_sz_);

PERFETTO_DCHECK(IsPowerOfTwo(ret.data_buf_sz_));
PERFETTO_DCHECK(base::IsPowerOfTwo(ret.data_buf_sz_));

return std::make_optional(std::move(ret));
}
Expand Down
9 changes: 1 addition & 8 deletions src/trace_processor/util/symbolizer/local_symbolizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,6 @@ std::optional<BinaryInfo> GetMachOBinaryInfo(char* mem, size_t size) {
return {};
}

template <typename T>
bool IsPowerOfTwo(T x) {
static_assert(std::is_unsigned_v<T> && std::is_integral_v<T>,
"T must be an unsigned integer");
return x != 0 && (x & (x - 1)) == 0;
}

template <typename E>
std::optional<BinaryInfo> ElfToBinaryInfo(char* mem, size_t size) {
std::optional<std::string> build_id = GetElfBuildId<E>(mem, size);
Expand All @@ -294,7 +287,7 @@ std::optional<BinaryInfo> ElfToBinaryInfo(char* mem, size_t size) {
}

// p_align can only be 0, 1 (no alignment requirement) or a power of two.
if (phdr->p_align != 0 && !IsPowerOfTwo(phdr->p_align)) {
if (phdr->p_align != 0 && !base::IsPowerOfTwo(phdr->p_align)) {
PERFETTO_DLOG("Invalid p_aling value: %" PRIu64,
static_cast<uint64_t>(phdr->p_align));
return std::nullopt;
Expand Down
Loading