联芸科技固件研发一面:Cache 命中率怎么统计与调优、RTMO 抓任务时长、合并有序链表去重
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍,并介绍一个印象最深、收获最大的项目。
- Cache 命中率如何判断高低?怎么统计?
- 抓到 Cache miss 之后,具体怎么调优?
- 芯片每个核的 Cache 容量多大?
- 代码里的 volatile 变量,结合 Cache 应该如何优化或规避问题?
- RTMO 抓取任务执行时间,是硬件工具还是软件包?原理是什么?
- 采集到任务运行时长数据之后,如何分析使用?
- 项目日常使用什么调试工具?
- 介绍一下你的课题项目,以及课题相关的问题。
- 投屏笔试:合并两个有序链表并去重,讲讲你的代码思路?如果单个链表内部本身有重复节点怎么处理?
- 研究生专业课主要学哪些内容?
- 说说你的优点和缺点。
《参考解析》
Cache 命中率的统计先分清层级:硬件层面用 PMU 计数器(x86 的 perf stat -e cache-references,cache-misses,L1-dcache-load-misses,ARM 用 perf 或芯片厂商的性能计数器),算 1 - misses/accesses;软件层面靠插桩 + 仿真(QEMU / gem5 / 厂商的 trace 工具)或 RTOS 的任务级 profiling。判断高低要看基线:L1 通常 95% 以上、L2 80%~90%、L3 60% 左右算健康,但更重要的是和「同 workload 的历史值」比,绝对值意义有限。
抓到 miss 之后的调优按数据布局优先:把热点数据改成连续访问(数组代替链表、SoA 代替 AoS)、按 cache line(通常 64B)对齐并避免伪共享(多核写同一 line 的不同字段要 padding)、把大循环分块(blocking / tiling)让工作集塞进 L1、按行优先遍历二维数组、减少指针跳转和虚调用、必要的 prefetch 指令。指令侧看 i-cache:减少大函数内联膨胀、把冷路径移出热函数。
volatile 与 Cache 的关系要说清它不解决什么:volatile 只保证编译器每次都从内存读写、不优化掉访问、不重排同线程内对它的访问,但它不产生内存屏障(跨架构需要 atomic / mb())、也不保证原子性;涉及外设寄存器(MMIO)或 DMA 缓冲区时,还要处理 Cache 一致性——要么把缓冲区放 non-cacheable 区、要么在 DMA 前后做 cache clean / invalidate,否则 CPU 读到的是旧 line。
任务时长采集属于软件插桩(RTMO 这类在任务切换点打时间戳、算差值),和硬件 trace(ETM / 芯片的 instruction trace)是两条路;分析时看最大 / P99 而不是平均值,找长尾任务、看是否被中断或锁抢占打断,再对齐 CPU Load 曲线定位热点。
合并去重这题的关键是「两链表各自也可能有重复」:做法是三指针——a、b 分别遍历,另用一个 tail 维护结果链表,每次取较小者,若与 tail 的最后一个值相同就跳过(这一步同时干掉单链表内部重复),相等时两指针同时前进;任一链表走完后,剩下的继续按「与 tail 不同才接」的规则追加。整体 O(m+n)、O(1) 额外空间。面试官指出漏了内部重复,本质是只考虑了跨链表去重——这是这类题最常见的失分点。