Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
299 views
in Technique[技术] by (71.8m points)

benchmarking - MATLAB function is slow the first time, but much faster subsequently. Why?

I have a large MATLAB function file. It first creates a zero matrix, then updates about 70% of the cells by evaluating a number of corresponding (long) algebraic expressions that are hard coded in the function. Once this is complete, a numeric matrix is returned.

The .m file is about 4 MB large (I have 100 of these m. files, but that is not directly relevant). When I evaluate the function the first time, it takes about 9 seconds to evaluate. Subsequent runs, however, only take about 0.1 second, which is more what I was expecting.

Why does the first evaluation take 9 seconds? Anytime I close and reopen MATLAB, I each time have this slow first evaluation, with subsequent runs being much faster. Why is this?

The m. file can be found at the below public link (you can copy the text from the browser): https://dl.dropboxusercontent.com/u/157153767/K_a_12_102x.m

The command window input you should use is: [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)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Slow first runs have been the case long before the JIT compiler was introduced into MATLAB, and true even for the case of MEX files, on which the JIT compiler is not applied. When you run code for the first time, MATLAB has to load it from disk, parse the code (see runtime type analysis details below), and apply JIT compilation if it is a .m file. Then on execution, space for data is allocated, and instructions are loaded into CPU cache, where they might stay with very fast access times for further executions. This is the reason for ubiquitous "cache warming" procedures outside the world of MATLAB, as I understand it (apologies to hardware buffs for my hand-waving). However, with .m fies, disk access is probably a big factor, even with files that are much smaller than "about 4MB large" as in your case. There's also an added step of function disambiguation when multiple functions have the same name.

To see this happening for a MEX file, simply run clear mex and time a function call. MATLAB has to load it from disk and into memory all over again, probably with an invalidated CPU cache.

Run-time Type Analysis

A second aspect of the code acceleration features (JIT code generation is the first), is run-time type analysis. From an old MathWork whitepaper:

Run-time type analysis is based on the following premise: If a line of M-code has been processed before, it is very likely that the variables have the same types and shapes that they had the last time the system saw this line. The first time that a line of code is executed, the system examines the variables and generates specific code for the data types and shapes that were found. Subsequent executions of the line can reuse this code as long as the system verifies that the variable types and sizes have not changed. Since the types rarely change, subsequent executions run as quickly as possible. If the types do change,the code is regenerated.

You might consider this part of the JIT compilation process, and it is. But the point is that this analysis is run on first execution, regardless of whether the accelerator decides to JIT-compile any lines of code. BTW, the whole file doesn't get compiled into machine code. It used to be possible to see which lines got accelerated in the profiler using setpref('profiler','showJitLines',1); but that was unfortunately removed as a feature.

Anyway, after actually looking at your code, there are a staggering number of constants and variables that need to be parsed after loading the file from disk. One line is over 31,000 characters long with several thousand numeric literals! That's a lot to analyze and decide what needs compilation and what can be cached between runs. As if to demonstrate this point, just viewing (not running) your code managed to crash the editor with DirectUI::DUIXmlParser::InitializeParserFromXmlLiteReader on the stack trace. Yikes, that's some nasty code!

Does the JIT compiler generate code for this function?

Let's time the code with MATLAB's acceleration features turned on. We also run control test that we know to run about 8x slower without acceleration.

>> 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.

Now we turn off acceleration and run the same tests:

>> 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.

Findings

The findings are two-fold:

  1. First-run time is NOT improved with acceleration (JIT) disabled (13.28 sec with JIT on vs. 15.63 sec with JIT off).
  2. Subsequent runs show that no machine code is generated when JIT is enabled (0.1518 sec with JIT ON vs. 0.1597 sec with JIT off)

In short, your code does not benefit from JIT acceleration, and JIT execution/analysis does NOT add to the first-run execution time.

The question remains, what causes the slow first-run time? Some possibilities: loading of the code text from disk, parsing (stripping comments and whitespace) the code before saving it in RAM, not reusing variable initialization saved from previous runs, maybe core MATLAB instructions used by the function saved in CPU cache, and any non-JIT related code analysis necessary for MATLAB to do runtime syntax checking. The fact that the file is 4MB and incredibly complex in terms of equation length and the sheer number of numeric literals suggests that its not CPU cache, but initial file loading and code analysis.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...