5#include <gtest/gtest.h>
33 std::vector<double>
generate_test_data(
size_t size,
double min_val = 0.0,
double max_val = 100.0) {
34 std::vector<double> data;
37 std::random_device rd;
38 std::mt19937 gen(rd());
39 std::uniform_real_distribution<double> dist(min_val, max_val);
41 for (
size_t i = 0; i < size; ++i) {
42 data.push_back(dist(gen));
57 EXPECT_TRUE(queue.
empty());
58 EXPECT_EQ(queue.
size(), 0);
61 for (
int i = 0; i < 10; ++i) {
62 auto result = queue.
push(i);
63 EXPECT_TRUE(result.is_ok()) <<
"Failed to push " << i;
66 EXPECT_FALSE(queue.
empty());
67 EXPECT_EQ(queue.
size(), 10);
70 for (
int i = 0; i < 10; ++i) {
71 auto result = queue.
pop();
72 EXPECT_TRUE(result.is_ok()) <<
"Failed to pop element " << i;
73 EXPECT_EQ(result.value(), i);
76 EXPECT_TRUE(queue.
empty());
77 EXPECT_EQ(queue.
size(), 0);
87 const int num_producers = 4;
88 const int num_consumers = 2;
89 const int items_per_producer = 1000;
91 std::vector<std::thread> producers;
92 std::vector<std::thread> consumers;
93 std::atomic<int> total_consumed{0};
94 std::atomic<bool> producers_done{
false};
97 for (
int p = 0; p < num_producers; ++p) {
98 producers.emplace_back([&queue, p]() {
99 for (
int i = 0; i < 1000; ++i) {
100 int value = p * 1000 + i;
101 auto result = queue.
push(value);
102 while (!result.is_ok() || !result.value()) {
103 std::this_thread::yield();
104 result = queue.
push(value);
111 for (
int c = 0; c < num_consumers; ++c) {
112 consumers.emplace_back([&queue, &total_consumed, &producers_done]() {
113 while (!producers_done.load() || !queue.
empty()) {
114 auto result = queue.
pop();
115 if (result.is_ok()) {
116 total_consumed.fetch_add(1);
118 std::this_thread::yield();
128 producers_done.store(
true);
135 EXPECT_EQ(total_consumed.load(), num_producers * items_per_producer);
136 EXPECT_TRUE(queue.
empty());
143 EXPECT_GT(stats.get_push_success_rate(), 30.0);
146 EXPECT_EQ(stats.pop_successes.load(),
static_cast<size_t>(total_consumed.load()));
153 std::string value =
"test_value";
154 auto result = queue.
push(std::move(value));
155 EXPECT_TRUE(result.is_ok());
156 EXPECT_TRUE(result.value());
157 EXPECT_EQ(queue.
size(), 1);
159 auto pop_result = queue.
pop();
160 EXPECT_TRUE(pop_result.is_ok());
161 EXPECT_EQ(pop_result.value(),
"test_value");
167 EXPECT_TRUE(queue.
empty());
169 auto result = queue.
pop();
170 EXPECT_TRUE(result.is_err());
182 for (
int i = 0; i < 4; ++i) {
183 auto result = queue.
push(i);
184 EXPECT_TRUE(result.is_ok());
185 EXPECT_TRUE(result.value());
189 auto full_result = queue.
push(999);
190 EXPECT_TRUE(full_result.is_ok());
191 EXPECT_FALSE(full_result.value());
199 valid.max_capacity = 64;
200 EXPECT_TRUE(
valid.validate());
229 EXPECT_GT(stats.push_attempts.load(), 0);
230 EXPECT_GT(stats.pop_attempts.load(), 0);
234 EXPECT_EQ(stats.push_attempts.load(), 0);
235 EXPECT_EQ(stats.push_successes.load(), 0);
236 EXPECT_EQ(stats.push_failures.load(), 0);
237 EXPECT_EQ(stats.pop_attempts.load(), 0);
238 EXPECT_EQ(stats.pop_successes.load(), 0);
239 EXPECT_EQ(stats.pop_failures.load(), 0);
242 EXPECT_DOUBLE_EQ(stats.get_push_success_rate(), 100.0);
243 EXPECT_DOUBLE_EQ(stats.get_pop_success_rate(), 100.0);
259 EXPECT_EQ(queue2.
size(), 3);
261 auto pop_result = queue2.
pop();
262 EXPECT_TRUE(pop_result.is_ok());
263 EXPECT_EQ(pop_result.value(), 10);
265 pop_result = queue2.
pop();
266 EXPECT_TRUE(pop_result.is_ok());
267 EXPECT_EQ(pop_result.value(), 20);
269 pop_result = queue2.
pop();
270 EXPECT_TRUE(pop_result.is_ok());
271 EXPECT_EQ(pop_result.value(), 30);
281 EXPECT_NE(queue,
nullptr);
282 EXPECT_TRUE(queue->empty());
283 EXPECT_EQ(queue->capacity(), 32);
299 std::vector<void*> allocated_blocks;
300 for (
int i = 0; i < 32; ++i) {
302 EXPECT_TRUE(result.is_ok()) <<
"Failed to allocate block " << i;
303 allocated_blocks.push_back(result.value());
309 for (
auto* ptr : allocated_blocks) {
311 EXPECT_TRUE(result.is_ok());
317 EXPECT_EQ(stats.total_allocations.load(), 32);
318 EXPECT_EQ(stats.total_deallocations.load(), 32);
319 EXPECT_GT(stats.get_allocation_success_rate(), 99.0);
333 TestObject(
int v,
double d) : value(v), data(d) {}
337 std::vector<TestObject*> objects;
338 for (
int i = 0; i < 50; ++i) {
340 EXPECT_TRUE(result.is_ok()) <<
"Failed to allocate object " << i;
342 auto* obj = result.value();
343 EXPECT_EQ(obj->value, i);
344 EXPECT_DOUBLE_EQ(obj->data, i * 0.5);
346 objects.push_back(obj);
350 for (
auto* obj : objects) {
352 EXPECT_TRUE(result.is_ok());
365 const int num_threads = 8;
366 const int operations_per_thread = 500;
368 std::vector<std::thread> threads;
369 std::atomic<int> successful_operations{0};
371 for (
int t = 0; t < num_threads; ++t) {
372 threads.emplace_back([&pool, &successful_operations, operations_per_thread]() {
373 std::vector<void*> allocated_ptrs;
376 for (
int i = 0; i < operations_per_thread; ++i) {
378 if (result.is_ok()) {
379 allocated_ptrs.push_back(result.value());
384 for (
auto* ptr : allocated_ptrs) {
386 if (result.is_ok()) {
387 successful_operations.fetch_add(1);
393 for (
auto& thread : threads) {
397 EXPECT_GT(successful_operations.load(), num_threads * operations_per_thread * 0.85);
400 EXPECT_GT(stats.get_allocation_success_rate(), 95.0);
408 valid.max_blocks = 256;
409 valid.block_size = 64;
411 EXPECT_TRUE(
valid.validate());
416 EXPECT_FALSE(zero_blocks.
validate());
438 EXPECT_FALSE(zero_align.
validate());
458 std::vector<void*> allocated;
459 for (
int i = 0; i < 4; ++i) {
461 EXPECT_TRUE(result.is_ok());
462 allocated.push_back(result.value());
468 EXPECT_TRUE(fail_result.is_err());
471 for (
auto* ptr : allocated) {
481 EXPECT_TRUE(result.is_err());
488 int foreign_value = 42;
489 auto result = pool.
deallocate(&foreign_value);
490 EXPECT_TRUE(result.is_err());
506 EXPECT_TRUE(result.is_err());
514 std::vector<double> data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0};
517 auto sum_result = aggregator.
sum(data);
518 EXPECT_TRUE(sum_result.is_ok());
519 EXPECT_DOUBLE_EQ(sum_result.value(), 36.0);
522 auto mean_result = aggregator.
mean(data);
523 EXPECT_TRUE(mean_result.is_ok());
524 EXPECT_DOUBLE_EQ(mean_result.value(), 4.5);
527 auto min_result = aggregator.
min(data);
528 EXPECT_TRUE(min_result.is_ok());
529 EXPECT_DOUBLE_EQ(min_result.value(), 1.0);
531 auto max_result = aggregator.
max(data);
532 EXPECT_TRUE(max_result.is_ok());
533 EXPECT_DOUBLE_EQ(max_result.value(), 8.0);
536 auto var_result = aggregator.
variance(data);
537 EXPECT_TRUE(var_result.is_ok());
538 EXPECT_GT(var_result.value(), 0.0);
547 auto data = generate_test_data(10000, 0.0, 100.0);
551 EXPECT_TRUE(summary_result.is_ok());
553 const auto&
summary = summary_result.value();
554 EXPECT_EQ(
summary.count, 10000);
557 EXPECT_LT(
summary.mean, 100.0);
558 EXPECT_GT(
summary.variance, 0.0);
559 EXPECT_GT(
summary.std_dev, 0.0);
560 EXPECT_GE(
summary.min_val, 0.0);
561 EXPECT_LE(
summary.max_val, 100.0);
567 EXPECT_GT(stats.get_simd_utilization(), 0.0);
582 auto large_data = generate_test_data(50000, 0.0, 1000.0);
585 auto start_simd = std::chrono::high_resolution_clock::now();
587 auto end_simd = std::chrono::high_resolution_clock::now();
590 auto start_scalar = std::chrono::high_resolution_clock::now();
592 auto end_scalar = std::chrono::high_resolution_clock::now();
594 EXPECT_TRUE(simd_summary.is_ok());
595 EXPECT_TRUE(scalar_summary.is_ok());
598 const auto& simd_result = simd_summary.value();
599 const auto& scalar_result = scalar_summary.value();
601 EXPECT_NEAR(simd_result.sum, scalar_result.sum, 1e-6);
602 EXPECT_NEAR(simd_result.mean, scalar_result.mean, 1e-6);
603 EXPECT_NEAR(simd_result.min_val, scalar_result.min_val, 1e-6);
604 EXPECT_NEAR(simd_result.max_val, scalar_result.max_val, 1e-6);
606 auto simd_duration = std::chrono::duration_cast<std::chrono::microseconds>(end_simd - start_simd);
607 auto scalar_duration = std::chrono::duration_cast<std::chrono::microseconds>(end_scalar - start_scalar);
610 std::cout <<
"SIMD duration: " << simd_duration.count() <<
" μs" << std::endl;
611 std::cout <<
"Scalar duration: " << scalar_duration.count() <<
" μs" << std::endl;
616 if (simd_duration.count() > scalar_duration.count() * 1.2) {
617 std::cout <<
"[INFO] SIMD slower than scalar - this may be expected in CI/VM environments" << std::endl;
625 std::vector<double> empty_data;
627 auto sum_result = aggregator.
sum(empty_data);
628 EXPECT_TRUE(sum_result.is_err());
630 auto mean_result = aggregator.
mean(empty_data);
631 EXPECT_TRUE(mean_result.is_err());
633 auto min_result = aggregator.
min(empty_data);
634 EXPECT_TRUE(min_result.is_err());
636 auto max_result = aggregator.
max(empty_data);
637 EXPECT_TRUE(max_result.is_err());
639 auto var_result = aggregator.
variance(empty_data);
640 EXPECT_TRUE(var_result.is_err());
643 EXPECT_TRUE(summary_result.is_err());
649 std::vector<double> single = {42.0};
651 auto result = aggregator.
variance(single);
652 EXPECT_TRUE(result.is_ok());
653 EXPECT_DOUBLE_EQ(result.value(), 0.0);
662 auto data = generate_test_data(100, 0.0, 100.0);
664 auto sum_result = aggregator.
sum(data);
665 EXPECT_TRUE(sum_result.is_ok());
667 auto mean_result = aggregator.
mean(data);
668 EXPECT_TRUE(mean_result.is_ok());
672 EXPECT_EQ(stats.simd_operations.load(), 0);
673 EXPECT_GT(stats.scalar_operations.load(), 0);
674 EXPECT_GT(stats.total_elements_processed.load(), 0);
681 EXPECT_TRUE(result.is_ok());
682 EXPECT_TRUE(result.value());
690 valid.alignment = 32;
691 EXPECT_TRUE(
valid.validate());
706 EXPECT_FALSE(zero_align.
validate());
719 EXPECT_FALSE(invalid_queue_config.
validate());
724 EXPECT_TRUE(valid_queue_config.
validate());
729 EXPECT_FALSE(invalid_pool_config.
validate());
735 EXPECT_TRUE(valid_pool_config.
validate());
740 EXPECT_FALSE(invalid_simd_config.
validate());
745 EXPECT_TRUE(valid_simd_config.
validate());
752 EXPECT_NE(queue,
nullptr);
753 EXPECT_TRUE(queue->empty());
757 EXPECT_NE(pool,
nullptr);
758 EXPECT_GT(pool->available_blocks(), 0);
762 EXPECT_NE(aggregator,
nullptr);
765 auto test_result = aggregator->test_simd();
766 EXPECT_TRUE(test_result.is_ok());
767 EXPECT_TRUE(test_result.value());
774 EXPECT_GE(queue_configs.size(), 3);
776 for (
const auto& config : queue_configs) {
777 EXPECT_TRUE(config.validate());
782 EXPECT_GE(pool_configs.size(), 3);
784 for (
const auto& config : pool_configs) {
785 EXPECT_TRUE(config.validate());
790 EXPECT_GE(simd_configs.size(), 3);
792 for (
const auto& config : simd_configs) {
793 EXPECT_TRUE(config.validate());
805 auto test_data = generate_test_data(1000);
807 for (
double value : test_data) {
808 auto result = queue.
push(value);
809 EXPECT_TRUE(result.is_ok());
813 std::vector<double> collected_data;
814 collected_data.reserve(test_data.size());
816 while (!queue.
empty()) {
817 auto result = queue.
pop();
818 if (result.is_ok()) {
819 collected_data.push_back(result.value());
823 EXPECT_EQ(collected_data.size(), test_data.size());
829 const auto& stats =
summary.value();
830 EXPECT_EQ(stats.count, test_data.size());
831 EXPECT_GT(stats.sum, 0.0);
832 EXPECT_GT(stats.mean, 0.0);
839 EXPECT_GT(queue_stats.get_push_success_rate(), 99.0);
840 EXPECT_GT(queue_stats.get_pop_success_rate(), 99.0);
841 EXPECT_GT(pool_stats.get_allocation_success_rate(), 99.0);
842 EXPECT_GT(simd_stats.total_elements_processed.load(), 0);
Test suite for Phase 3 P4: Lock-free data structures integration.
std::vector< double > generate_test_data(size_t size, double min_val=0.0, double max_val=100.0)
Generate test data.
Thread-safe lock-free MPMC (Multiple Producer Multiple Consumer) queue.
const lockfree_queue_statistics & get_statistics() const
Get queue statistics.
size_t size() const
Get current queue size.
common::Result< bool > push(const T &value)
Push an element to the queue.
bool empty() const
Check if the queue is empty.
common::Result< T > pop()
Pop an element from the queue.
void reset_statistics()
Reset statistics.
Thread-safe fixed-size block memory allocator.
common::VoidResult deallocate_object(T *obj)
Destroy and deallocate an object.
const memory_pool_statistics & get_statistics() const
Get pool statistics.
size_t available_blocks() const
Get number of available blocks.
size_t total_blocks() const
Get total number of blocks.
common::Result< void * > allocate()
Allocate a memory block.
common::VoidResult deallocate(void *ptr)
Deallocate a memory block.
common::Result< T * > allocate_object(Args &&... args)
Allocate and construct an object.
SIMD-accelerated statistical aggregator.
common::Result< statistical_summary > compute_summary(const std::vector< double > &data)
Compute full statistical summary.
const simd_aggregator_statistics & get_statistics() const
Get aggregator statistics.
common::Result< double > mean(const std::vector< double > &data)
Calculate mean of elements.
common::Result< bool > test_simd()
Self-test SIMD functionality.
common::Result< double > sum(const std::vector< double > &data)
Calculate sum of elements.
common::Result< double > variance(const std::vector< double > &data)
Calculate variance of elements.
const simd_capabilities & get_capabilities() const
Get SIMD capabilities.
common::Result< double > min(const std::vector< double > &data)
Find minimum value.
common::Result< double > max(const std::vector< double > &data)
Find maximum value.
Lock-free MPMC queue optimized for metric collection pipelines.
Platform-specific aligned memory allocation pool for monitoring objects.
@ summary
Pre-calculated quantiles and count/sum.
std::unique_ptr< simd_aggregator > make_simd_aggregator()
Create a SIMD aggregator with default configuration.
std::unique_ptr< memory_pool > make_memory_pool()
Create a memory pool with default configuration.
std::vector< simd_config > create_default_simd_configs()
Create default SIMD configurations for different use cases.
std::vector< lockfree_queue_config > create_default_queue_configs()
Create default queue configurations for different use cases.
std::vector< memory_pool_config > create_default_pool_configs()
Create default pool configurations for different use cases.
std::unique_ptr< lockfree_queue< T > > make_lockfree_queue()
Create a lock-free queue with default configuration.
SIMD-accelerated metric aggregation (AVX2/NEON auto-detected).
Configuration for lock-free queue.
size_t initial_capacity
Initial capacity of the queue.
size_t max_capacity
Maximum capacity (0 = unlimited)
bool validate() const
Validate configuration.
Configuration for memory pool.
size_t block_size
Size of each block in bytes.
bool use_thread_local_cache
Use thread-local caching.
size_t alignment
Memory alignment (must be power of 2)
size_t max_blocks
Maximum number of blocks (0 = unlimited)
size_t initial_blocks
Initial number of blocks.
bool validate() const
Validate configuration.
Configuration for SIMD aggregator.
bool validate() const
Validate configuration.
bool enable_simd
Enable SIMD acceleration.
size_t alignment
Memory alignment for SIMD operations.
size_t vector_size
SIMD vector width for processing.
TEST_F(OptimizationTest, LockfreeQueueBasicOperations)