www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - release mode optimization

reply Charles Hixson <charleshixsn earthlink.net> writes:
Would the following code:
for (int i = 1; i < di.count; i++)
{  assert (node.di.entry[i - 1].key < node.di.entry[i].key);  }

be optimized away if compiled under -release?
Jan 09 2013
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, January 09, 2013 16:14:47 Charles Hixson wrote:
 Would the following code:
 for (int i = 1; i < di.count; i++)
 { assert (node.di.entry[i - 1].key < node.di.entry[i].key); }
 
 be optimized away if compiled under -release?
If you compile with -release, assertions will be compiled out, so you'd get for(int i = 1; i < d.count; i++) {} However, I don't believe that -release enables any optimizations - that's what -O is for - so the loop would likely be left in with -release. If you compile with -O, it _might_ be optimized out. I don't know. It would be great if it did, but you'd have to test it to know for sure. But that's not hard to do at all (in fact, it wouldn't have taken much longer to test it then to post your question). In fact, if I test it now... This code import std.conv; import std.datetime; import std.stdio; void main() { auto sw = StopWatch(AutoStart.yes); foreach(i; 0 .. 50_000_000) {} writeln(to!Duration(sw.peek)); } takes just over 37ms on my machine. If I remove the foreach, it takes about 3 hnsecs. So clearly, dmd does _not_ optimize out the loop. I have no idea what gdc and ldc do though. - Jonathan M Davis
Jan 09 2013
next sibling parent reply "David Nadlinger" <see klickverbot.at> writes:
On Thursday, 10 January 2013 at 00:40:21 UTC, Jonathan M Davis 
wrote:
 So clearly, dmd does _not_ optimize out the loop. I have no 
 idea what
 gdc and ldc do though.
Wow, DMD doesn't optimize it away indeed, just confirmed that by a look at the assembly. LDC does delete the loop though, starting at -O1, and I can't imagine that GDC wouldn't as well. David
Jan 09 2013
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Jan 10, 2013 at 02:03:47AM +0100, David Nadlinger wrote:
 On Thursday, 10 January 2013 at 00:40:21 UTC, Jonathan M Davis
 wrote:
So clearly, dmd does _not_ optimize out the loop. I have no idea what
gdc and ldc do though.
Wow, DMD doesn't optimize it away indeed, just confirmed that by a look at the assembly.
I tested DMD on a loop containing assert(true);, and apparently that *is* optimized out with -O. So DMD does catch simpler cases of no-op loops. Probably the OP's code is a bit beyond DMD's optimizer to recognize as a no-op loop.
 LDC does delete the loop though, starting at -O1, and I can't
 imagine that GDC wouldn't as well.
[...] Yeah, something like that would be a sitting duck for GCC's optimizer. T -- Claiming that your operating system is the best in the world because more people use it is like saying McDonalds makes the best food in the world. -- Carl B. Constantine
Jan 09 2013
parent "David Nadlinger" <see klickverbot.at> writes:
On Thursday, 10 January 2013 at 01:14:42 UTC, H. S. Teoh wrote:
 I tested DMD on a loop containing assert(true);, and apparently 
 that
 *is* optimized out with -O.
I tested it with the program from Jonathan's post – still has an empty inc/cmp/jl loop in there with -O -release (x86_64). David
Jan 09 2013
prev sibling parent Charles Hixson <charleshixsn earthlink.net> writes:
On 01/09/2013 04:40 PM, Jonathan M Davis wrote:
 On Wednesday, January 09, 2013 16:14:47 Charles Hixson wrote:
 Would the following code:
 for (int i = 1; i<  di.count; i++)
 { assert (node.di.entry[i - 1].key<  node.di.entry[i].key); }

 be optimized away if compiled under -release?
If you compile with -release, assertions will be compiled out, so you'd get for(int i = 1; i< d.count; i++) {} However, I don't believe that -release enables any optimizations - that's what -O is for - so the loop would likely be left in with -release. If you compile with -O, it _might_ be optimized out. I don't know. It would be great if it did, but you'd have to test it to know for sure. But that's not hard to do at all (in fact, it wouldn't have taken much longer to test it then to post your question). In fact, if I test it now... This code import std.conv; import std.datetime; import std.stdio; void main() { auto sw = StopWatch(AutoStart.yes); foreach(i; 0 .. 50_000_000) {} writeln(to!Duration(sw.peek)); } takes just over 37ms on my machine. If I remove the foreach, it takes about 3 hnsecs. So clearly, dmd does _not_ optimize out the loop. I have no idea what gdc and ldc do though. - Jonathan M Davis
Thank you for a reply that was both useful and informative. P.S.: Not knowing where to look, it would have taken me a lot more time that your estimate. I'm not sure that a few hours would have sufficed, as I seem to be running into various compiler problems that I don't understand well enough to characterize.
Jan 09 2013
prev sibling next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 00:21:48 UTC, Charles Hixson 
wrote:
 Would the following code:
 for (int i = 1; i < di.count; i++)
 {  assert (node.di.entry[i - 1].key < node.di.entry[i].key);  }

 be optimized away if compiled under -release?
If you write it as: //---- version(assert) { for (int i = 1; i < di.count; i++) assert (node.di.entry[i - 1].key < node.di.entry[i].key); } //---- Then I 100% guarantee that it will not appear in release mode ;) I know it's *kind of* off topic in regards to the original question, but if you have a chunk of code that is destined only for assertive validation, you might as well put it in an assert block: Not only is it guaranteed behavior (as opposed to relying on the compiler). It also makes reviewing simpler, as it is self documenting. Without it, a reviewer might waste effort thinking about the loop conditions* *Also: What is "di"? If it is a user defined type, and if "count" is not declared as const, then the compiler may not optimize away the loop itself, because it is worried about any side effect from calling di.count.
Jan 10 2013
parent Charles Hixson <charleshixsn earthlink.net> writes:
di is a struct containing *NO* functions.  count, however, is a 
 property, it just returns a counter variable, but that's not a local 
property.

I *LIKE* the
version(assert)
{
...
}
choice.  I'd been thinking about debug.  I didn't know that version (or 
possibly assert) could be used that way.
On 01/10/2013 01:13 AM, monarch_dodra wrote:
 On Thursday, 10 January 2013 at 00:21:48 UTC, Charles Hixson wrote:
 Would the following code:
 for (int i = 1; i < di.count; i++)
 { assert (node.di.entry[i - 1].key < node.di.entry[i].key); }

 be optimized away if compiled under -release?
If you write it as: //---- version(assert) { for (int i = 1; i < di.count; i++) assert (node.di.entry[i - 1].key < node.di.entry[i].key); } //---- Then I 100% guarantee that it will not appear in release mode ;) I know it's *kind of* off topic in regards to the original question, but if you have a chunk of code that is destined only for assertive validation, you might as well put it in an assert block: Not only is it guaranteed behavior (as opposed to relying on the compiler). It also makes reviewing simpler, as it is self documenting. Without it, a reviewer might waste effort thinking about the loop conditions* *Also: What is "di"? If it is a user defined type, and if "count" is not declared as const, then the compiler may not optimize away the loop itself, because it is worried about any side effect from calling di.count.
Jan 10 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/09/2013 04:14 PM, Charles Hixson wrote:
 Would the following code:
 for (int i = 1; i < di.count; i++)
 { assert (node.di.entry[i - 1].key < node.di.entry[i].key); }

 be optimized away if compiled under -release?
It looks like you can use std.algorithm.isSorted instead: http://dlang.org/phobos/std_algorithm.html#isSorted assert(isSorted(di)); Or perhaps: assert(isSorted(node.di.entry[0 .. di.count])); That code will disappear in release mode. Additionally, if the O(N) complexity of that check is not acceptable even in non-release mode there is std.range.assumeSorted: assumeSorted makes very few comparisons so it may miss occasional sort issues. Also, it is not really for checking but more for range algorithms that require or work better with a sorted range. Ali
Jan 10 2013
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
On 01/10/2013 08:41 AM, Ali Çehreli wrote:
 On 01/09/2013 04:14 PM, Charles Hixson wrote:
 Would the following code:
 for (int i = 1; i < di.count; i++)
 { assert (node.di.entry[i - 1].key < node.di.entry[i].key); }

 be optimized away if compiled under -release?
It looks like you can use std.algorithm.isSorted instead: http://dlang.org/phobos/std_algorithm.html#isSorted assert(isSorted(di)); Or perhaps: assert(isSorted(node.di.entry[0 .. di.count])); That code will disappear in release mode. Additionally, if the O(N) complexity of that check is not acceptable even in non-release mode there is std.range.assumeSorted: assumeSorted makes very few comparisons so it may miss occasional sort issues. Also, it is not really for checking but more for range algorithms that require or work better with a sorted range. Ali
Unfortunately, entry is also a struct. key isn't its only member. If there's some other reason to define a opCmp on entry, that would be a good approach. OTOH, if : version(assert) {...} works as suggested by monarch_dodra above, that will allow me to avoid the problem.
Jan 10 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 20:24:02 UTC, Charles Hixson 
wrote:
 On 01/10/2013 08:41 AM, Ali Çehreli wrote:
 On 01/09/2013 04:14 PM, Charles Hixson wrote:
 Would the following code:
 for (int i = 1; i < di.count; i++)
 { assert (node.di.entry[i - 1].key < node.di.entry[i].key); }

 be optimized away if compiled under -release?
It looks like you can use std.algorithm.isSorted instead: http://dlang.org/phobos/std_algorithm.html#isSorted assert(isSorted(di)); Or perhaps: assert(isSorted(node.di.entry[0 .. di.count])); That code will disappear in release mode. Additionally, if the O(N) complexity of that check is not acceptable even in non-release mode there is std.range.assumeSorted: assumeSorted makes very few comparisons so it may miss occasional sort issues. Also, it is not really for checking but more for range algorithms that require or work better with a sorted range. Ali
OTOH, if : version(assert) {...} works as suggested by monarch_dodra above, that will allow me to avoid the problem.
Well, you check if something is sorted by hand, if the code to check it already exists?
 Unfortunately, entry is also a struct.  key isn't its only 
 member.  If there's some other reason to define a opCmp on 
 entry, that would be a good approach.
I'm not entirely sure what you mean by that. The fact that it is a struct should pose no problem. As for whether or you need to define opCmp, keep in mind that "isSorted" (and *anything else* related to sorted in general) take a "less" paramter http://dlang.org/phobos/std_algorithm.html#isSorted So you can write an external "foo" function, that takes 2 entries, and returns the "lowest" one (by any custom ordering), and then call: isSorted!foo(myStuff)
Jan 10 2013