Dean Michael Berris 25d505953a [XRay] Use preallocated memory for XRay profiling
Summary:
This change builds upon D54989, which removes memory allocation from the
critical path of the profiling implementation. This also changes the API
for the profile collection service, to take ownership of the memory and
associated data structures per-thread.

The consolidation of the memory allocation allows us to do two things:

- Limits the amount of memory used by the profiling implementation,
  associating preallocated buffers instead of allocating memory
  on-demand.

- Consolidate the memory initialisation and cleanup by relying on the
  buffer queue's reference counting implementation.

We find a number of places which also display some problematic
behaviour, including:

- Off-by-factor bug in the allocator implementation.

- Unrolling semantics in cases of "memory exhausted" situations, when
  managing the state of the function call trie.

We also add a few test cases which verify our understanding of the
behaviour of the system, with important edge-cases (especially for
memory-exhausted cases) in the segmented array and profile collector
unit tests.

Depends on D54989.

Reviewers: mboerger

Subscribers: dschuff, mgorny, dmgreen, jfb, llvm-commits

Differential Revision: https://reviews.llvm.org/D55249

llvm-svn: 348568
2018-12-07 06:23:06 +00:00

83 lines
2.1 KiB
C++

//===-- allocator_test.cc -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of XRay, a function call tracing system.
//
//===----------------------------------------------------------------------===//
#include "xray_allocator.h"
#include "xray_buffer_queue.h"
#include "gtest/gtest.h"
namespace __xray {
namespace {
struct TestData {
s64 First;
s64 Second;
};
TEST(AllocatorTest, Construction) { Allocator<sizeof(TestData)> A(2 << 11); }
TEST(AllocatorTest, Allocate) {
Allocator<sizeof(TestData)> A(2 << 11);
auto B = A.Allocate();
ASSERT_NE(B.Data, nullptr);
}
TEST(AllocatorTest, OverAllocate) {
Allocator<sizeof(TestData)> A(sizeof(TestData));
auto B1 = A.Allocate();
ASSERT_NE(B1.Data, nullptr);
auto B2 = A.Allocate();
ASSERT_EQ(B2.Data, nullptr);
}
struct OddSizedData {
s64 A;
s32 B;
};
TEST(AllocatorTest, AllocateBoundaries) {
Allocator<sizeof(OddSizedData)> A(GetPageSizeCached());
// Keep allocating until we hit a nullptr block.
unsigned C = 0;
auto Expected =
GetPageSizeCached() / RoundUpTo(sizeof(OddSizedData), kCacheLineSize);
for (auto B = A.Allocate(); B.Data != nullptr; B = A.Allocate(), ++C)
;
ASSERT_EQ(C, Expected);
}
TEST(AllocatorTest, AllocateFromNonOwned) {
bool Success = false;
BufferQueue BQ(GetPageSizeCached(), 10, Success);
ASSERT_TRUE(Success);
BufferQueue::Buffer B;
ASSERT_EQ(BQ.getBuffer(B), BufferQueue::ErrorCode::Ok);
{
Allocator<sizeof(OddSizedData)> A(B.Data, B.Size);
// Keep allocating until we hit a nullptr block.
unsigned C = 0;
auto Expected =
GetPageSizeCached() / RoundUpTo(sizeof(OddSizedData), kCacheLineSize);
for (auto B = A.Allocate(); B.Data != nullptr; B = A.Allocate(), ++C)
;
ASSERT_EQ(C, Expected);
}
ASSERT_EQ(BQ.releaseBuffer(B), BufferQueue::ErrorCode::Ok);
}
} // namespace
} // namespace __xray