Re: [julia-users] compile time conditional statements and julia?

417 views
Skip to first unread message

Stefan Karpinski

unread,
May 29, 2013, 2:14:56 PM5/29/13
to julia...@googlegroups.com
You could do this with a @debug macro. With debug mode on it would just emit its argument expressions; with debug mode off, it would emit nothing. The exact API for controlling whether debug mode is on or off would have to be bikeshedded.

On Wednesday, May 29, 2013, Simon Hardy-Francis wrote:


Consider this simple Perl script:

use strict;
use Time::HiRes;

my $t1 = Time::HiRes::time;
foreach (1..50000000) {
}
my $t2 = Time::HiRes::time;

my $t3 = Time::HiRes::time;
my $debug = 0;
foreach (1..50000000) {
   if ($debug) { printf qq[my debug line: %u], $_; }
}
my $t4 = Time::HiRes::time;

my $t5 = Time::HiRes::time;
use constant DEBUG => 0;
foreach (1..50000000) {
   if (DEBUG) { printf qq[my debug line: %u], $_; }
}
my $t6 = Time::HiRes::time;

printf qq[%f seconds for plain loop\n], $t2 - $t1;
printf qq[%f seconds for negative if() loop \n], $t4 - $t3;
printf qq[%f seconds for compiled out loop \n], $t6 - $t5;

The output is:

$ perl example.pl 
1.372535 seconds for plain loop
1.899815 seconds for negative if() loop 
1.370118 seconds for compiled out loop 

The nice thing is that "if (DEBUG) { printf qq[my debug line: %u], $_; }" line gets compiled away and there is no resulting negative if() at run-time. This technique is very useful for instrumenting Perl code with verbose logging which doesn't slow down production code (by executing many negative 'if' statements) when verbosity is dialed down.

Is there an equivalent way to achieve the same performance results in julia?

Thanks,
Simon

Tim Holy

unread,
May 29, 2013, 3:29:55 PM5/29/13
to julia...@googlegroups.com
On Wednesday, May 29, 2013 02:14:56 PM Stefan Karpinski wrote:
> You could do this with a @debug macro. With debug mode on it would just
> emit its argument expressions; with debug mode off, it would emit nothing.
> The exact API for controlling whether debug mode is on or off would have to
> be bikeshedded.

And of course you'd want to do this in a way that doesn't conflict with Toivo's
Debug package.

--Tim

Simon Hardy-Francis

unread,
May 29, 2013, 4:09:48 PM5/29/13
to julia...@googlegroups.com
Thanks. So just for fun I came up with the following code which unfortunately doesn't work as expected:

tic(); i = 1;            while i <= 50000000; i += 1; end; toc()

tic(); i = 1; debug = 0; while i <= 50000000; i += 1
  if 1 == debug
    println("my debug line: ", i);
  end
end; toc()

# how to disable this macro before run-time?
macro mydebug(text, value)
  println(text, value);
end

tic(); i = 1; debug = 0; while i <= 50000000; i += 1
  @mydebug("my debug line: ", i);
end; toc()

When I run it then I get the following:

$ ./julia example.jl
elapsed time: 3.741771936 seconds
elapsed time: 4.526868245 seconds
my debug line: i
elapsed time: 3.639432751 seconds

Questions:
1. Why is it so much slower than the Perl equivalent, especially consider all the sexy julia benchmarks floating around?
2. Why does the macro on show one debug line instead of 50 million?
3. How to get the macro to display the value of i?
4. How to programmatically switch off / disable the macro during compile time / before run-time?

Thanks,
Simon

Alessandro "Jake" Andrioni

unread,
May 29, 2013, 4:14:12 PM5/29/13
to julia...@googlegroups.com
On 29 May 2013 17:09, Simon Hardy-Francis <sim...@gmail.com> wrote:
> 1. Why is it so much slower than the Perl equivalent, especially consider
> all the sexy julia benchmarks floating around?

If you are running this on the REPL, put it inside a function or
declare the variables local, as otherwise they default to being global
(and thus some optimizations aren't available).

For example:
julia> tic(); i = 1; while i <= 50000000; i += 1; end; toc()
elapsed time: 2.9939913 seconds
2.9939913

julia> tic(); local i = 1; while i <= 50000000; i += 1; end; toc()
elapsed time: 0.011757534 seconds
0.011757534

while the perl script here outputs:
$ perl example.pl
1.595925 seconds for plain loop
2.233078 seconds for negative if() loop
1.741121 seconds for compiled out loop

Keno Fischer

unread,
May 29, 2013, 4:17:15 PM5/29/13
to julia...@googlegroups.com
1. Because you're at toplevel, so the compiler can't make any assumptions on the type of i. You need to put in in a function.
2. Because the print is at parse time
3. in the macro body
quote
    println($text,$value)
end
4. You'll want debug to be a constant defined before the macro and then it's as simple as
if debug
return quote
    println($text,$value)
end
else
nothing
end

Simon Hardy-Francis

unread,
May 29, 2013, 4:50:16 PM5/29/13
to julia...@googlegroups.com, jake...@gmail.com
Hi Alessandro,

Thanks for the reply.

Why does the 1st line fail while the 3rd line works in the following example?

$ ./julia

julia> tic(); local i = 1;            while i <= 50000000; i += 1; end; toc()
ERROR: in anonymous: i not defined
 in anonymous at no file

julia> tic(); i = 1;            while i <= 50000000; i += 1; end; toc()
elapsed time: 3.812239381 seconds
3.812239381

julia> tic(); local i = 1;            while i <= 50000000; i += 1; end; toc()
elapsed time: 0.013821885 seconds
0.013821885

Further, I'm wondering if 0.01 seconds for looping 50 million times is a little too fast? :-) My suspicion is that julia is optimizing the loop away, which results in the apparently very fast benchmark. In the following test I try to put something inside the loop:

$ ./julia 

julia> i = 1; j = 0; tic(); local j; local i = 1;            while i <= 50000000; i += 1; j = j + i; end; toc(); println("i=", i, ", j=", j);
elapsed time: 5.331966565 seconds
i=50000001, j=1250000075000000

julia> j = 0; tic(); local j; local i = 1;            while i <= 50000000; i += 1; j = j + i; end; toc(); println("i=", i, ", j=", j);
elapsed time: 0.015534019 seconds
i=50000001, j=0

Why is j=0 for the 2nd line? I think I don't understand what the 'local' statement does :-( What is the difference between these two lines?

And FYI here is the 'j loop' version in Perl:

$ perl -e 'use strict; use Time::HiRes; my $j; my $t1 = Time::HiRes::time; foreach (1..50000000) { $j += $_; } my $t2 = Time::HiRes::time; printf qq[%f seconds for j loop; j=%u\n], $t2 - $t1, $j;'            
2.619239 seconds for j loop; j=1250000025000000

Thanks,
Simon

vav...@uwaterloo.ca

unread,
Aug 2, 2014, 8:33:33 PM8/2/14
to julia...@googlegroups.com
Dear Julia colleagues,

I'm reviving this old thread because I am also trying to create two versions of my balanced-tree code, the fast version and the debug version, and I am trying to figure out the appropriate way for one source-code file to yield two versions.  In C++, the usual technique is a -DDEBUG compilation flag, followed by #ifdef DEBUG ... #else ... #endif macros.  

I thought that maybe in Julia I could accomplish this with ordinary "if" statements  since the compiler could optimize away unused branches, but it doesn't seem to work:

module testcodegen1

function t1(x::Float64)
    s = 0.0
    for i = 1 : 20000000
        s += sin(x)
    end
    s
end

function t2(x::Float64)
    s = 0.0
    for i = 1 : 20000000
        if true
            s += sin(x)
        else
            s += sin(2*x)
        end
    end
    s
end

end

Clearly t1 and t2 are equivalent, but t2 has an unreachable code branch that could be optimized away.  However, the compiler doesn't seem to recognize this:  

julia> tic(); testcodegen1.t1(3.0);  toc()
tic(); testcodegen1.t1(3.0);  toc()
elapsed time: 0.216690647 seconds
0.216690647

julia> tic(); testcodegen1.t2(3.0);  toc()
tic(); testcodegen1.t2(3.0);  toc()
elapsed time: 0.53437478 seconds
0.53437478

It seems that using ordinary 'if' statements to distinguish the debugging mode entails a big performance hit.

Thanks for the help,
Steve Vavasis




On Wednesday, May 29, 2013 1:46:21 PM UTC-4, Simon Hardy-Francis wrote:


Consider this simple Perl script:

use strict;
use Time::HiRes;

my $t1 = Time::HiRes::time;
foreach (1..50000000) {
}
my $t2 = Time::HiRes::time;

my $t3 = Time::HiRes::time;
my $debug = 0;
foreach (1..50000000) {
   if ($debug) { printf qq[my debug line: %u], $_; }
}
my $t4 = Time::HiRes::time;

my $t5 = Time::HiRes::time;
use constant DEBUG => 0;
foreach (1..50000000) {
   if (DEBUG) { printf qq[my debug line: %u], $_; }
}
my $t6 = Time::HiRes::time;

printf qq[%f seconds for plain loop\n], $t2 - $t1;
printf qq[%f seconds for negative if() loop \n], $t4 - $t3;
printf qq[%f seconds for compiled out loop \n], $t6 - $t5;

Jameson Nash

unread,
Aug 2, 2014, 9:04:03 PM8/2/14
to julia...@googlegroups.com
constant propagation is almost implemented in inference.jl (it's quite similar to type propagation), but it isn't active now: https://github.com/JuliaLang/julia/issues/5560

Tim Holy

unread,
Aug 2, 2014, 10:03:25 PM8/2/14
to julia...@googlegroups.com
There's something else wrong. It makes no sense that the time hit should be so
large; evaluating sin is _expensive_, much more than a conditional, especially
since this one will work perfectly with the CPU's branch-point prediction.

I tried it using @time rather than tic/toc, and the extra information provided
by @time revealed that there is allocation -> some kind of type problem.
(Basically you should always use @time in preference to tic/toc, it's just
much more informative.) Then, I left the `if` in place but commented out the
`else` part, and the performance of the two functions became identical. So
there's something about the else branch that's messing up type inference (and
as far as I can tell it shouldn't, so it's probably a bug).

Can you please file an issue?

--Tim

Tim Holy

unread,
Aug 4, 2014, 3:14:11 PM8/4/14
to julia...@googlegroups.com
Bump @Steve Vavasis. Did you ever file an issue on this? https://github.com/JuliaLang/julia/issues
Reply all
Reply to author
Forward
0 new messages