|
|
|
|
|
|
| |
| |
|
|
|
|
| |
| |
|
|
As part of my Insanely Complicated Tree function, I need to clip some
(x, y, z) coordinates to a sphere of radius r. (I'm going to use it as
an isosurface modifier; I want the effect to value according to phi and
theta but be constant for all r.)
The obvious way to do this is to normalise the vector of (x, y, z) and
then multiply by r, which more or less becomes:
f_normal_x(x, y, z, r) = r * x / f_r(x, y, z)
f_normal_y(x, y, z, r) = r * y / f_r(x, y, z)
f_normal_z(x, y, z, r) = r * z / f_r(x, y, z)
(Possible typos/thinkos owing to posting past midnight...)
Now, I'm going to be using this in a single expression:
result(x, y, z, r) = f_bozo(f_normal_x(x, y, z, r), f_normal_y(x, y, z,
r), f_normal_z(x, y, z, r))
My question is: is Povray intelligent enough to calculate f_r(x, y, z)
once, or will it do it three times? If it's going to do it three times,
are there any clean strategies for optimising the function (or should I
just not worry about it)?
My worry is that calculating common values and then passing them in
makes writing modular functions very hard --- the logic gets spread
across all functions rather than being focused in specific areas. e.g.:
result2(x, y, z, r) = f_bozo(x*r, y*r, z*r)
result1(x, y, z, r, R) = result2(x/R, y/R, z/R, r)
result(x, y, z, r) = result1(x, y, z, r, f_r(x, y, z))
...which is much less easy to read.
--
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 22.07.11 01:14, David Given wrote:
> As part of my Insanely Complicated Tree function, I need to clip some
> (x, y, z) coordinates to a sphere of radius r. (I'm going to use it as
> an isosurface modifier; I want the effect to value according to phi and
> theta but be constant for all r.)
<snip>
> ...which is much less easy to read.
If you show the POV-Ray SDL, then I can tell you what will happen and how to
optimise it. From your post it is not clear if you are talking about macros
or functions as you say function, but use a syntax closer to a declare.
Thorsten
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 22/07/11 14:10, Thorsten Froehlich wrote:
[...]
> If you show the POV-Ray SDL, then I can tell you what will happen and
> how to optimise it. From your post it is not clear if you are talking
> about macros or functions as you say function, but use a syntax closer
> to a declare.
Functions (I'm missing out the Povray boilerplate for simplicity because
it's too verbose).
--
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 22.07.11 21:54, David Given wrote:
> On 22/07/11 14:10, Thorsten Froehlich wrote:
> [...]
>> If you show the POV-Ray SDL, then I can tell you what will happen and
>> how to optimise it. From your post it is not clear if you are talking
>> about macros or functions as you say function, but use a syntax closer
>> to a declare.
>
> Functions (I'm missing out the Povray boilerplate for simplicity because
> it's too verbose).
Well, as said, without the SDL I can't help as that is what in the end
determines how your functions are evaluated.
Thorsten
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 22/07/11 22:25, Thorsten Froehlich wrote:
[...]
> Well, as said, without the SDL I can't help as that is what in the end
> determines how your functions are evaluated.
I'm not looking to optimise this specific bit of code. I'm looking for
general strategies in how to optimise code in general.
For example: I assume that Povray parses functions into an AST, and then
evaluates them by traversing the tree. Once the AST has been
constructed, does it run any of the standard compiler optimisation
algorithms on this such as common subexpression elimination or constant
propagation?
e.g. in my original example, when evaluating result(), f_r() is
referenced three times with the same parameters. Is Povray clever enough
to spot this and only evaluate it once?
--
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 22.07.11 23:51, David Given wrote:
> On 22/07/11 22:25, Thorsten Froehlich wrote:
> [...]
>> Well, as said, without the SDL I can't help as that is what in the end
>> determines how your functions are evaluated.
>
> I'm not looking to optimise this specific bit of code. I'm looking for
> general strategies in how to optimise code in general.
>
> For example: I assume that Povray parses functions into an AST, and then
> evaluates them by traversing the tree. Once the AST has been
> constructed, does it run any of the standard compiler optimisation
> algorithms on this such as common subexpression elimination or constant
> propagation?
Constant folding will always happen, as long as they are next to each other
in the tree. This includes single-argument intrinsic functions. (sqrt, sin,
cos, tan, abs, etc.). Further, there is inline expansion for pow, min and max.
There are no higher-level optimisations, as there is no detection (nor a
complete list) of side effects some pattern functions do have (weel, had
before 3.7). Further, the syntax tree is only kept as long as needed, which
means as soon as the parser is done with a function.
Without knowing the specifics, most likely for your use the best way to
eliminate common subexpressions is to use multiple functions and pass the
subexpressions as arguments.
Thorsten
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
On 23/07/11 07:12, Thorsten Froehlich wrote:
[...]
> There are no higher-level optimisations, as there is no detection (nor a
> complete list) of side effects some pattern functions do have (weel, had
> before 3.7). Further, the syntax tree is only kept as long as needed,
> which means as soon as the parser is done with a function.
Hmm. Thanks. What's actually used to evaluate the function, then? Is it
byte-compiled?
> Without knowing the specifics, most likely for your use the best way to
> eliminate common subexpressions is to use multiple functions and pass
> the subexpressions as arguments.
Yes, that's what I'm doing --- it's brittle and rather verbose. (A lot
of my functions take (x, y, z) coordinates, clip them to a sphere, and
actually do a texture calculation based the clipped value. It's a bit
painful.)
I don't suppose you know what happened to the old POVMan patch to allow
Renderman shader functions from Povray, do you? All the references I've
found appear to be dead...
--
┌─── dg@cowlark.com ─────
http://www.cowlark.com ─────
│
│ "I have a mind like a steel trap. It's rusty and full of dead mice."
│ --- Anonymous, on rasfc
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Am 23.07.2011 13:12, schrieb David Given:
> Hmm. Thanks. What's actually used to evaluate the function, then? Is it
> byte-compiled?
It does use a VM, yes.
>> Without knowing the specifics, most likely for your use the best way to
>> eliminate common subexpressions is to use multiple functions and pass
>> the subexpressions as arguments.
>
> Yes, that's what I'm doing --- it's brittle and rather verbose. (A lot
> of my functions take (x, y, z) coordinates, clip them to a sphere, and
> actually do a texture calculation based the clipped value. It's a bit
> painful.)
My favorite solution to such issues is to replace, e.g.,
#declare F = function(a) { sin(a) + cos(a) + sin(a)*cos(a) }
with
#declare F_ = function(sina,cosa) { sina + cosa + sina*cosa }
#declare F = function(a) { F_(sin(a),cos(a)) }
The idea is to create a helper function where all the multiply-used
sub-expressions are substituted by parameters, and have a main function
that computes these sub-expressions and passes them to that helper
function. I think it's sufficiently easy to read if you use good names
for the sub-expressions.
I usually use an added underscore for such functions, but you might also
call them "F2", "F_sub", or whatever fits your taste.
For instance, for your example I might use
#declare f_normal_x_ = function(x,r,fr) { r * x / fr }
#declare f_normal_y_ = function(y,r,fr) { r * y / fr }
#declare f_normal_z_ = function(z,r,fr) { r * z / fr }
#declare result_ = function(x,y,z,r,fr) { f_bozo(
f_normal_x_(x,r,fr), f_normal_y_(y,r,fr), f_normal_z_(z,r,fr)
)}
#declare result = function(x,y,z,r) { result_(x,y,z,r, f_r(x,y,z)) }
BTW, note that f_normal_x_, f_normal_y_ and f_normal_z_ are actually
redundant; you could just as well use
#declare f_normal_ = function(axis,r,fr) { r*axis / fr }
#declare result_ = function(x,y,z,r,fr) { f_bozo(
f_normal_(x,r,fr), f_normal_(y,r,fr), f_normal_(z,r,fr)
)}
#declare result = function(x,y,z,r) { result_(x,y,z,r, f_r(x,y,z)) }
However, depending on circumstances I might still use separate
functions, to have a 1:1 mapping between original functions and helper
functions which might improve legibility.
Not sure if that boils down to the same as your own attempt - I didn't
try to understand how your set of functions works, as they're indeed not
excessively easy to read ;-). In my experience, good naming of the
sub-expression substitution parameters is essential for legibility.
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
| |
|
|
Le 2011/08/04 18:00, clipka a écrit :
>
> My favorite solution to such issues is to replace, e.g.,
>
> #declare F = function(a) { sin(a) + cos(a) + sin(a)*cos(a) }
>
> with
>
> #declare F_ = function(sina,cosa) { sina + cosa + sina*cosa }
> #declare F = function(a) { F_(sin(a),cos(a)) }
>
> The idea is to create a helper function where all the multiply-used
> sub-expressions are substituted by parameters, and have a main function
> that computes these sub-expressions and passes them to that helper
> function. I think it's sufficiently easy to read if you use good names
> for the sub-expressions.
>
You are probably also geting some performance improvement that way: The
sin() and cos() functions are now only evaluated once, then you pass the
returned values to the helper function.
Alain
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
|
|