#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 #include #include #include #include #include #include #include #include #include #include namespace vde::core { // ═══════════════════════════════════════════════════════════════════════════ // 任务图并行调度 // ═══════════════════════════════════════════════════════════════════════════ /// 单个任务节点 struct TaskNode { int id = 0; ///< 任务 ID std::string name; ///< 任务名称 std::function func; ///< 任务执行函数 std::vector 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& 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 tasks_; struct Impl; std::unique_ptr impl_; }; /// 便捷函数:直接对任务列表执行并行图调度 /// /// @param tasks 任务图节点列表 /// @param num_threads 线程数(0 = 硬件并发数) /// /// @ingroup core void parallel_task_graph( const std::vector& 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 func, int priority = 0); /// 提交任务并返回 future /// @tparam F 可调用对象类型 /// @tparam Args 参数类型 /// @param f 可调用对象 /// @param args 参数 /// @return 任务的 std::future template auto submit_with_result(F&& f, Args&&... args) -> std::future; /// 等待所有任务完成 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_; }; /// 全局工作窃取调度器 /// /// @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_; }; /// 便捷函数:获取全局内存池 /// /// @return 全局 MemoryPoolIntegration 实例 /// /// @ingroup core [[nodiscard]] inline MemoryPoolIntegration& memory_pool_integration() { return MemoryPoolIntegration::instance(); } // ═══════════════════════════════════════════════════════════════════════════ // 缓存优化提示 // ═══════════════════════════════════════════════════════════════════════════ /// 缓存行大小(典型值为 64 字节) constexpr size_t CACHE_LINE_SIZE = 64; /// 将值对齐到缓存行 template 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 struct CacheAlignedAllocator { using value_type = T; CacheAlignedAllocator() = default; template CacheAlignedAllocator(const CacheAlignedAllocator&) {} [[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(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 value{0}; /// }; /// @endcode template struct PaddedAtomic { std::atomic value{0}; char padding[Alignment - sizeof(std::atomic)]{}; }; static_assert(sizeof(PaddedAtomic) == 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 hot_fields; ///< 热字段列表(应放在前面) std::vector 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& access_records, const std::string& type_name = ""); /// Point3D 的 SoA 布局 struct Point3DSoA { std::vector x; ///< X 坐标数组 std::vector y; ///< Y 坐标数组 std::vector z; ///< Z 坐标数组 /// 从 AoS 转换为 SoA static Point3DSoA from_aos(const std::vector& points); /// 从 SoA 转换为 AoS std::vector to_aos() const; /// 点数 [[nodiscard]] size_t size() const { return x.size(); } /// 清空 void clear() { x.clear(); y.clear(); z.clear(); } }; } // namespace vde::core