Consider these four function in different form:
f1[ls1_] := Append[Rest@ls1, 0.] + Prepend[Most@ls1, 0.]
f2 = Compile[{{ls1, _Real, 1}},
Append[Rest@ls1, 0.] + Prepend[Most@ls1, 0.],
CompilationTarget -> "C"];
f3[ls_] := Module[{n = Length@ls, tp = ls},
tp[[1]] = ls[[2]];
tp[[n]] = ls[[n - 1]];
Do[
tp[[i]] = ls[[i - 1]] + ls[[i + 1]], {i, 2, n - 1}
];
tp]
f4 = Compile[{{ls, _Real, 1}},
Module[{n = Length@ls, tp = ls},
tp[[1]] = ls[[2]];
tp[[n]] = ls[[n - 1]];
Do[
tp[[i]] = ls[[i - 1]] + ls[[i + 1]], {i, 2, n - 1}
];
tp], CompilationTarget -> "C"
];
Comparing their performance, we can see that the functional version f1
and f2
have about the same performance, but the compiled procedural version f4
is about 2X slower.
ls = Sin /@ (Range[1, 2000]/2000.);
AbsoluteTiming[TimeConstrained[Do[f1[ls];, {20000}], 5]]
AbsoluteTiming[TimeConstrained[Do[f2[ls];, {20000}], 5]]
AbsoluteTiming[TimeConstrained[Do[f3[ls];, {20000}], 5]]
AbsoluteTiming[TimeConstrained[Do[f4[ls];, {20000}], 5]]
(*{0.976474,Null}*)
(*{0.784508,Null}*)
(*{5.000856,$Aborted}*)
(*{1.595374,Null}*)
However, if we test the procedural version in Fortran (code at the end), it runs about 4X faster than f2
.
xslittlegrass$ ifort -r8 -O0 test.f90
xslittlegrass$ ./a.out
0.232574000000000
xslittlegrass$
Questions:
- Why
f4
is about 2X slower thanf1
andf2
? - Why
f4
is about 7X slower than the Fortran version? - Can we make a compiled version that has comparable performance to the Fortran version?
- I thought that a procedural function compiled to C is comparable in performance compared to procedural functions written in C. But this example seems to disagree with it. So in general how large is the gap of the performance between these two?
test.f90
program main
implicit none
integer,parameter :: N0 = 2000
integer i,j
real(kind=8) :: list(N0), result(N0),start,finish
do i = 1, N0
list(i) = sin(i/real(N0))
end do
call CPU_TIME(start)
do j = 1, 20000
result(1) = list(2)
result(N0) = list(N0-1)
do i=2,N0-1
result(i) = list(i+1) + list(i-1)
end do
end do
call CPU_TIME(finish)
write(*,*) finish-start
end program
CompilePrint
output for those compiled functions? Maybe something in the way they are translated to compiled code might explain the difference. Also Leonid has a good set of pointers on How to compile effectively. $\endgroup$Inset
andDrop
. $\endgroup$