Page 87 - 《软件学报》2026年第6期
P. 87

2406                                                       软件学报  2026  年第  37  卷第  6  期


                 TFLite  的预优化内核能够直接在目标平台上高效执行. 而                TVM  的算子内核由张量表达式自动生成, 并通过
                 schedule_auto_inline 与  loop_tiling  等优化  pass 实现循环分块和寄存器缓存, 但这种依赖运行时调度与反馈的动态
                 优化机制呈现出一定的局限性: 第一, TVM           的  AutoTVM  调优过程依赖于运行时反馈, 而        RISC-V  的静态编译模式
                 无法提供即时反馈, 导致生成的调度策略往往基于默认启发式规则而非平台特性; 第二, TVM                            的  Graph Executor
                 在每次算子调用时需要进行上下文切换和内存重分配, 这在算子粒度较细或低复杂度场景下产生的开销占比可达
                 总执行时间的     20%–30%, 从而抵消了编译优化的收益.
                    然而, TFLite 的预编译策略在内存管理上呈现出明显的资源权衡特征. 热力图显示                      TFLite 的常驻内存占用是
                 TVM  的  1.5–2 倍, 这是因为  TFLite 为实现预编译优化, 在图优化阶段      (tflite::graph_utils::CalculateOptimalAllocation())
                 将所有可能的中间结果和临时缓冲区提前分配并常驻内存. 这种“空间换时间”策略在算子执行时避免了动态分配
                 开销, 但在高复杂度场景下会导致内存峰值激增. 相比之下, TVM                  的  Relay  到  TIR lowering  过程为每个计算阶段
                 生成独立的中间张量, 并通过         StorageRewrite pass 进行按需分配与回收, 在单算子测试中虽然增加了动态分配的
                 系统调用开销, 但有效控制了内存峰值. 这一差异揭示了在                  RISC-V  这种内存受限平台上, 预编译优化与内存效率
                 之间呈现出明显的权衡关系: TFLite 牺牲内存效率以获取执行速度, 适合内存充足的场景; TVM                         牺牲部分执行效
                 率以节省内存, 更适合极端资源受限的嵌入式场景.
                    此外, RIVdoo  还发现  TVM  的缺页率显著高于      TFLite (比值约  0.4–0.5). 这一差异源于两者内存访问模式的不
                 同. TFLite 的实现基于连续内存块, 张量排布规则固定, 从而具备良好的空间局部性和页表友好性. 而 TVM 通过
                 StorageRewrite 与  DoubleBuffer 等  pass 引入动态张量切分和缓存调度, 这种动态调度策略在          x86  等拥有大容量
                 TLB (通常  512–1 024  项) 和多级缓存  (L3  可达数十  MB) 的平台上能够有效提升数据复用率, 但在             RISC-V  平台
                 上对存储层次结构更为敏感. 具体而言, 当前主流               RISC-V  实现的  TLB  容量通常仅为    32–64  项, L2  缓存不超过
                 2 MB, 这使得  TVM  的  StorageRewrite pass 生成的碎片化内存布局无法被有效缓存. 箱形图中缺页率的离群点                (比
                 值约  1.15) 恰好对应于   TVM  在  Softmax、Mean  等归约类算子上的实现, 这些算子需要遍历大规模特征维度,
                 TVM  的  ScheduleOps::ComputeStorageScope() 函数为每个归约维度分配独立的临时缓冲区, 导致内存访问跨度随
                 复杂度呈指数级增长. 在       RISC-V  的简化缓存控制器上, 这种访问模式频繁触发             TLB miss 和  cache miss, 导致缺页
                 率异常上升. 这一发现表明, TVM        的存储调度策略在当前         RISC-V  平台条件下对资源约束较为敏感, 其在此类平
                 台上的行为特征有待进一步分析与优化, 例如通过合并临时缓冲区、限制张量切分粒度等方式减少页表压力.
                    在系统层面, TVM 的     Conv2D  算子的用户态占比普遍高于        TFLite, 其在高复杂度配置下达到        73.3%, 而 TFLite
                 为  59.2%. 这一现象反映出    TVM  内核在算子执行过程中更多依赖用户态计算逻辑, 例如在                  conv2d_nchw_spatial_
                 pack.cc 中通过循环展开与张量重排实现卷积操作, 从而增加了用户态                  CPU 时间. 而  TFLite 在  optimized_ops.h 中
                 直接调用    NEON/Reference 内核, 并通过轻量化的系统调用完成内存访问与调度, 因而表现为更高的系统开销比
                 例. 相对地, Dense 算子则呈现相反趋势: TVM       的系统调用开销在低复杂度下达到            30.2%, 显著高于  TFLite 的  15.6%.
                 这一问题可追溯至       TVM  的动态内存分配逻辑, 特别是在          runtime/module.cc 中频繁触发的小块分配与释放操作,
                 造成系统调用占比较高. 而        TFLite 的  ArenaPlanner 则通过统一的内存池管理机制减少了分配次数, 在一定程度上
                 减少了系统调用次数.
                    此外, RVV  实验揭示了向量化优化在不同算子类型和复杂度层级下的差异化效果. 计算密集型算子                             (Conv2D、
                 MatMul) 在高复杂度下从     RVV  获得  30%–50%  的性能提升, 表明向量化指令在大规模并行计算中能够有效利用
                 RISC-V  的  SIMD  能力. 然而, 箱形图中  CPU  时间的离群点揭示了      RVV  优化的局限性: 部分算子      (如  Div、取模运
                 算) 在启用  RVV  后性能反而下降, 用户态       CPU  占比异常增加    (比值>1.2). 源码分析表明, 这些算子在当前         RISC-V
                 向量扩展规范     (RVV 1.0) 中缺乏专门的硬件加速指令, 编译器被迫通过软件模拟实现向量化除法和取模操作, 引
                 入了额外的循环展开和条件分支, 导致指令数量激增和分支预测失效. 更关键的是, RVV                          向量化在低复杂度场景
                 下的收益被启动开销完全抵消: 向量寄存器的初始化、向量长度配置以及标量-向量数据传输在小规模数据下占
                 据了总执行时间的       30%–40%, 使得向量化反而不如标量实现高效. 此外, 归约类算子                (Mean、Softmax) 在中复杂
                 度下因   RVV  导致缓存失效率上升       (缺页率比值约     1.5–1.8), 这是因为向量化加载指令      (vle) 的内存访问粒度    (通常
   82   83   84   85   86   87   88   89   90   91   92