Kob*_*obs 7 benchmarking matlab
我有一个很大的MATLAB函数文件.它首先创建一个零矩阵,然后通过评估函数中硬编码的多个相应(长)代数表达式来更新大约70%的单元格.完成后,将返回一个数字矩阵.
.m文件大约4 MB(我有100个这样的m.文件,但这不是直接相关的).当我第一次评估该功能时,需要大约9秒来评估.然而,后续运行只需要大约0.1秒,这正是我所期待的.
为什么第一次评估需要9秒钟?每当我关闭并重新打开MATLAB时,我每次都会进行这种缓慢的第一次评估,后续运行速度要快得多.为什么是这样?
米 文件可以在以下公共链接中找到(您可以从浏览器中复制文本):https: //dl.dropboxusercontent.com/u/157153767/K_a_12_102x.m
您应该使用的命令窗口输入是:[test] = K_a_12_102x(414000000,1.1095e + 09,1.2500e-04,0.0840,0.0840,0.0240,0.0240,0.0020,0.0020,0,0,0,0,3.0397e + 08,8.9930e + 07,0,3.0397e + 08,0,1.0702e + 08,0,0,0,0,0,0,497.7389,80.7355,-15.9811,391.1985,-15.9811,103.5248,20440000,0,20440000 ,0.06)
cha*_*pjc 14
在将JIT编译器引入MATLAB之前很久就已经出现了慢速运行,即使对于MEX文件也是如此,未应用JIT编译器.当您第一次运行代码时,MATLAB必须从磁盘加载它,解析代码(请参阅下面的运行时类型分析详细信息),如果它是.m文件,则应用JIT编译.然后在执行时,分配数据空间,并将指令加载到CPU缓存中,在那里它们可以保持非常快的访问时间以进行进一步的执行.这就是在MATLAB世界之外无处不在的"缓存升温"程序的原因,正如我所理解的那样(为我挥手致意硬件增益).但是,对于.m fies,磁盘访问可能是一个重要因素,即使文件比"大约4MB大"小得多,就像你的情况一样.当多个函数具有相同的名称时,还有一个函数消歧的附加步骤.
要查看MEX文件发生这种情况,只需运行clear mex并计时函数调用即可.MATLAB必须重新从磁盘加载到内存中,可能是CPU缓存无效.
代码加速功能的第二个方面(JIT代码生成是第一个),是运行时类型分析.从旧的MathWork白皮书:
运行时类型分析基于以下前提:如果之前已处理过一行M代码,则变量很可能具有与上次系统看到此行时相同的类型和形状.第一次执行一行代码时,系统会检查变量并为找到的数据类型和形状生成特定代码.只要系统验证变量类型和大小没有改变,该行的后续执行就可以重用该代码.由于类型很少改变,后续执行尽可能快地执行.如果类型确实更改,则重新生成代码.
您可以考虑JIT编译过程的这一部分,它就是.但关键是这个分析是在第一次执行时运行的,无论加速器是否决定JIT编译任何代码行.顺便说一句,整个文件没有编译成机器代码.过去可以看到哪些线在使用的探查器中加速setpref('profiler','showJitLines',1);但不幸的是作为一个特征被移除.
无论如何,在实际查看代码之后,从磁盘加载文件后需要解析大量的常量和变量.一行超过31,000个字符,数千个数字文字!分析和决定需要编译的内容以及运行之间可以缓存的内容有很多.好像要证明这一点,只是查看(不运行)您的代码设法使编辑器DirectUI::DUIXmlParser::InitializeParserFromXmlLiteReader在堆栈跟踪上崩溃.哎呀,这是一些讨厌的代码!
让我们来看看打开MATLAB加速功能的代码.我们还运行控制测试,我们知道在没有加速的情况下运行速度大约8倍.
>> feature accel on
>> clear K_a_12_102x
>> x = rand(1000); tic,for t=1:1e6, x=x; end,toc % control
Elapsed time is 0.083878 seconds.
% do first-run of K_a_12_102x, took 13.280327 sec
>> tic; [test]=K_a_12_102x(414000000,1.1095e+09,1.2500e-04,0.0840,0.0840,0.0240,0.0240,0.0020,0.0020,0,0,0,0,3.0397e+08,8.9930e+07,0,3.0397e+08,0,1.0702e+08,0,0,0,0,0,0,497.7389,80.7355,-15.9811,391.1985,-15.9811,103.5248,20440000,0,20440000,0.06); toc
Elapsed time is 0.151804 seconds.
Run Code Online (Sandbox Code Playgroud)
现在我们关闭加速并运行相同的测试:
>> feature accel off
>> clear K_a_12_102x
>> tic,for t=1:1e6, x=x; end,toc % control
Elapsed time is 0.630039 seconds.
% do a first-run of K_a_12_102x, took 15.634775 seconds
>> tic; [test]=K_a_12_102x(414000000,1.1095e+09,1.2500e-04,0.0840,0.0840,0.0240,0.0240,0.0020,0.0020,0,0,0,0,3.0397e+08,8.9930e+07,0,3.0397e+08,0,1.0702e+08,0,0,0,0,0,0,497.7389,80.7355,-15.9811,391.1985,-15.9811,103.5248,20440000,0,20440000,0.06); toc
Elapsed time is 0.159683 seconds.
Run Code Online (Sandbox Code Playgroud)
调查结果有两方面:
简而言之,您的代码不会受益于JIT加速,并且JIT执行/分析不会添加到首次执行的执行时间.
问题仍然存在,是什么导致首次运行缓慢?一些可能性:从磁盘加载代码文本,在将代码保存到RAM中之前解析(剥离注释和空白)代码,而不是重用以前运行中保存的变量初始化,可能是保存在CPU缓存中的函数使用的核心MATLAB指令,以及任何MATLAB执行运行时语法检查所必需的非JIT相关代码分析.事实上,文件是4MB,并且在方程长度和数字文字数量方面非常复杂,这表明它不是CPU缓存,而是初始文件加载和代码分析.
我认为这是JIT编译.第一次执行该文件时,MATLAB必须对其进行解释(将文本转换为机器代码).
后续运行使用缓存的机器代码并执行得更快.为了验证这一点:在代码中稍作修改之后,MATLAB将需要重做这个编译 - 所以它对于下一次运行应该很慢.(我这样做的确如此.)你正在做大量简单的操作,应该很快执行.转换为机器代码会降低您的速度.
要加速整个过程:将代码传输到C,C#或类似的东西,并将其包含为DLL文件.您将获得持续快速的计算,但您无法轻松更改它们.
(使用C#DLL文件,你也有一些JIT编译,但它不太经常,可能仍然比MATLAB更快.)
我做了一些编码并将代码移植到C#.原始时间为13.4秒和0.15秒(第一次/第二次运行)
简单端口,发布配置:
>> test_1
Elapsed time is 124.7 seconds.
>> test_1
Elapsed time is 0.0297 seconds.
Run Code Online (Sandbox Code Playgroud)
所以第一次运行比MATLAB更糟糕 - 更糟糕.虽然我喜欢C#,但它可能不是这项工作的最佳工具.(顺便说一句:我不得不使用命令行编译器,因为Visual Studio 2010一直在崩溃...)