January 18, 2007
Bill Baxter Wrote:
> D still not as fast as the C++, but close.

I refuse to analyze this any further.

On comparing the implementations of Primary, I noticed, that the OP has introduced a constructor which executes "new Material". There is no "new" in the cpp-version of Primary but a "SetMaterial" function.

On deleting the new expression in the D-version an exception was raised on executing the newly compiled binary.

Astonishingly grepping over the .cpp and .h -files with agent ransack no calls of "SetMaterial" were delivered---but "GetMaterial" is called---which uses the unset "Material" pointer. :-(

Conclusion: at least one of the following is true
1) I have near to no ability to understand c++
2) the c++-version is lucky to run at all

In case of 2) the OP has silently changed the algorithm on porting to D.
January 18, 2007
%u wrote:
> Bill Baxter Wrote:
>> D still not as fast as the C++, but close.
> 
> I refuse to analyze this any further.
> 
> On comparing the implementations of Primary, I noticed, that the OP has introduced a constructor which executes "new Material". There is no "new" in the cpp-version of Primary but a "SetMaterial" function.
> 
> On deleting the new expression in the D-version an exception was raised on executing the newly compiled binary.
> 
> Astonishingly grepping over the .cpp and .h -files with agent ransack no calls of "SetMaterial" were delivered---but "GetMaterial" is called---which uses the unset "Material" pointer. :-(
> 
> Conclusion: at least one of the following is true
> 1) I have near to no ability to understand c++ 2) the c++-version is lucky to run at all
> 
> In case of 2) the OP has silently changed the algorithm on porting to D.

It's case 1) I'm afraid.  :-)

Material is a by-value member of Primitive in the C++ version.  This means it acts more like a D struct than a D class.  GetMaterial calls return a pointer to the Material that's part of the class, and it will have been initialized implicitly by the Primitive constructor using whatever Material's default constructor does.

So the C++ code is ok.  But it's not clear why Material became a class in the D version rather than a struct.

--bb
January 18, 2007
Lionello Lunesu Wrote:
> No, it can't.. Passing a struct by ref will result in unexpected behavior if it changes in some other thread. As always, the default should be safe no matter what, and that means copying the struct's contents.
That's right for structs.

> I guess a new modifier like "byref" is the only option..
"byref" is the wrong word here because the real meaning is "value parameter that is not assigned to". Thus "const" is right and already reserved.
January 18, 2007
Bill Baxter Wrote:
> So the C++ code is ok.  But it's not clear why Material became a class in the D version rather than a struct.
Thx. I did not notice, that "Material" is a struct in the cpp-version.

This shows however, that programmers still are not following engeering principles: no technical documentation of the port is given and no one complains.

Instead several people are eager searching flaws in the reference implementation of D for which there is also no technical documentation :-(
January 18, 2007
%u wrote:
> Bill Baxter Wrote:
>> So the C++ code is ok.  But it's not clear why Material became a
>> class in the D version rather than a struct.
> Thx. I did not notice, that "Material" is a struct in the cpp-version.
> 
> This shows however, that programmers still are not following engeering principles: no technical documentation of the port is given and no one complains.
> 
> Instead several people are eager searching flaws in the reference implementation of D for which there is also no technical documentation :-(

Let's assume that the OP was earnestly trying to make the C++ and D code comparable... If so, then this exercise did point out some areas where D needs attention. In the final analysis, it's "good faith" ports like these that are going to satisfy whether or not D "is as fast or faster" than C++, and in many cases, whether or not people will make the switch. If it requires a lot of code modifications over and above a simple port to make D comparable in performance, people will shy away from D.

C++ is still being used for new development in large part because of great performance, and the language constructs ("expressibility") that make that possible. One area where this keeps popping up in D is being able to pass structs 'byref' w/o necessarily using 'inout'.
January 18, 2007
%u wrote:
> Lionello Lunesu Wrote:
>> No, it can't.. Passing a struct by ref will result in unexpected behavior if it changes in some other thread. As always, the default should be safe no matter what, and that means copying the struct's contents.
> That's right for structs.
>  
>> I guess a new modifier like "byref" is the only option..
> "byref" is the wrong word here because the real meaning is "value parameter that is not assigned to". Thus "const" is right and already reserved.

That's Ok as long as all D compilers will most likely rightly determine whether or not to pass the const byref as an optimization. Since this is probably not realistic, I think something like 'byref' is called for. There's been a great debate as to whether or not 'const' is actually enforceable, and unless it is, it would not really be of any value as an optimizer hint (like const can't be counted on as an optimizer hint for C++).
January 18, 2007
When comparing the generated assembly from the dmc exe with the one from dmd, I noticed that the D one had many "movsd; movsd; movsd;" sequences (obviously copying of one vector3 to another). I could not find these in the C version.

Maybe the DMC is better at register aliasing (or what's it called) than DMD? I mean, DMD's actually moving data around, where DMC simply changes the names of the data?

Only W. knows.

L.
January 18, 2007
Bill Baxter wrote:
> You left out changing Intersect's Ray argument to be inout.  And generally all Ray (and possibly vector3 parameters) to be inout to avoid  the cost of copying them on the stack.

Sorry Bill, that was unintentional. I changed the Raytrace's Ray argument, but forgot the Interect's Ray argument

> 
> Also converting vector expressions like
>       vector3 v = a_Ray.origin - m_Centre;
> to
>       vector3 v = a_Ray.origin;
>       v -= m_Centre;
> 
> makes a difference.  Changing that one line in the Sphere.Intersect routine changes my runtime from 12.2 to 14.3 sec.

That helps too. The time is now down to approx. 10 sec. (2 times slower than C++).

> 
> Interestingly the same sort of transformation to the C++ code didn't seem to make much difference.  It could be related in part to the C++ vector parameters on the operators all taking const vector& (references) vs the D ones being just plain vector3.  Chaging all the operators in the D version to inout may help speed too.

I've tried this "temporary value elimination" optimization in other areas of the code, but the effect is minimal. Based on my experience with Java, I think C++ is very good using return value optimization to eliminate temporary objects.

Thanks,
  Bradley
January 18, 2007
Lionello Lunesu wrote:
> When comparing the generated assembly from the dmc exe with the one from dmd, I noticed that the D one had many "movsd; movsd; movsd;" sequences (obviously copying of one vector3 to another). I could not find these in the C version.
> 
> Maybe the DMC is better at register aliasing (or what's it called) than DMD? I mean, DMD's actually moving data around, where DMC simply changes the names of the data?
> 
> Only W. knows.
> 
> L.

Hmm.  I hope he knows...and is paying attention to this thread.

--bb
January 18, 2007

Dave wrote:
> %u wrote:
>> Bill Baxter Wrote:
>>> So the C++ code is ok.  But it's not clear why Material became a
>>> class in the D version rather than a struct.
>> Thx. I did not notice, that "Material" is a struct in the cpp-version.
>>
>> This shows however, that programmers still are not following engeering principles: no technical documentation of the port is given and no one complains.
>>
>> Instead several people are eager searching flaws in the reference implementation of D for which there is also no technical documentation :-(
> 
> Let's assume that the OP was earnestly trying to make the C++ and D code comparable... If so, then this exercise did point out some areas where D needs attention. In the final analysis, it's "good faith" ports like these that are going to satisfy whether or not D "is as fast or faster" than C++, and in many cases, whether or not people will make the switch. If it requires a lot of code modifications over and above a simple port to make D comparable in performance, people will shy away from D.

Thanks for defending me, Dave. You are correct in assuming that I am trying to make the C++ and D code comparable. I'm not trying to sabotage the D effort. In fact, I would very much like to see the D code perform significantly better than C++. I'm just trying to learn how to write high-performance D code.

Thanks,
  Bradley