Files
ViewDesignEngine/include/vde/core/performance_tuning.h
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

395 lines
14 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.
#pragma once
/**
* @file performance_tuning.h
* @brief 性能调优 — 任务图并行调度、工作窃取、内存池、缓存优化、数据布局
*
* 提供计算密集型任务的系统级性能优化工具:
* - parallel_task_graph — 基于任务依赖图的并行调度
* - work_stealing_scheduler — 工作窃取线程池
* - memory_pool_integration — 全局内存池(减少 malloc 开销)
* - cache_optimization_hints — 缓存对齐/预取提示
* - profile_guided_layout — 基于性能分析的数据布局优化
*
* @ingroup core
*/
#include "vde/core/point.h"
#include "vde/core/aabb.h"
#include <vector>
#include <string>
#include <memory>
#include <functional>
#include <future>
#include <atomic>
#include <mutex>
#include <thread>
#include <unordered_map>
#include <type_traits>
#include <cstddef>
namespace vde::core {
// ═══════════════════════════════════════════════════════════════════════════
// 任务图并行调度
// ═══════════════════════════════════════════════════════════════════════════
/// 单个任务节点
struct TaskNode {
int id = 0; ///< 任务 ID
std::string name; ///< 任务名称
std::function<void()> func; ///< 任务执行函数
std::vector<int> dependencies; ///< 依赖任务 ID 列表
int priority = 0; ///< 优先级(越大越优先)
};
/// 并行任务图 — 基于拓扑排序 + 线程池的 DAG 调度器
///
/// 使用示例:
/// @code
/// ParallelTaskGraph graph(4); // 4 线程
/// graph.add_task({0, "read", []{ read_data(); }, {}});
/// graph.add_task({1, "proc1", []{ proc1(); }, {0}}); // 依赖任务 0
/// graph.add_task({2, "proc2", []{ proc2(); }, {0}}); // 依赖任务 0
/// graph.add_task({3, "merge", []{ merge(); }, {1,2}}); // 依赖 1,2
/// graph.execute();
/// @endcode
class ParallelTaskGraph {
public:
/// 构造函数
/// @param num_threads 线程数(0 = 硬件并发数)
explicit ParallelTaskGraph(int num_threads = 0);
~ParallelTaskGraph();
// 禁止拷贝
ParallelTaskGraph(const ParallelTaskGraph&) = delete;
ParallelTaskGraph& operator=(const ParallelTaskGraph&) = delete;
/// 添加任务节点
void add_task(const TaskNode& task);
/// 批量添加任务
void add_tasks(const std::vector<TaskNode>& tasks);
/// 执行所有任务(拓扑排序 + 并行调度)
/// 如果存在循环依赖,抛出 std::runtime_error
void execute();
/// 重置所有任务(可复用)
void reset();
/// 获取任务数
[[nodiscard]] size_t task_count() const { return tasks_.size(); }
/// 获取线程数
[[nodiscard]] int thread_count() const { return num_threads_; }
private:
int num_threads_;
std::vector<TaskNode> tasks_;
struct Impl;
std::unique_ptr<Impl> impl_;
};
/// 便捷函数:直接对任务列表执行并行图调度
///
/// @param tasks 任务图节点列表
/// @param num_threads 线程数(0 = 硬件并发数)
///
/// @ingroup core
void parallel_task_graph(
const std::vector<TaskNode>& tasks,
int num_threads = 0);
// ═══════════════════════════════════════════════════════════════════════════
// 工作窃取调度器
// ═══════════════════════════════════════════════════════════════════════════
/// 工作窃取调度器 — 线程池从任务队列中窃取工作
///
/// 每个线程维护自己的任务队列,空闲线程从其他线程队列窃取任务。
/// 适用于负载不均的批处理场景(如面片处理、CAD 算法随机化)。
class WorkStealingScheduler {
public:
/// 构造函数
/// @param num_threads 线程数(0 = 硬件并发数)
explicit WorkStealingScheduler(int num_threads = 0);
~WorkStealingScheduler();
// 禁止拷贝
WorkStealingScheduler(const WorkStealingScheduler&) = delete;
WorkStealingScheduler& operator=(const WorkStealingScheduler&) = delete;
/// 提交带优先级的任务
/// @param func 任务函数
/// @param priority 优先级(越大越优先,默认 0)
void submit(std::function<void()> func, int priority = 0);
/// 提交任务并返回 future
/// @tparam F 可调用对象类型
/// @tparam Args 参数类型
/// @param f 可调用对象
/// @param args 参数
/// @return 任务的 std::future
template<typename F, typename... Args>
auto submit_with_result(F&& f, Args&&... args)
-> std::future<decltype(f(args...))>;
/// 等待所有任务完成
void wait_all();
/// 获取活跃线程数
[[nodiscard]] int active_threads() const;
/// 获取队列中待处理任务数
[[nodiscard]] size_t pending_tasks() const;
/// 停止调度器
void shutdown();
private:
int num_threads_;
struct Impl;
std::unique_ptr<Impl> impl_;
};
/// 全局工作窃取调度器
///
/// @return 全局共享的 WorkStealingScheduler 实例
///
/// @ingroup core
[[nodiscard]] WorkStealingScheduler& work_stealing_scheduler();
// ═══════════════════════════════════════════════════════════════════════════
// 全局内存池集成
// ═══════════════════════════════════════════════════════════════════════════
/// 内存池统计数据
struct MemoryPoolStats {
size_t total_allocations = 0; ///< 总分配次数
size_t total_deallocations = 0; ///< 总释放次数
size_t current_bytes = 0; ///< 当前占用字节
size_t peak_bytes = 0; ///< 峰值占用字节
size_t cache_hits = 0; ///< 缓存命中(池中直接分配)
size_t cache_misses = 0; ///< 缓存未命中(需 malloc
};
/// 全局内存池集成
///
/// 单例内存池,为常见大小的 Point3D、Vector3D、AABB 等对象
/// 提供预分配池,减少频繁 malloc/free 的开销。
///
/// 使用方式:
/// @code
/// auto& pool = memory_pool_integration();
/// auto* pt = pool.allocate_point3d();
/// // ... 使用 pt ...
/// pool.deallocate_point3d(pt);
/// @endcode
class MemoryPoolIntegration {
public:
/// 获取单例
[[nodiscard]] static MemoryPoolIntegration& instance();
/// 分配一个 Point3D
[[nodiscard]] Point3D* allocate_point3d();
/// 释放一个 Point3D
void deallocate_point3d(Point3D* p);
/// 分配一个 Vector3D
[[nodiscard]] Vector3D* allocate_vector3d();
/// 释放一个 Vector3D
void deallocate_vector3d(Vector3D* v);
/// 分配指定大小的内存块
[[nodiscard]] void* allocate(size_t bytes);
/// 释放内存块
void deallocate(void* ptr, size_t bytes);
/// 获取统计信息
[[nodiscard]] MemoryPoolStats stats() const;
/// 重置池(释放所有缓存)
void reset();
/// 设置池大小
/// @param pool_size 每种大小的缓存数量
void set_pool_size(size_t pool_size);
/// 预热池(预分配指定数量的对象)
void warm_up(size_t count);
private:
MemoryPoolIntegration();
~MemoryPoolIntegration();
MemoryPoolIntegration(const MemoryPoolIntegration&) = delete;
MemoryPoolIntegration& operator=(const MemoryPoolIntegration&) = delete;
struct Impl;
std::unique_ptr<Impl> impl_;
};
/// 便捷函数:获取全局内存池
///
/// @return 全局 MemoryPoolIntegration 实例
///
/// @ingroup core
[[nodiscard]] inline MemoryPoolIntegration& memory_pool_integration() {
return MemoryPoolIntegration::instance();
}
// ═══════════════════════════════════════════════════════════════════════════
// 缓存优化提示
// ═══════════════════════════════════════════════════════════════════════════
/// 缓存行大小(典型值为 64 字节)
constexpr size_t CACHE_LINE_SIZE = 64;
/// 将值对齐到缓存行
template<typename T>
constexpr size_t cache_aligned_size() {
constexpr size_t s = sizeof(T);
return ((s + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE) * CACHE_LINE_SIZE;
}
/// 缓存对齐分配器
template<typename T>
struct CacheAlignedAllocator {
using value_type = T;
CacheAlignedAllocator() = default;
template<typename U>
CacheAlignedAllocator(const CacheAlignedAllocator<U>&) {}
[[nodiscard]] T* allocate(std::size_t n) {
void* ptr = nullptr;
if (posix_memalign(&ptr, CACHE_LINE_SIZE, n * sizeof(T)) != 0) {
throw std::bad_alloc();
}
return static_cast<T*>(ptr);
}
void deallocate(T* ptr, std::size_t) {
free(ptr);
}
};
/// 缓存优化提示
///
/// 返回当前硬件平台的优化建议:
/// - 缓存行大小
/// - 预取距离(以缓存行为单位的步进距离)
/// - NUMA 节点信息(如果可用)
///
struct CacheOptimizationHints {
size_t l1_cache_size = 32 * 1024; ///< L1 数据缓存大小 (bytes)
size_t l2_cache_size = 256 * 1024; ///< L2 缓存大小 (bytes)
size_t l3_cache_size = 8 * 1024 * 1024; ///< L3 缓存大小 (bytes)
size_t cache_line_size = 64; ///< 缓存行大小 (bytes)
int numa_node_count = 1; ///< NUMA 节点数
bool hyperthreading = true; ///< 是否超线程
};
/// 获取缓存优化提示
///
/// @return 当前硬件平台的缓存优化提示
///
/// @ingroup core
[[nodiscard]] CacheOptimizationHints cache_optimization_hints();
/// 预取内存地址到缓存(编译器提示)
///
/// @param addr 要预取的内存地址
///
/// @ingroup core
inline void prefetch(const void* addr) {
__builtin_prefetch(addr, 0, 3);
}
/// 预取写入(使缓存行进入修改状态)
///
/// @param addr 要预取的内存地址
///
/// @ingroup core
inline void prefetch_write(const void* addr) {
__builtin_prefetch(addr, 1, 3);
}
/// 防止假共享的填充字段
///
/// 用法:将共享原子变量放在填充结构体中
/// @code
/// struct alignas(64) PaddedCounter {
/// std::atomic<int> value{0};
/// };
/// @endcode
template<size_t Alignment = CACHE_LINE_SIZE>
struct PaddedAtomic {
std::atomic<int> value{0};
char padding[Alignment - sizeof(std::atomic<int>)]{};
};
static_assert(sizeof(PaddedAtomic<CACHE_LINE_SIZE>) == CACHE_LINE_SIZE,
"PaddedAtomic must be exactly one cache line");
// ═══════════════════════════════════════════════════════════════════════════
// 数据布局优化 (Profile-Guided Layout)
// ═══════════════════════════════════════════════════════════════════════════
/// 访问频率记录
struct AccessRecord {
std::string field_name; ///< 字段名
size_t access_count = 0; ///< 访问次数
size_t cache_misses = 0; ///< 缓存未命中次数
double hotness = 0.0; ///< 热度(访问/总访问)
};
/// SoA (Structure of Arrays) 布局变换方案
///
/// 将 AoS 布局(结构体数组)转换为 SoA 布局(数组结构体)以改善缓存利用率。
/// 适用场景:遍历大量 Point3D/Vector3D 进行坐标变换、碰撞检测等。
struct SoALayoutPlan {
std::vector<std::string> hot_fields; ///< 热字段列表(应放在前面)
std::vector<std::string> cold_fields; ///< 冷字段列表(可放在后面)
size_t stride_bytes = 0; ///< 行跨距 (bytes)
double estimated_improvement = 0.0; ///< 预估性能提升比例
};
/// 基于性能分析的数据布局优化
///
/// 分析给定类型的访问模式,生成 SoA 布局变换方案。
/// 热字段(频繁访问)放在一起以提高缓存命中率,
/// 冷字段(偶尔访问)分离以减少缓存污染。
///
/// @param access_records 各字段的访问记录
/// @param type_name 类型名称
/// @return SoA 布局变换方案
///
/// @ingroup core
[[nodiscard]] SoALayoutPlan profile_guided_layout(
const std::vector<AccessRecord>& access_records,
const std::string& type_name = "");
/// Point3D 的 SoA 布局
struct Point3DSoA {
std::vector<double> x; ///< X 坐标数组
std::vector<double> y; ///< Y 坐标数组
std::vector<double> z; ///< Z 坐标数组
/// 从 AoS 转换为 SoA
static Point3DSoA from_aos(const std::vector<Point3D>& points);
/// 从 SoA 转换为 AoS
std::vector<Point3D> to_aos() const;
/// 点数
[[nodiscard]] size_t size() const { return x.size(); }
/// 清空
void clear() { x.clear(); y.clear(); z.clear(); }
};
} // namespace vde::core