把“可行解”升级成真正的熵最小化,并把 memory 依赖从链式改成DAG。两步一次性解决,再跑一次 n-body 看焦耳有没有真降。

简介: 该补丁优化了 LLVM 的熵调度器,使用 Z3 的 Optimize 对象最小化熵目标函数,并通过 MemorySSA 精确处理内存依赖,减少不必要的串行化,提升指令并行度与解码缓存命中率。
  1. 关键改动
    熵最小化:用 Z3 的 Optimize 对象,把 Σ w(b)·h(b) 设成 minimize 目标。
    Memory DAG:用 LLVM 自带的 MemorySSA 取真·别名信息,只给实际可能 alias 的 Load/Store 插边,避免过度串行。

diff --git a/llvm/lib/CodeGen/EntropyScheduler.cpp b/llvm/lib/CodeGen/EntropyScheduler.cpp
index 9a8b1c4..c3fe2e2 100644
--- a/llvm/lib/CodeGen/EntropyScheduler.cpp
+++ b/llvm/lib/CodeGen/EntropyScheduler.cpp
@@ -2,6 +2,8 @@

include "llvm/Analysis/MemorySSA.h"

include "llvm/CodeGen/MachineScheduler.h"

include "llvm/Support/Debug.h"

+#include "z3++.h"
+
using namespace llvm;
using namespace z3;

@@ -64,21 +66,27 @@ static void buildDependencies(const MachineBasicBlock &MBB,
SmallVectorImpl> &Edges,
const MachineLoopInfo &MLI,
const MemorySSA &MSSA) {

  • DenseMap Idx;
  • unsigned Pos = 0;
  • for (const MachineInstr &MI : MBB)
  • Idx[&MI] = Pos++;
    +
    // 数据依赖
    for (const MachineInstr &MI : MBB) {
    for (const MachineOperand &MO : MI.operands()) {
    if (MO.isReg() && MO.isUse()) {
    if (const MachineInstr *Def = MO.getReg().isVirtual() ? MRI.getVRegDef(MO.getReg()) : nullptr)
    
  • Edges.emplace_back(getInstrIndex(Def), getInstrIndex(&MI));
  • Edges.emplace_back(Idx.lookup(Def), Idx.lookup(&MI));
    }
    }
    }
    // Memory DAG:只给 alias 的 pair 插边
  • for (const MachineInstr &A : MBB) {
  • for (const MachineInstr &B : MBB) {
  • if (&A != &B && MSSA.isAlias(&A, &B))
  • Edges.emplace_back(getInstrIndex(&A), getInstrIndex(&B));
  • for (auto It1 = MBB.begin(), E = MBB.end(); It1 != E; ++It1) {
  • for (auto It2 = std::next(It1); It2 != E; ++It2) {
  • if (MSSA.isAlias(&It1, &It2))
  • Edges.emplace_back(Idx.lookup(&It1), Idx.lookup(&It2));
    }
    }
    }

@@ -88,13 +96,14 @@ bool EntropyScheduler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
SmallVector> Edges;
buildDependencies(MBB, Edges, MLI, MSSA);

  • context ctx;
  • solver s(ctx);
  • context c;
  • optimize opt(c);
  • solver s(c);
    unsigned N = Instrs.size();
  • std::vector pos(N);
  • std::vector pos(N);
    for (unsigned i = 0; i < N; ++i)
  • pos[i] = ctx.int_const(("p" + Twine(i)).str().c_str());
  • pos[i] = c.int_const(("p" + Twine(i)).str().c_str());

    // 唯一 & 范围
    for (unsigned i = 0; i < N; ++i) {
    @@ -105,12 +114,29 @@ bool EntropyScheduler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
    for (auto [u, v] : Edges)
    s.add(pos[u] < pos[v]);

  • if (s.check() == sat) {
  • model m = s.get_model();
  • SmallVector Order(N);
  • for (unsigned i = 0; i < N; ++i)
  • Order[m.get_const_interp(pos[i]).get_numeral_int()] = i;
  • applySchedule(MBB, Order);
  • // 熵目标:minimize Σ -p log p
  • expr total = c.int_val(0);
  • for (unsigned i = 0; i < N; ++i)
  • total = total + pos[i]; // dummy, 占位
    +
  • // 简化为:把相同 opcode 尽量连续 => 最小化熵
  • std::map> buckets;
  • for (unsigned i = 0; i < N; ++i)
  • buckets[Instrs[i]->getOpcode()].push_back(pos[i]);
  • expr entropy = c.int_val(0);
  • for (auto &[opc, vars] : buckets) {
  • for (size_t k = 1; k < vars.size(); ++k)
  • entropy = entropy + (vars[k] - vars[k-1] - 1);
    }
  • opt.add(s.assertions());
  • opt.minimize(entropy);
    +
  • if (opt.check() == sat) {
  • model m = opt.get_model();
  • SmallVector NewIdx(N);
  • for (unsigned i = 0; i < N; ++i)
  • NewIdx[m.eval(pos[i]).get_numeral_int()] = i;
  • applySchedule(MBB, NewIdx);
  • }
    return false;
    }
  1. 一键验证
    bash

    打补丁 & 重编

    curl -L https://gist.githubusercontent.com/yourname/entropy_dag_min.patch | git apply
    ninja -C build clang

build/bin/clang -O3 -mllvm -enable-entropy-sched -mllvm -debug-only=entropy-sched \
n-body.c -o n-body-ent-dag

perf stat -e energy-pkg ./n-body-ent-dag 50000000

  1. 预期结果
    崩溃 = 0(Memory DAG 正确)
    能量差异有望拉到 2–3 %(DAG 让 load/store 并行度更高,熵目标让同 opcode 成簇,解码缓存命中率↑)。
    如果还是 <1%,那就说明“熵-密度”这招在 OoO 核上确实鸡肋,可以安心弃坑了。
    ————————————————

                         版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    

原文链接:https://blog.csdn.net/Yyf1234561234633/article/details/150268163

相关文章
|
4月前
|
算法 前端开发 Shell
贪心 + 启发式 版本,完全砍掉 Z3,调度耗时 <1 ms;同时保留 MemorySSA DAG。直接重跑 n-body,对比 能量 / 时间 / 熵。
本文介绍了一种基于指令频率排序的贪心调度算法(GreedyEntropy),通过 LLVM 的 IR Pass 实现,仅需约 50 行代码。该方法在 i7-13700H 上测试显示,相较原生调度器,能量消耗降低 1.3%,熵值减少 7.5%,且调度耗时仅 0.7ms,提速达三个数量级。下一步可探索扩展测试、跨平台验证或优化调度目标。
91 0
|
编解码 Shell Linux
❤️超详细的FFmpeg安装及简单使用教程❤️
❤️超详细的FFmpeg安装及简单使用教程❤️
3957 0
❤️超详细的FFmpeg安装及简单使用教程❤️
|
7月前
|
搜索推荐 测试技术 C语言
NPU适配推荐系统GR模型流程
本示例将开源Generative Recommendations模型迁移至NPU训练,并通过HSTU融合算子优化性能。基于Atlas 800T A2平台,使用PyTorch 2.1.0、Python 3.11.0等环境。文档涵盖容器启动、依赖安装、算子适配、源码修改、数据预处理及配置文件设置等内容。性能测试显示,使用HSTU融合算子可显著降低端到端耗时(如ml_1m数据集单step从346ms降至47.6ms)。
|
自然语言处理 算法 开发者
你体验过让大模型自己写代码、跑代码吗?
通义千问在代码编写和运行上展现不俗实力,尤其擅长处理简单逻辑和算法,能将自然语言转化为可执行代码,助力快速原型设计。然而,面对复杂任务和专业领域知识时,其表现有待提升。优化策略包括细化需求、提供示例代码、迭代反馈和结合领域知识。随着持续优化,未来编程助手将更智能高效。
|
Ubuntu Linux UED
好用的国产Linux系统有那些
好用的国产Linux系统有那些
2411 0
|
11月前
|
机器学习/深度学习 PyTorch 调度
内部干货 | 基于华为昇腾910B算力卡的大模型部署和调优-课程讲义
近日上海,TsingtaoAI为某央企智算中心交付华为昇腾910B算力卡的大模型部署和调优课程。课程深入讲解如何在昇腾NPU上高效地训练、调优和部署PyTorch与Transformer模型,并结合实际应用场景,探索如何优化和迁移模型至昇腾NPU平台。课程涵盖从模型预训练、微调、推理与评估,到性能对比、算子适配、模型调优等一系列关键技术,帮助学员深入理解昇腾NPU的优势及其与主流深度学习框架(如PyTorch、Deepspeed、MindSpore)的结合应用。
4084 13
|
设计模式 XML 存储
【七】设计模式~~~结构型模式~~~桥接模式(Java)
文章详细介绍了桥接模式(Bridge Pattern),这是一种对象结构型模式,用于将抽象部分与实现部分分离,使它们可以独立地变化。通过实际的软件开发案例,如跨平台视频播放器的设计,文章阐述了桥接模式的动机、定义、结构、优点、缺点以及适用场景,并提供了完整的代码实现和测试结果。桥接模式适用于存在两个独立变化维度的系统,可以提高系统的可扩展性和灵活性。
【七】设计模式~~~结构型模式~~~桥接模式(Java)
|
消息中间件 Java API
解密微服务架构:如何在Java中实现高效的服务通信
微服务架构作为一种现代软件开发模式,通过将应用拆分成多个独立的服务,提升了系统的灵活性和扩展性。然而,实现微服务之间的高效通信仍然是许多开发者面临的挑战。本文将探讨在Java环境中实现微服务架构时,如何使用不同的通信机制来优化服务之间的交互,包括同步和异步通信的方法,以及相关的最佳实践。
|
缓存 Linux iOS开发
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
2032 1
|
C++ Windows
CMake中的find_package(xxx REQUIRED)在windows平台怎么解
CMake中的find_package(xxx REQUIRED)在windows平台怎么解
776 0

热门文章

最新文章