
搞CPU性能评测的人对SPEC CPU2006这套基准测试套件肯定不陌生。它几乎是行业里跑分对标的标准动作但这也是一块难啃的骨头。安装、编译、运行任何一个环节都能踩坑而我这次遇到的是工具使用阶段的glob报错。这类问题看似不起眼却能直接卡死整个测试流程尤其在做多平台对比、赶评测任务的时候特别耽误事。这篇文章把我这次排查和解决的完整过程整理出来从glob是什么、为什么会报错到怎么定位、怎么彻底修好一次性讲清楚给正在被同样问题折磨的人一个可复现的解决方案。1. 先搞清楚glob到底是什么以及它为什么会出现在SPEC工具链里1.1 glob不是玄学就是文件通配符展开glob这个词其实是从Unix shell里继承下来的一个基础能力。你在终端里敲过ls *.log或者rm -rf tmp/*.o这个*的展开过程就叫glob。它把带有*、?、[]这些特殊符号的路径模式匹配成一组真实存在的文件路径。C语言里对应glob()函数Perl里也有glob()shell则有专门的路径名展开机制。放到SPEC CPU2006的语境里glob就是个“按模式找文件”的机制。它本身不复杂但一旦匹配不到文件、目录路径不对、或者模式里带着空变量就会滋生各种让人摸不着头脑的报错。很多人一看到“glob failed”就慌以为是编译器坏了其实多半是环境问题。1.2 SPEC CPU2006的工具链是怎么运行起来的SPEC CPU2006的测试流程不是你把基准程序编译完直接跑二进制那么简单。它的主入口是runspec脚本这个脚本会做三件事读取配置、编排基准程序、生成运行命令。中间的关键代理是specinvoke——专门负责执行测试程序的工具它会读取一个.cmd格式的命令文件然后根据里面的输入输出文件定义去启动对应的基准测试程序。问题就出在这个.cmd文件上。runspec在调度的时候会把数据文件、输出文件、程序路径用相对或绝对路径写进命令文件里其中大量使用了通配符形式比如input: $SPEC/benchspec/CPU2006/401.bzip2/data/test/input/*.in output: $SPEC/benchspec/CPU2006/401.bzip2/data/test/output/*.outspecinvoke执行时对每一行的输入输出模式都要调用Perl的glob()做文件路径展开。只要模式里有一个目录不存在、一个通配符匹配不到文件、或者$SPEC变量没传入导致路径不完整glob直接返回空结果工具就会报错终止。这就是很多人在运行SPEC CPU2006时遇到glob问题的直接机制。1.3 报错出现的典型位置和含义glob报错在不同环节会以不同面目出现。最常见的是在runspec刚开始调度的时候输出一行类似glob failed: No such file or directory at ./bin/specinvoke line 234.有时候是Perl层的警告Use of uninitialized value in glob at ./bin/specinvoke line 189.如果你刚好用了自定义脚本也可能看到glob() returned empty之类的提示。不管措辞怎么变本质都是在按通配符找文件的过程中环境给的信息不完整或者不符合预期。下面我会按照实际排查的顺序把常见诱因一个个过滤掉。2. 搭建SPEC CPU2006环境时最容易埋下的glob隐患2.1 安装目录和数据文件是第一个检查点很多人装完SPEC CPU2006就直接跑觉得安装时一路yes就完事了。实际上安装过程里最关键的一步是数据文件的展开。SPEC CPU2006的每个基准程序都带有test、train、ref三套数据安装脚本在最后阶段会调用数据解压工具把这些数据展开到各自目录。如果你安装时跳过了、中途中断了或者拿到的介质本身就不完整那后续specinvoke按模式找文件时一个目录是空的glob自然就失败。检查方法很简单进入某个基准程序目录看数据cd $SPEC/benchspec/CPU2006/401.bzip2/data ls test/ ls train/ ls ref/如果某个目录不存在或者目录里有文件但都是0字节基本可以判断数据没展开完整。这个属于最典型的glob问题诱因。2.2 环境变量的坑比数据文件还隐蔽数据文件完整不代表glob就万事大吉。SPEC CPU2006提供了shrc环境脚本安装完成后必须执行source shrc来初始化SPEC、SPEC_CPU、PATH这些变量。很多人直接手动设置PATH或者干脆没source就跑这时候工具脚本里所有依赖$SPEC的位置就都是空的。我之前踩过这样一个坑给某测试平台重新分区后把SPEC目录从/opt/benchspec挪到了/data/spec/spec2006结果忘了重新执行安装脚本只改了PATH。跑runspec的时候specinvoke里的$SPEC还是指向旧路径glob去旧目录展开自然啥也匹配不到报错信息还特别误导人一直提示No such file or directory。这种场景的正确检查方式echo $SPEC echo $SPEC_CPU如果输出为空或者指向不存在的路径先修环境变量。不要直接用export SPEC/xxx去硬顶最稳妥的做法是重新source shrc让脚本自己配置好整套变量。2.3 权限问题和目录结构也会干扰glob读取第三种隐患来自文件权限。SPEC CPU2006的run目录、result目录在运行时会生成大量临时文件如果安装时的属主和当前运行用户不一致或者目录权限是700但工具以另一个用户身份运行glob按模式去读取目录时就会遇到Permission denied。这类报错喜欢伪装成“glob failed: No such file or directory”因为Perl的glob在遇到不可读目录时往往返回的不是直接的权限错误而是空列表或者generic的No such file。另外安装目录里如果混进了中文路径、空格、特殊字符也会让通配符解析变得异常脆弱。Unix环境下很多工具处理空格路径都有自己的规则而SPEC CPU2006的工具链本身年代久远对这类路径的兼容性极差有空格的话glob启动阶段就会出怪问题。所以如果还没开始跑先把安装目录放到纯英文、无空格的路径下。3. 实战从报错到定位一次完整的glob问题排查3.1 复现现场runspec一出场就翻车我这次是在搭建新测试平台时遇到的。机器是x86_64架构系统是最新的Linux发行版用官方ISO解压安装SPEC CPU2006后先跑了一个最简单的基准401.bzip2做环境验证执行source shrc runspec --configMyConfig.cfg --test 401.bzip2一开始一切正常编译阶段甚至顺利通过了结果在进入运行阶段时输出了一段刺眼的报错Running 401.bzip2... glob failed: No such file or directory at ./bin/specinvoke line 216. invocation line: ... --output $SPEC/benchspec/CPU2006/401.bzip2/data/test/output/*.out注意这个报错信息它已经把glob失败的调用行列出来了指向的是输出通配符*.out。这就是最好的排查线索直接顺着这条路径去查而不是去改specinvoke脚本本身。3.2 手工验证通配符让问题原形毕露报错信息已经告诉我们它试图在data/test/output/这个目录下匹配.out文件。那我就在命令行里手动复现一下这个展开过程用shell的内置glob做检验ls $SPEC/benchspec/CPU2006/401.bzip2/data/test/output/结果一执行就发现问题了目录能访问但里面是空的连一个.out文件都没有。test数据集确实存在但里面的输出文件没有生成或者说数据的展开不完整。再往下查发现data/test/output目录里缺少很多文件只留下了一个多余的描述文件。这个定位思路适用于所有glob问题报错信息里给了哪个模式就直接拿那个模式做ls或者find看看能不能匹配到文件。能不能匹配是分水岭匹配不到说明数据缺失能匹配到但工具还报错那就是模式解析出了问题。3.3 用strace做终极确认避免盲修瞎改手动验证只能确认“空的”这个结果但如果想看得更细比如specinvoke到底访问了哪些路径、在权限上是否受阻这时候就该用strace。我用它跟踪了specinvoke的文件访问行为strace -f -e tracefile,getdents -o /tmp/spec_trace.log ./specinvoke -n 1打开日志后能看到一堆openat、newfstatat、getdents系统调用。重点关注那些返回ENOENT的路径。我这次日志里连续出现了几十次ENOENT全部指向data/test/output目录下的缺失文件。这就彻底确认了不是脚本逻辑问题不是Perl环境问题就是数据集本身不完整。这一步的经验是glob报错时别一上来就重装整套SPEC先用strace看系统调用几秒钟就能定位到具体挂在哪个路径上后续修复就有的放矢。4. 解决方案从临时绕行到彻底根治4.1 快速应急用其它数据集先跑通如果赶时间等不及补齐数据文件可以通过runspec的数据集参数临时绕开。SPEC CPU2006的config文件里支持对数据规模做控制比如runspec --configMyConfig.cfg --test 401.bzip2 runspec --configMyConfig.cfg --train 401.bzip2--test和--train会强制使用对应数据集。如果你要跑的基准程序test数据集是完整的而ref数据集缺失那先跑test或train是合法的应急手段。我也是在这个阶段先用--test把测试平台的环境验证通了证明编译器配置和二进制没问题从而把问题范围缩小到数据文件层面。4.2 补齐数据文件根治的关键动作应急归应急做正式的跑分对标还是需要完整的数据集。彻底解决办法是重新展开数据文件。在SPEC CPU2006安装目录下重新触发数据安装流程cd $SPEC ./install.sh或者更直接用自带的unpack工具按基准包逐个展开$SPEC/tools/bin/unpack 401.bzip2这里要特别留神一个问题unpack工具可能会覆盖你已经在跑的基准程序二进制所以在正式展开前先把benchspec/CPU2006/401.bzip2/run下的结果备份好。我这次因为只是环境验证阶段数据还没跑出有效结果直接重跑install.sh也无所谓。展开完成后再验证一次ls $SPEC/benchspec/CPU2006/401.bzip2/data/test/output/ | head ls $SPEC/benchspec/CPU2006/401.bzip2/data/ref/output/ | head看到文件都齐了再执行runspecglob报错就消失了。整个过程我实测下来从复现到修好不到半小时如果早用strace定位还能更快。4.3 命令文件与自定义脚本里的通配符陷阱数据解决了但还有一种glob问题是自己写的东西触发的。比如你在自定义脚本里调用specinvoke写了一个不精确的路径模式或者把$SPEC变量传成了空字符串都会让glob展开失败。这类问题排查时有个特点报错信息里的模式是残缺的比如glob failed: ... /data//input/*.in路径中间出现双斜杠或者模式首字符直接是/。我建议在自定义脚本里统一采用绝对路径并且显式检查变量SPEC${SPEC:?SPEC variable not set} input_pattern$SPEC/benchspec/CPU2006/401.bzip2/data/test/input if [ ! -d $input_pattern ]; then echo input data directory missing: $input_pattern 2 exit 1 fi这样做既能让问题提前暴露也能避免glob在模式匹配阶段带着无效路径兜圈子。4.4 工具链本身兼容老系统也没错但要留意Perl行为还有一类glob报错跟数据、路径都没关系纯粹是工具链在底层Perl上的行为差异。SPEC CPU2006自带的工具版本比较老在较新的Linux发行版上Perl的glob实现会对“目录可读性检查和路径存在性检查”的出现顺序做调整。某些极小概率出现的情况会让glob对一个存在但不可读的目录返回No such file or directory而不是直白的Permission denied。遇到这种临时方案是运行前统一目录权限chmod -R urwX $SPEC或者以安装用户身份运行。长期方案是重新编译SPEC自带的工具链安装到$SPEC/tools/bin下让它们匹配当前系统的库和Perl版本。这个重编过程我在后续的另外一篇文章里会细写这里只要记住glob报错不全是数据问题工具链的兼容性也值得怀疑尤其是当你确认数据文件完全正常、路径也正确但报错依旧的时候。5. 常见问题与避坑速查5.1 glob问题快速诊断表报错现象可能原因处理方向glob failed: No such file or directory数据文件缺失或路径不存在检查对应目录补齐数据重新unpackglob failed: No such file or directory且路径指向旧目录$SPEC变量未更新重新source shrc确认SPEC路径Use of uninitialized value in glob环境变量或配置变量为空检查config文件变量、命令行传参glob: Permission denied运行用户无目录读权限chmod/chown或换回安装用户能ls到文件但glob返回空结果Perl版本或工具链兼容问题重编工具链调整环境自定义脚本里glob失败通配符模式或路径拼接错误用绝对路径提前校验变量和目录5.2 几个值得记住的避坑心得跑SPEC CPU2006这么多年glob问题只是众多坑中的一个但它的排查思路很典型。第一看到glob失败先别慌别去改specinvoke源码先看报错里给的具体模式然后手动ls一下这是最高效的一步。第二养成跑之前检查数据文件的习惯尤其是换了新机器、新环境之后source shrc是第一步ls data/test是第二步这两步都不费时间但能省掉大把折腾时间。第三构建测试平台时尽量用干净路径安装避免中文字符和临时移动目录。我见过太多人在分区调整后忘记重装或重新source环境导致路径漂移这类问题最隐蔽因为报错看起来完全是文件系统的锅。第四数据文件缺失这种低级问题往往不是安装者故意省而是安装过程中断、介质不完整导致的。所以判断时不要有侥幸心理直接去目录里数文件最实在。5.3 一套稳定的初始检查操作序列最后分享一套我每到一个新环境跑SPEC CPU2006前都会走的检查序列。先执行source shrc然后检查echo $SPEC是否为预期目录接着挑选一个基准程序验证test、train、ref三个数据目录的核心文件是否存在再用--test跑一个轻量基准确认编译和运行链路通顺最后才跑正式的ref数据集。这套流程下来glob这类工具链问题基本在正式跑分前就暴露了。我个人在实际操作中的体会是SPEC CPU2006是套老工具但它跑出来的数字到今天仍有参考价值。遇到glob报错别急着断言“工具坏了”大多数情况下是环境变量、数据文件或者路径规范这些外围因素在捣乱。把排查思路理顺这类问题五到十分钟就能定位。希望这篇记录能帮同行们少走点弯路跑分顺利。