The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
MiniLight renderer cleanup, simpler (safer) code is faster

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Eigen Class

Posts: 358
Nickname: eigenclass
Registered: Oct, 2005

Eigenclass is a hardcore Ruby blog.
MiniLight renderer cleanup, simpler (safer) code is faster Posted: Mar 30, 2009 6:57 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Eigen Class.
Original Post: MiniLight renderer cleanup, simpler (safer) code is faster
Feed Title: Eigenclass
Feed URL: http://feeds.feedburner.com/eigenclass
Feed Description: Ruby stuff --- trying to stay away from triviality.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Eigen Class
Latest Posts From Eigenclass

Advertisement

MiniLight is a minimal global illumination renderer that has been translated to 7 languages and takes on average 570 lines of code. Neat! It's of course accompanied by some benchmarks. The results are unsurprising: C++ is the largest (951 lines) and fastest, followed by OCaml (461 LoC, 2.7X slower on x86 --- this is relevant because it's faster on AMD64) and Scala (427 LoC, 6.7X slower). The slowest versions are unsurprisingly Ruby (498 LoC, 575X slower) and Python (490 LoC, 173X slower); these languages have a hard time here, not being well-suited for numerical nor symbolic processing (both in terms of implementation effort and efficiency).

I took a look at the OCaml code and couldn't resist the temptation to clean it up a bit (I did not optimize it thoroughly, though, so there's still ample optimization potential --- the same can be said of all implementations, I suspect). You can find the modified MiniLight code here.

I essentially massaged the parts that screamed for a cleanup (some bad practices explained below), making the code 17 lines shorter in the process and the program substantially faster. I then realized that whereas the C++ version was using a very fast custom PRNG, the OCaml translation utilized the stdlib one, with an appreciable effect on the speed:

Version LoCs smits-large processing time
C++ 951 15.6
OCaml orig 461 24.5
OCaml, idiomatic pattern matching 448 15.8
OCaml, simpler record type for triangle 444 14.7
OCaml, custom PRNG 452 11.6

(AMD64, GCC 4.3.2, OCaml 3.11.1 with -nodynlink)

By using more idiomatic pattern matching and option types, the OCaml version goes from being 57% slower to just as fast as the C++ one, with fewer lines of code and more static safety (see below). With the same PRNG as the C++, the OCaml version is now 34% faster than the C++. Both admit doubtlessly further optimizations. Algorithmic ones will be easier to express in OCaml, but C++ will have the edge in terms of low-level code optimization.

Anti-pattern: if instead of pattern matching

Most of the speed increase was brought by moving from ugly if expressions to idiomatic pattern matching. The raytracer had code like

let emissionIn =
   if (Triangle.Null = hitObject) || ((Triangle.Obj emitter) = hitObject) then
     ...
   else
     vZero
in

This feels wrong: when you have a variant type, you definitely want to pattern match, not to use if. As it turns out, the above code is also slower than pattern matching for two reasons:

  • Triangle.Obj emitter allocates a block in the heap that will be dead right away

  • it uses structural comparison (meaning that the object/record fields are compared one by one) instead of identity comparison

This is a simpler, more idiomatic way to write the above, which is also much faster (I use the standard option type instead of a new one that serves no purpose):

let emissionIn = match hitObject with
    Some emitter' when emitter' != emitter -> vZero
  | _ -> ...

It's easier to read too, as you don't have to analyze two boolean expressions, but only one.

Anti-pattern: tuples with boolean flags instead of option types

Read more...

Read: MiniLight renderer cleanup, simpler (safer) code is faster

Topic: Building Ruby 1.9.1 on Windows Previous Topic   Next Topic Topic: Interview: Carl Lerche on Merb

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use