4. 性能度量指标

内存,说白了就是整个多媒体管线的「数据粮仓」。视频帧、音频采样、中间缓冲区,全得从这儿过。我见过太多团队把精力全砸在CPU优化上,结果帧率死活上不去——最后发现,是内存把路堵死了。

这一章,咱们就掰开揉碎,看看内存瓶颈到底藏在哪儿。

4.1 内存带宽:被忽视的吞吐天花板

很多人以为内存够大就行。其实,带宽才是多媒体流的命门。你想想看,4K@60fps的视频流,YUV420格式,每秒要搬运的数据量接近1.2GB。这还没算音频、特效、合成。

核心公式:

所需带宽 = 分辨率 × 帧率 × 像素位深 × 读写系数

以4Kp60 10bit HDR为例:3840×2160×60×1.25字节 ≈ 620 MB/s(仅读取)

加上写回、滤镜、缩放,轻松突破 2 GB/s

我在项目中遇到过一台服务器,CPU利用率不到30%,但视频转码就是卡。用perf stat -e memory-bandwidth一查,内存带宽已经跑到95%了。换了两条更高频率的内存条,问题直接解决。

怎么查?

  • Intel PCM(Processor Counter Monitor):pcm-memory.x 直接看带宽利用率
  • AMD uProf:AMDuProfPcm -m memory
  • Linux perf:perf stat -e uncore_imc/data_reads/,uncore_imc/data_writes/

避坑指南:我曾经以为双通道就够用了。结果发现,对于8K解码,四通道内存才能喂饱解码器。别只看内存容量,通道数和频率同样关键。

4.2 缓存命中率:性能的隐形杀手

内存带宽再大,也比L1缓存慢两个数量级。L1访问延迟约1ns,主存呢?100ns起步。所以,缓存命中率直接决定了你的代码是「飞」还是「爬」。

多媒体处理有个特点:数据局部性差。你处理完一帧的左上角,下一帧可能跳到右下角。这会导致缓存频繁失效。

典型场景分析:

访问模式 缓存命中率 性能影响
顺序访问(逐行扫描) ~95% 优秀,硬件预取有效
跨步访问(隔行采样) ~60-80% 中等,需手动预取
随机访问(查表/散列) <30% 灾难,必须重构

我习惯用 perf stat -e cache-misses,cache-references 快速定位。如果cache-misses/cache-references > 10%,就得动手优化了。

注意:别被「高命中率」骗了。有些场景命中率90%,但每次miss都触发一次页错误,那比低命中率还可怕。要结合TLB miss一起看。

优化三板斧:

  1. 数据对齐:结构体按64字节对齐,避免跨缓存行
  2. 分块处理:把大帧切成小块,让数据在L2/L3里完成计算
  3. 软件预取:__builtin_prefetch 提前告诉CPU「下一块数据在这儿」
// 示例:分块处理 + 预取
for (int block_y = 0; block_y < height; block_y += BLOCK_SIZE) {
    for (int block_x = 0; block_x < width; block_x += BLOCK_SIZE) {
        // 预取下一块
        __builtin_prefetch(&frame[block_y + BLOCK_SIZE][block_x], 0, 3);
        process_block(frame, block_x, block_y, BLOCK_SIZE);
    }
}

4.3 内存泄漏:慢性死亡

内存泄漏在多媒体系统里特别隐蔽。为什么?因为视频流是持续的,泄漏一点看不出来。但跑上几个小时,内存占用从200MB涨到8GB,然后OOM killer一刀砍下来——服务挂了。

我遇到过最坑的一次:一个音频重采样库,每次调用都malloc一个临时缓冲区,但只在特定采样率下才会泄漏。测试用例跑的是44.1kHz,没问题;上线跑48kHz,三天后崩溃。

排查工具:

  • Valgrind Memcheck:valgrind --leak-check=full ./your_app,适合开发阶段
  • AddressSanitizer:编译加 -fsanitize=address,性能开销小,适合CI
  • /proc/self/smaps:实时看进程内存分布,grep Pss 看实际物理内存

我的习惯:在关键路径上启用内存池。预分配一大块,自己管理分配释放。既避免泄漏,又减少malloc/free的开销。对于多媒体流处理,这招特别管用。

4.4 大页内存配置:给TLB减负

说到TLB miss,就绕不开大页(Huge Pages)。

默认4KB一页,一个4K视频帧需要约2百万个页表项。TLB就那么几十个条目,根本装不下。每次访问新页都得查页表,性能直接崩。

大页的优势:

页大小 TLB覆盖范围 适用场景
4KB(默认) ~256KB 通用
2MB(HugeTLB) ~128MB 视频帧缓冲区
1GB(HugeTLB) ~64GB GPU显存映射、大模型推理

怎么配?

# 预留2MB大页(例如预留1024个)
echo 1024 > /proc/sys/vm/nr_hugepages

# 或者用1GB大页
echo 4 > /proc/sys/vm/nr_hugepages_mempolicy

# 挂载hugetlbfs
mount -t hugetlbfs hugetlbfs /dev/hugepages

# 程序里用mmap分配大页
void *buf = mmap(NULL, size, PROT_READ | PROT_WRITE,
                 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);

踩坑记录:我曾经在容器里配大页,忘了给cgroup加hugetlb权限。结果程序启动时mmap失败,还没日志。排查了半天才发现是权限问题。记住:容器里用大页,必须显式授权。

另外,透明大页(THP)我建议关掉。它虽然自动,但容易导致内存碎片和延迟抖动。多媒体流对延迟敏感,手动管理大页更靠谱。

# 关闭透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

4.5 知识体系总览

下面这张图,把内存瓶颈的几个维度串起来了。你可以把它当作排查时的检查清单。

内存瓶颈分析知识体系 内存瓶颈分析知识体系 内存瓶颈 内存带宽 缓存命中率 内存泄漏 大页配置 PCM / uProf perf cache-misses Valgrind / ASan HugeTLB / THP 排查建议 1. 先看带宽利用率(硬件计数器) 2. 再看缓存/TLB miss(perf) 3. 最后检查泄漏和大页配置

嗯,内存这块儿,说白了就是「带宽够不够、缓存热不热、泄漏有没有、页表大不大」。把这四个点盯住了,多媒体系统的内存瓶颈基本就无处遁形。