blob: 5dee0ff8c93b2e04c7c657df8d9a4f198f7c226f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// This file is copied from
// https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/tests/gtest_pod_array.cpp
// and modified by Doris
#include "vec/common/pod_array.h"
#include <gtest/gtest.h>
#include "runtime/primitive_type.h"
#include "vec/common/allocator_fwd.h"
#include "vec/core/field.h"
namespace doris {
TEST(PODArrayTest, PODArrayBasicMove) {
static constexpr size_t initial_bytes = 32;
using Array = vectorized::PODArray<
uint64_t, initial_bytes,
AllocatorWithStackMemory<Allocator<false, false, false, DefaultMemoryAllocator, false>,
initial_bytes>>;
{
Array arr;
Array arr2;
arr2 = std::move(arr);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2 = std::move(arr);
ASSERT_EQ(arr2.size(), 3);
ASSERT_EQ(arr2[0], 1);
ASSERT_EQ(arr2[1], 2);
ASSERT_EQ(arr2[2], 3);
arr = std::move(arr2);
ASSERT_EQ(arr.size(), 3);
ASSERT_EQ(arr[0], 1);
ASSERT_EQ(arr[1], 2);
ASSERT_EQ(arr[2], 3);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
Array arr2;
arr2 = std::move(arr);
ASSERT_EQ(arr2.size(), 5);
ASSERT_EQ(arr2[0], 1);
ASSERT_EQ(arr2[1], 2);
ASSERT_EQ(arr2[2], 3);
ASSERT_EQ(arr2[3], 4);
ASSERT_EQ(arr2[4], 5);
arr = std::move(arr2);
ASSERT_EQ(arr.size(), 5);
ASSERT_EQ(arr[0], 1);
ASSERT_EQ(arr[1], 2);
ASSERT_EQ(arr[2], 3);
ASSERT_EQ(arr[3], 4);
ASSERT_EQ(arr[4], 5);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr2.push_back(7);
arr2 = std::move(arr);
ASSERT_EQ(arr2.size(), 3);
ASSERT_EQ(arr2[0], 1);
ASSERT_EQ(arr2[1], 2);
ASSERT_EQ(arr2[2], 3);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr2.push_back(7);
arr2.push_back(8);
arr = std::move(arr2);
ASSERT_EQ(arr.size(), 5);
ASSERT_EQ(arr[0], 4);
ASSERT_EQ(arr[1], 5);
ASSERT_EQ(arr[2], 6);
ASSERT_EQ(arr[3], 7);
ASSERT_EQ(arr[4], 8);
}
}
TEST(PODArrayTest, PODArrayBasicSwap) {
static constexpr size_t initial_bytes = 32;
using Array = vectorized::PODArray<
uint64_t, initial_bytes,
AllocatorWithStackMemory<Allocator<false, false, false, DefaultMemoryAllocator, false>,
initial_bytes>>;
{
Array arr;
Array arr2;
arr.swap(arr2);
arr2.swap(arr);
}
{
Array arr;
Array arr2;
arr2.push_back(1);
arr2.push_back(2);
arr2.push_back(3);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 3);
ASSERT_TRUE(arr[0] == 1);
ASSERT_TRUE(arr[1] == 2);
ASSERT_TRUE(arr[2] == 3);
ASSERT_TRUE(arr2.empty());
arr.swap(arr2);
ASSERT_TRUE(arr.empty());
ASSERT_TRUE(arr2.size() == 3);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
}
{
Array arr;
Array arr2;
arr2.push_back(1);
arr2.push_back(2);
arr2.push_back(3);
arr2.push_back(4);
arr2.push_back(5);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 5);
ASSERT_TRUE(arr[0] == 1);
ASSERT_TRUE(arr[1] == 2);
ASSERT_TRUE(arr[2] == 3);
ASSERT_TRUE(arr[3] == 4);
ASSERT_TRUE(arr[4] == 5);
ASSERT_TRUE(arr2.empty());
arr.swap(arr2);
ASSERT_TRUE(arr.empty());
ASSERT_TRUE(arr2.size() == 5);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
ASSERT_TRUE(arr2[3] == 4);
ASSERT_TRUE(arr2[4] == 5);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 3);
ASSERT_TRUE(arr[0] == 4);
ASSERT_TRUE(arr[1] == 5);
ASSERT_TRUE(arr[2] == 6);
ASSERT_TRUE(arr2.size() == 3);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 3);
ASSERT_TRUE(arr[0] == 1);
ASSERT_TRUE(arr[1] == 2);
ASSERT_TRUE(arr[2] == 3);
ASSERT_TRUE(arr2.size() == 3);
ASSERT_TRUE(arr2[0] == 4);
ASSERT_TRUE(arr2[1] == 5);
ASSERT_TRUE(arr2[2] == 6);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
Array arr2;
arr2.push_back(3);
arr2.push_back(4);
arr2.push_back(5);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 3);
ASSERT_TRUE(arr[0] == 3);
ASSERT_TRUE(arr[1] == 4);
ASSERT_TRUE(arr[2] == 5);
ASSERT_TRUE(arr2.size() == 2);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 2);
ASSERT_TRUE(arr[0] == 1);
ASSERT_TRUE(arr[1] == 2);
ASSERT_TRUE(arr2.size() == 3);
ASSERT_TRUE(arr2[0] == 3);
ASSERT_TRUE(arr2[1] == 4);
ASSERT_TRUE(arr2[2] == 5);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr2.push_back(7);
arr2.push_back(8);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 5);
ASSERT_TRUE(arr[0] == 4);
ASSERT_TRUE(arr[1] == 5);
ASSERT_TRUE(arr[2] == 6);
ASSERT_TRUE(arr[3] == 7);
ASSERT_TRUE(arr[4] == 8);
ASSERT_TRUE(arr2.size() == 3);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 3);
ASSERT_TRUE(arr[0] == 1);
ASSERT_TRUE(arr[1] == 2);
ASSERT_TRUE(arr[2] == 3);
ASSERT_TRUE(arr2.size() == 5);
ASSERT_TRUE(arr2[0] == 4);
ASSERT_TRUE(arr2[1] == 5);
ASSERT_TRUE(arr2[2] == 6);
ASSERT_TRUE(arr2[3] == 7);
ASSERT_TRUE(arr2[4] == 8);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
Array arr2;
arr2.push_back(6);
arr2.push_back(7);
arr2.push_back(8);
arr2.push_back(9);
arr2.push_back(10);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 5);
ASSERT_TRUE(arr[0] == 6);
ASSERT_TRUE(arr[1] == 7);
ASSERT_TRUE(arr[2] == 8);
ASSERT_TRUE(arr[3] == 9);
ASSERT_TRUE(arr[4] == 10);
ASSERT_TRUE(arr2.size() == 5);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
ASSERT_TRUE(arr2[3] == 4);
ASSERT_TRUE(arr2[4] == 5);
arr.swap(arr2);
ASSERT_TRUE(arr.size() == 5);
ASSERT_TRUE(arr[0] == 1);
ASSERT_TRUE(arr[1] == 2);
ASSERT_TRUE(arr[2] == 3);
ASSERT_TRUE(arr[3] == 4);
ASSERT_TRUE(arr[4] == 5);
ASSERT_TRUE(arr2.size() == 5);
ASSERT_TRUE(arr2[0] == 6);
ASSERT_TRUE(arr2[1] == 7);
ASSERT_TRUE(arr2[2] == 8);
ASSERT_TRUE(arr2[3] == 9);
ASSERT_TRUE(arr2[4] == 10);
}
}
TEST(PODArrayTest, PODArrayBasicSwapMoveConstructor) {
static constexpr size_t initial_bytes = 32;
using Array = vectorized::PODArray<
uint64_t, initial_bytes,
AllocatorWithStackMemory<Allocator<false, false, false, DefaultMemoryAllocator, false>,
initial_bytes>>;
{
Array arr;
Array arr2 {std::move(arr)};
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2 {std::move(arr)};
ASSERT_TRUE(arr.empty()); // NOLINT
ASSERT_TRUE(arr2.size() == 3);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
Array arr2 {std::move(arr)};
ASSERT_TRUE(arr.empty()); // NOLINT
ASSERT_TRUE(arr2.size() == 5);
ASSERT_TRUE(arr2[0] == 1);
ASSERT_TRUE(arr2[1] == 2);
ASSERT_TRUE(arr2[2] == 3);
ASSERT_TRUE(arr2[3] == 4);
ASSERT_TRUE(arr2[4] == 5);
}
}
TEST(PODArrayTest, PODArrayInsert) {
{
std::string str = "test_string_abacaba";
vectorized::PODArray<char> chars;
chars.insert(chars.end(), str.begin(), str.end());
EXPECT_EQ(str, std::string(chars.data(), chars.size()));
std::string insert_in_the_middle = "insert_in_the_middle";
auto pos = str.size() / 2;
str.insert(str.begin() + pos, insert_in_the_middle.begin(), insert_in_the_middle.end());
chars.insert(chars.begin() + pos, insert_in_the_middle.begin(), insert_in_the_middle.end());
EXPECT_EQ(str, std::string(chars.data(), chars.size()));
std::string insert_with_resize;
insert_with_resize.reserve(chars.capacity() * 2);
char cur_char = 'a';
while (insert_with_resize.size() < insert_with_resize.capacity()) {
insert_with_resize += cur_char;
if (cur_char == 'z') {
cur_char = 'a';
} else {
++cur_char;
}
}
str.insert(str.begin(), insert_with_resize.begin(), insert_with_resize.end());
chars.insert(chars.begin(), insert_with_resize.begin(), insert_with_resize.end());
EXPECT_EQ(str, std::string(chars.data(), chars.size()));
}
{
vectorized::PODArray<uint64_t> values;
vectorized::PODArray<uint64_t> values_to_insert;
for (size_t i = 0; i < 120; ++i) {
values.emplace_back(i);
}
values.insert(values.begin() + 1, values_to_insert.begin(), values_to_insert.end());
ASSERT_EQ(values.size(), 120);
values_to_insert.emplace_back(0);
values_to_insert.emplace_back(1);
values.insert(values.begin() + 1, values_to_insert.begin(), values_to_insert.end());
ASSERT_EQ(values.size(), 122);
values_to_insert.clear();
for (size_t i = 0; i < 240; ++i) {
values_to_insert.emplace_back(i);
}
values.insert(values.begin() + 1, values_to_insert.begin(), values_to_insert.end());
ASSERT_EQ(values.size(), 362);
}
}
// TEST(PODArrayTest, PODArrayInsertFromItself)
// {
// {
// vectorized::PaddedPODArray<UInt64> array { 1 };
// for (size_t i = 0; i < 3; ++i)
// array.insertFromItself(array.begin(), array.end());
// vectorized::PaddedPODArray<UInt64> expected {1,1,1,1,1,1,1,1};
// ASSERT_EQ(array,expected);
// }
// }
TEST(PODArrayTest, PODArrayAssign) {
{
vectorized::PaddedPODArray<uint64_t> array;
array.push_back(1);
array.push_back(2);
array.assign({1, 2, 3});
ASSERT_EQ(array.size(), 3);
ASSERT_EQ(array, vectorized::PaddedPODArray<uint64_t>({1, 2, 3}));
}
{
vectorized::PaddedPODArray<uint64_t> array;
array.push_back(1);
array.push_back(2);
array.assign({});
ASSERT_TRUE(array.empty());
}
{
vectorized::PaddedPODArray<uint64_t> array;
array.assign({});
ASSERT_TRUE(array.empty());
}
}
TEST(PODArrayTest, PODNoOverallocation) {
/// Check that PaddedPODArray allocates for smaller number of elements than the power of two due to padding.
/// NOTE: It's Ok to change these numbers if you will modify initial size or padding.
vectorized::PaddedPODArray<char> chars;
std::vector<size_t> capacities;
size_t prev_capacity = 0;
for (size_t i = 0; i < 1000000; ++i) {
chars.emplace_back();
if (chars.capacity() != prev_capacity) {
prev_capacity = chars.capacity();
capacities.emplace_back(prev_capacity);
}
}
EXPECT_EQ(capacities, (std::vector<size_t> {4064, 8160, 16352, 32736, 65504, 131040, 262112,
524256, 1048544}));
}
template <size_t size>
struct ItemWithSize {
char v[size] {};
};
TEST(PODArrayTest, PODInsertElementSizeNotMultipleOfLeftPadding) {
using ItemWith24Size = ItemWithSize<24>;
vectorized::PaddedPODArray<ItemWith24Size> arr1_initially_empty;
size_t items_to_insert_size = 120000;
for (size_t test = 0; test < items_to_insert_size; ++test) {
arr1_initially_empty.emplace_back();
}
EXPECT_EQ(arr1_initially_empty.size(), items_to_insert_size);
vectorized::PaddedPODArray<ItemWith24Size> arr2_initially_nonempty;
for (size_t test = 0; test < items_to_insert_size; ++test) {
arr2_initially_nonempty.emplace_back();
}
EXPECT_EQ(arr1_initially_empty.size(), items_to_insert_size);
}
TEST(PODArrayTest, PODErase) {
{
vectorized::PaddedPODArray<uint64_t> items {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vectorized::PaddedPODArray<uint64_t> expected;
expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
items.erase(items.begin(), items.begin());
EXPECT_EQ(items, expected);
items.erase(items.end(), items.end());
EXPECT_EQ(items, expected);
}
{
vectorized::PaddedPODArray<uint64_t> actual {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vectorized::PaddedPODArray<uint64_t> expected;
expected = {0, 1, 4, 5, 6, 7, 8, 9};
actual.erase(actual.begin() + 2, actual.begin() + 4);
EXPECT_EQ(actual, expected);
expected = {0, 1, 4};
actual.erase(actual.begin() + 3, actual.end());
EXPECT_EQ(actual, expected);
expected = {};
actual.erase(actual.begin(), actual.end());
EXPECT_EQ(actual, expected);
for (size_t i = 0; i < 10; ++i) {
actual.emplace_back(static_cast<uint64_t>(i));
}
expected = {0, 1, 4, 5, 6, 7, 8, 9};
actual.erase(actual.begin() + 2, actual.begin() + 4);
EXPECT_EQ(actual, expected);
expected = {0, 1, 4};
actual.erase(actual.begin() + 3, actual.end());
EXPECT_EQ(actual, expected);
expected = {};
actual.erase(actual.begin(), actual.end());
EXPECT_EQ(actual, expected);
}
{
vectorized::PaddedPODArray<uint64_t> actual {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vectorized::PaddedPODArray<uint64_t> expected;
expected = {1, 2, 3, 4, 5, 6, 7, 8, 9};
actual.erase(actual.begin());
EXPECT_EQ(actual, expected);
}
}
TEST(PODArrayTest, PaddedPODArrayTrackingMemory) {
auto t = MemTrackerLimiter::create_shared(MemTrackerLimiter::Type::GLOBAL, "UT");
// PaddedPODArray
{
SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(t);
EXPECT_EQ(t->consumption(), 0);
size_t PRE_GROWTH_SIZE = vectorized::TrackingGrowthMinSize;
vectorized::PaddedPODArray<uint64_t, 4096> array;
EXPECT_EQ(t->consumption(), 0);
int64_t mem_consumption = t->consumption();
size_t c_res_mem = 0;
auto tracking_size = [&array, &c_res_mem](size_t c_end_new) {
return (((c_end_new - c_res_mem) >> 16) << 16) + (array.allocated_bytes() >> 3);
};
auto check_memory_growth = [&t, &mem_consumption, &c_res_mem](size_t mem_growth) {
EXPECT_EQ(t->consumption(), mem_consumption + mem_growth)
<< ", current: " << mem_consumption << ", c_res_mem: " << c_res_mem
<< ", mem_growth: " << mem_growth << ", expected: " << t->consumption() << ", "
<< get_stack_trace();
std::cout << "PODArrayTest check_memory, current: " << mem_consumption
<< ", c_res_mem: " << c_res_mem << ", mem_growth: " << mem_growth
<< ", expected: " << t->consumption() << std::endl;
mem_consumption += mem_growth;
c_res_mem += mem_growth;
};
array.push_back(1);
EXPECT_EQ(array.size(), 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 8, c_res_mem: 0, c_end_of_storage: 4064, res_mem_growth: 4064
check_memory_growth(array.allocated_bytes());
array.push_back(2);
EXPECT_EQ(array.size(), 2);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t));
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t));
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 262144, c_res_mem: 4064, c_end_of_storage: 524256, res_mem_growth: 262144
check_memory_growth(tracking_size(PRE_GROWTH_SIZE));
array.push_back(3);
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) + 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.assign({1, 2, 3});
EXPECT_EQ(array.size(), 3);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.resize((PRE_GROWTH_SIZE / sizeof(uint64_t)) * 3);
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 3);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 786432, c_res_mem: 266208, c_end_of_storage: 1048544, res_mem_growth: 589824
check_memory_growth(tracking_size(PRE_GROWTH_SIZE * 3));
array.push_back_without_reserve(11);
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 3 + 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t) * 6, 2);
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 6);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 1572864, c_res_mem: 856032, c_end_of_storage: 2097120, res_mem_growth: 917504
check_memory_growth(tracking_size(PRE_GROWTH_SIZE * 6));
array.push_back_without_reserve(22);
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 6 + 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.emplace_back(33);
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 6 + 2);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.pop_back();
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 6 + 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
for (int i = 0; i < (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 2; i++) {
array.push_back(2);
array.pop_back();
array.pop_back();
}
EXPECT_EQ(array.size(), (PRE_GROWTH_SIZE / sizeof(uint64_t)) * 4 + 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t) * 7, 3);
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 7);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 1835008, c_res_mem: 1773536, c_end_of_storage: 2097120, res_mem_growth: 262144,
check_memory_growth(tracking_size(PRE_GROWTH_SIZE * 7));
{
vectorized::PaddedPODArray<uint64_t, 32> array2;
array2.push_back(3);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 8, c_res_mem: 0, c_end_of_storage: 8, res_mem_growth: 8
EXPECT_EQ(t->consumption(),
mem_consumption + array2.allocated_bytes()); // 40 = array2.allocated_bytes()
array2.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t), 3);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 262144, c_res_mem: 8, c_end_of_storage: 524256, res_mem_growth: 262144
EXPECT_EQ(t->consumption(),
mem_consumption + 40 +
PRE_GROWTH_SIZE); // 40 + PRE_GROWTH_SIZE = array2.c_res_mem
array.insert(array2.begin(), array2.end());
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 2097152, c_res_mem: 2035680, c_end_of_storage: 4194272, res_mem_growth: 524288
EXPECT_EQ(t->consumption(),
mem_consumption + tracking_size(PRE_GROWTH_SIZE * 8) + 40 + PRE_GROWTH_SIZE);
}
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 8);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(tracking_size(PRE_GROWTH_SIZE * 8)); // release array2
{
vectorized::PaddedPODArray<uint64_t, 32> array2;
array2.resize_fill((PRE_GROWTH_SIZE / sizeof(uint64_t)) * 7, 3);
// c_end_new: 1835008, c_res_mem: 0, c_end_of_storage: 2097120, res_mem_growth: 2097120
array.insert_small_allow_read_write_overflow15(array2.begin(), array2.end());
// c_end_new: 3932160, c_res_mem: 2559968, c_end_of_storage: 4194272, res_mem_growth: 1634304
}
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 15);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(
array.allocated_bytes() -
mem_consumption); // array.capacity > tracking_size(PRE_GROWTH_SIZE * 15)
{
vectorized::PaddedPODArray<uint64_t, 32> array2;
array2.push_back(3);
array.insert(array2.begin(), array2.end());
}
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 15 + 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t) * 16, 4);
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 16);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// c_end_new: 4194304, c_res_mem: 4194272, c_end_of_storage: 8388576, res_mem_growth: 1048576
check_memory_growth(tracking_size(PRE_GROWTH_SIZE * 16));
{
vectorized::PaddedPODArray<uint64_t, 32> array2;
array2.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t), 3);
array.insert(array.begin(), array2.begin(), array2.end());
}
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 17);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
{
vectorized::PaddedPODArray<uint64_t, 32> array2;
array2.resize_fill((PRE_GROWTH_SIZE / sizeof(uint64_t) * 2), 3);
array.insert_assume_reserved(array2.begin(), array2.end());
array.insert_assume_reserved_and_allow_overflow(array2.begin(), array2.end());
}
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 21);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(tracking_size(PRE_GROWTH_SIZE * 21));
size_t n = 100;
array.assign(n, (uint64_t)0);
EXPECT_EQ(array.size(), 100);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
array.erase(array.begin() + 10, array.end());
EXPECT_EQ(array.size(), 10);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
check_memory_growth(0);
}
EXPECT_EQ(t->consumption(), 0);
}
TEST(PODArrayTest, PODArrayTrackingMemory) {
auto t = MemTrackerLimiter::create_shared(MemTrackerLimiter::Type::GLOBAL, "UT");
// PODArray with AllocatorWithStackMemory
{
SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(t);
EXPECT_EQ(t->consumption(), 0);
size_t PRE_GROWTH_SIZE = vectorized::TrackingGrowthMinSize;
static constexpr size_t initial_bytes = 32;
using Array =
vectorized::PODArray<uint64_t, initial_bytes,
AllocatorWithStackMemory<Allocator<
false, false, false, DefaultMemoryAllocator, false>>>;
Array array;
array.push_back(1);
EXPECT_EQ(array.size(), 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// reset_resident_memory, c_end_new: 8, c_res_mem: 0, c_end_of_storage: 32, res_mem_growth: 32
EXPECT_EQ(t->consumption(), array.allocated_bytes());
array.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t), 1);
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t));
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// reset_resident_memory, c_end_new: 262144, c_res_mem: 32, c_end_of_storage: 262144, res_mem_growth: 262112
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE);
// test swap
size_t new_capacity = 0;
size_t new_size = 0;
{
Array array2;
array2.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t) * 2, 1);
EXPECT_EQ(array2.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 2);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
// reset_resident_memory, c_end_new: 524288, c_res_mem: 0, c_end_of_storage: 524288, res_mem_growth: 524288
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE * 3);
new_capacity = array2.capacity();
new_size = array2.size();
array.swap(array2);
EXPECT_EQ(array2.size(), PRE_GROWTH_SIZE / sizeof(uint64_t));
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 2);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE * 3);
EXPECT_EQ(array.capacity(), new_capacity);
EXPECT_EQ(array.size(), new_size);
}
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE * 2);
}
EXPECT_EQ(t->consumption(), 0);
// PODArray with Allocator
{
SCOPED_SWITCH_THREAD_MEM_TRACKER_LIMITER(t);
EXPECT_EQ(t->consumption(), 0);
static constexpr size_t PRE_GROWTH_SIZE = (1ULL << 20); // 1M
static constexpr size_t initial_bytes = 32;
using Array =
vectorized::PODArray<uint64_t, initial_bytes,
Allocator<false, false, false, DefaultMemoryAllocator, false>>;
Array array;
array.push_back(1);
EXPECT_EQ(array.size(), 1);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
EXPECT_EQ(t->consumption(), array.allocated_bytes());
array.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t), 1);
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t));
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE);
// test swap
size_t new_capacity = 0;
size_t new_size = 0;
{
Array array2;
array2.resize_fill(PRE_GROWTH_SIZE / sizeof(uint64_t) * 2, 1);
EXPECT_EQ(array2.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 2);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE * 3);
new_capacity = array2.capacity();
new_size = array2.size();
array.swap(array2);
EXPECT_EQ(array2.size(), PRE_GROWTH_SIZE / sizeof(uint64_t));
EXPECT_EQ(array.size(), PRE_GROWTH_SIZE / sizeof(uint64_t) * 2);
doris::thread_context()->thread_mem_tracker_mgr->flush_untracked_mem();
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE * 3);
EXPECT_EQ(array.capacity(), new_capacity);
EXPECT_EQ(array.size(), new_size);
}
EXPECT_EQ(t->consumption(), PRE_GROWTH_SIZE * 2);
}
EXPECT_EQ(t->consumption(), 0);
}
} // end namespace doris