Files
ViewDesignEngine/tests/core/test_performance.cpp
T
茂之钳 921c29cb22
CI / Build & Test (push) Failing after 33s
CI / Release Build (push) Failing after 29s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
feat(v7): B-Rep deep attack + Class-A surfacing + CAM deep + performance tuning
v7.1 — B-Rep 深度攻坚 (对标 Parasolid 95%):
- advanced_healing: auto_heal_pipeline, face_splitting/merging, topology_optimization
- watertight_verification, tolerance_analysis, tolerance diagnostic report
- sheet_metal: unfold_sheet_metal (K-Factor/BFS), bend_deduction_table, create_flange
- direct_modeling enhanced: draft_face_advanced (hinge), scale_body (non-uniform), mirror_body
- 32 tests (17 healing + 15 sheet metal), syntax-check passed

v7.2 — Class-A 曲面攻坚 (对标 CGM 95%):
- class_a_surfacing: g3_blend (4-row CP), curvature_matching (Levenberg-Marquardt)
- highlight_lines, reflection_lines, iso_photes, surface_diagnosis, shape_modification
- advanced_intersection: robust_ssi (3-stage: AABB+subdivision→Newton 1e-12→singularity)
- curve_surface_intersection, self_intersection_detection (BVH)
- 30 tests (18 class-A + 12 intersection), zero compile errors

v7.3 — CAM 深化 + 性能优化:
- cam_advanced: adaptive_clearing, trochoidal_milling, rest_machining, pencil_tracing
- tool_holder_collision_check, toolpath_optimization, feed_rate_optimization
- performance_tuning: parallel_task_graph (DAG+Kahn), work_stealing_scheduler
- memory_pool_integration, cache_optimization_hints, profile_guided_layout
- Fixed BrepModel API compatibility (body.bounds()/to_mesh() instead of .faces())
- 20 tests

12 files, ~5200 lines, 82 tests
2026-07-26 22:54:46 +08:00

261 lines
7.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <gtest/gtest.h>
#include "vde/core/performance_tuning.h"
#include "vde/core/point.h"
#include <vector>
#include <string>
#include <thread>
#include <atomic>
#include <chrono>
using namespace vde::core;
// ===========================================================================
// parallel_task_graph 测试
// ===========================================================================
TEST(PerformanceTuningTest, ParallelTaskGraph_BasicExecution) {
std::atomic<int> counter{0};
std::vector<TaskNode> tasks = {
{0, "task0", [&]{ counter++; }, {}},
{1, "task1", [&]{ counter++; }, {0}}, // 依赖 task0
{2, "task2", [&]{ counter++; }, {0}}, // 依赖 task0
{3, "task3", [&]{ counter++; }, {1,2}}, // 依赖 task1, task2
};
parallel_task_graph(tasks, 2);
EXPECT_EQ(counter.load(), 4);
}
TEST(PerformanceTuningTest, ParallelTaskGraph_DiamondDependency) {
std::vector<int> execution_order;
std::mutex mtx;
auto make_task = [&](int id, std::vector<int> deps) -> TaskNode {
return {id, "task" + std::to_string(id),
[&, id]{
std::lock_guard<std::mutex> lk(mtx);
execution_order.push_back(id);
}, deps};
};
std::vector<TaskNode> tasks = {
make_task(0, {}),
make_task(1, {0}),
make_task(2, {0}),
make_task(3, {1, 2}),
make_task(4, {3}),
};
parallel_task_graph(tasks, 4);
ASSERT_EQ(execution_order.size(), 5u);
// task0 must be first
EXPECT_EQ(execution_order[0], 0);
// task4 must be last
EXPECT_EQ(execution_order[4], 4);
}
TEST(PerformanceTuningTest, ParallelTaskGraph_CycleDetection) {
std::vector<TaskNode> tasks = {
{0, "task0", []{}, {1}}, // 依赖 task1
{1, "task1", []{}, {0}}, // 依赖 task0 → 循环
};
EXPECT_THROW({
parallel_task_graph(tasks, 2);
}, std::runtime_error);
}
TEST(PerformanceTuningTest, ParallelTaskGraph_EmptyTasks) {
std::vector<TaskNode> empty;
EXPECT_NO_THROW(parallel_task_graph(empty, 1));
}
// ===========================================================================
// WorkStealingScheduler 测试
// ===========================================================================
TEST(PerformanceTuningTest, WorkStealingScheduler_BasicSubmit) {
auto& scheduler = work_stealing_scheduler();
std::atomic<int> counter{0};
for (int i = 0; i < 100; ++i) {
scheduler.submit([&]{ counter++; });
}
scheduler.wait_all();
EXPECT_EQ(counter.load(), 100);
}
TEST(PerformanceTuningTest, WorkStealingScheduler_PriorityTasks) {
auto& scheduler = work_stealing_scheduler();
std::vector<int> completion_order;
std::mutex mtx;
// 提交低优先级任务
scheduler.submit([&]{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::lock_guard<std::mutex> lk(mtx);
completion_order.push_back(0);
}, 0);
// 提交高优先级任务(应优先执行)
scheduler.submit([&]{
std::lock_guard<std::mutex> lk(mtx);
completion_order.push_back(1);
}, 10);
scheduler.wait_all();
EXPECT_EQ(completion_order.size(), 2u);
EXPECT_EQ(completion_order[0], 1) << "High priority should complete first";
}
// ===========================================================================
// MemoryPoolIntegration 测试
// ===========================================================================
TEST(PerformanceTuningTest, MemoryPool_AllocateDeallocate) {
auto& pool = memory_pool_integration();
pool.reset();
auto* pt = pool.allocate_point3d();
ASSERT_NE(pt, nullptr);
*pt = Point3D(1, 2, 3);
EXPECT_DOUBLE_EQ(pt->x(), 1.0);
pool.deallocate_point3d(pt);
auto stats = pool.stats();
EXPECT_GT(stats.total_allocations + stats.cache_hits, 0u);
pool.reset();
}
TEST(PerformanceTuningTest, MemoryPool_Reuse) {
auto& pool = memory_pool_integration();
pool.reset();
pool.warm_up(10);
auto* pt1 = pool.allocate_point3d();
auto* pt2 = pool.allocate_point3d();
EXPECT_NE(pt1, pt2) << "Should get different pointers";
pool.deallocate_point3d(pt1);
pool.deallocate_point3d(pt2);
auto* pt3 = pool.allocate_point3d();
// pt3 很可能来自池(pt1 或 pt2
EXPECT_TRUE(pt3 == pt1 || pt3 == pt2) << "Should reuse from pool";
pool.reset();
}
TEST(PerformanceTuningTest, MemoryPool_GenericAllocate) {
auto& pool = memory_pool_integration();
pool.reset();
pool.set_pool_size(64);
void* buf = pool.allocate(128);
ASSERT_NE(buf, nullptr);
pool.deallocate(buf, 128);
auto stats = pool.stats();
EXPECT_GE(stats.total_allocations, 1u);
pool.reset();
}
// ===========================================================================
// cache_optimization_hints 测试
// ===========================================================================
TEST(PerformanceTuningTest, CacheOptimizationHints_ReturnsValid) {
auto hints = cache_optimization_hints();
EXPECT_GT(hints.l1_cache_size, 0u);
EXPECT_GT(hints.l2_cache_size, 0u);
EXPECT_GT(hints.cache_line_size, 0u);
EXPECT_EQ(hints.cache_line_size, 64u) << "Expected 64-byte cache line";
EXPECT_GE(hints.numa_node_count, 1);
}
TEST(PerformanceTuningTest, Prefetch_Compiles) {
int value = 42;
// 预取不应崩溃
EXPECT_NO_THROW(prefetch(&value));
EXPECT_NO_THROW(prefetch_write(&value));
}
TEST(PerformanceTuningTest, PaddedAtomic_Alignment) {
PaddedAtomic<> padded;
padded.value = 42;
EXPECT_EQ(padded.value.load(), 42);
// 验证对齐
EXPECT_EQ(sizeof(padded), CACHE_LINE_SIZE);
EXPECT_EQ(alignof(decltype(padded)), CACHE_LINE_SIZE);
}
// ===========================================================================
// profile_guided_layout 测试
// ===========================================================================
TEST(PerformanceTuningTest, ProfileGuidedLayout_HotColdSplit) {
std::vector<AccessRecord> records = {
{"field_a", 1000, 50, 0.0},
{"field_b", 100, 5, 0.0},
{"field_c", 10, 1, 0.0},
};
auto plan = profile_guided_layout(records, "TestStruct");
EXPECT_GT(plan.hot_fields.size(), 0u);
EXPECT_GT(plan.cold_fields.size(), 0u);
EXPECT_GT(plan.estimated_improvement, 0.0)
<< "Should estimate performance improvement";
}
TEST(PerformanceTuningTest, ProfileGuidedLayout_EmptyRecords) {
std::vector<AccessRecord> empty;
auto plan = profile_guided_layout(empty, "Empty");
EXPECT_EQ(plan.hot_fields.size(), 0u);
EXPECT_EQ(plan.cold_fields.size(), 0u);
}
// ===========================================================================
// Point3DSoA 测试
// ===========================================================================
TEST(PerformanceTuningTest, Point3DSoA_ConversionRoundtrip) {
std::vector<Point3D> original = {
Point3D(1, 2, 3),
Point3D(4, 5, 6),
Point3D(7, 8, 9),
Point3D(10, 11, 12),
};
auto soa = Point3DSoA::from_aos(original);
EXPECT_EQ(soa.size(), 4u);
EXPECT_DOUBLE_EQ(soa.x[0], 1.0);
EXPECT_DOUBLE_EQ(soa.y[1], 5.0);
EXPECT_DOUBLE_EQ(soa.z[2], 9.0);
auto restored = soa.to_aos();
EXPECT_EQ(restored.size(), 4u);
for (size_t i = 0; i < original.size(); ++i) {
EXPECT_DOUBLE_EQ(restored[i].x(), original[i].x());
EXPECT_DOUBLE_EQ(restored[i].y(), original[i].y());
EXPECT_DOUBLE_EQ(restored[i].z(), original[i].z());
}
}
TEST(PerformanceTuningTest, Point3DSoA_Empty) {
std::vector<Point3D> empty;
auto soa = Point3DSoA::from_aos(empty);
EXPECT_EQ(soa.size(), 0u);
auto restored = soa.to_aos();
EXPECT_EQ(restored.size(), 0u);
}