# understanding this timing result

I got two timings which I do not understand.

a = RandomReal[1., {1000, 1000}];
Table[RotateLeft[a, {1, 1}][[1, 1]], {i, 1, 500}]; // AbsoluteTiming
Table[RotateLeft[a, {1, 1}];, {i, 1, 500}]; // AbsoluteTiming


which gives

{1.02723, Null}
{3.02416, Null}


But from the Trace, it seems that both doing roughly the same amount of work. Why is there such a huge differece?

another one is

Do[(a*1.)[[1, 1]], {i, 1, 2000}]; // AbsoluteTiming
Table[(a*1.)[[1, 1]], {i, 1, 2000}]; // AbsoluteTiming


which gives

{11.3509, Null}
{3.5007, Null}


Why is there a huge difference between Table and Do?

Memory. Table[RotateLeft[a, {1, 1}];, {i, 1, 500}] requires to allocate and to write $$1000 \times 1000 \times 500 \times 8$$ bytes for storing the result, while Table[RotateLeft[a, {1, 1}][[1, 1]], {i, 1, 500}]; requires only $$500 \times 8$$ bytes. However, I cannot reproduce the timings with Mathematica 12 for macos. My timings are 0.413361 for the former and 0.39489 for the latter.

However, I don't fully understand the difference between Do and Table. And the relative difference is a bit smaller on my machine. The timings are 1.669 for Do and 0.748476 for Table. One possible reason could be that the memory for the result of Table is allocated one and the BLAS(?) routines that are called by a*1. are directly used as return buffer. In contrast, there is a chance that Do allocates and deallocates memory for each intermediate result. But I don't know. This issue is probably worth to be submitted to Wolfram Support.

Edit

As J.M. suspected, it is about SystemOptions["CompileOptions" -> {"TableCompileLength"}]. Executing

SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> 10000}]


before the Do and Table calls makes them equally bad in performance. So for some reason, the Do loop is not autocompiled. First I wondered why that is. Then it came to my mind that the intend of using a Do loop is typically a side effect that might be infeasible to be handled by a compiled function.

Edit

The return value of RotateLeft[a, {1, 1}]; is Null and that cannot be compiled. So Table[RotateLeft[a, {1, 1}];, {i, 1, 500}]; is evaluated without the JIT-compiler.

• Can you do an experiment where you first evaluate SetSystemOptions["CompileOptions" -> {"TableCompileLength" -> n}], where n is e.g. larger or smaller than the table's length? Feb 15, 2021 at 9:51
• Hi, Henrik Schumacher. Thank you for answering. But I do not understand why Table[RotateLeft[a, {1, 1}];, {i, 1, 500}] would need 1000×1000×500×8, there is ; after RotateLeft, it does not need such a large space to hold result. Feb 15, 2021 at 16:15
• Besides, I found setting "TableCompileLength" -> 10000, makes two Table of RotateLeft the same timing. So it maybe a evidence that memory is not the issue here. But I do not understand, when compileLength is small, the only difference is that the second Table generate a list like {Null, Null, ...} which is unpacked, but that should not account for such a huge timing difference. I used 12.2, this behaviour appears on both windows and linux Feb 15, 2021 at 16:23
• Valid points. I had overlooked the semicolon. It is then probably all about compilation. Null cannot be compiled, so auto-compilation for Table[RotateLeft[a, {1, 1}];, {i, 1, 500}] does not work. Feb 15, 2021 at 16:26
• Thank you so much. I got a better understanding of autocompile now. So Table saw each element is returning Null, so the whole Table process is not compiled. But it is still bizarre to me that RotateLeft is kernel function, why there would be seconds of speed up after compilation. Generating a list of 500 null takes less than 1 microsecond. What has autocompilation been speeding up? Feb 15, 2021 at 16:49