Tech Off Thread

10 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Performance Programming in C# (calling C# guru's)

Back to Forum: Tech Off
  • User profile image
    MrJelly

    I want to perform from intensive 3D calculations (Photon Tracing). I generally do this type of thing in C++, but I would like to give C# a go, however, I am having some performance and language problems in regards to temporary object and passing them around. For example, consider the following simple code in C++. "normalized" is a stack variable and is allocated quickly and then passed to the "dot" function as a reference (also fast).

    double angle(Vector3D& normal, Vector3D& ray)
    {
       Vector3D normalized ;
       normalized.normalize(ray) ;
       return (normal.dot(normalized)) ;
    }


    If I write this in C# I have to do something like the following...

    double angle(Vector3D normal, Vector3D ray)
    {
      Vector3D normalized = new Vector3D();
      normalized.normalize(ray) ;
      return (normal.dot(normalized)) ;
    }


    If I make Vector3D a class then the "new Vector3D()" function slows the operation down by about 170%, as it requires the creation of a new object. If I make it a struct then things slow down as well as all the Vector3D how get passed by value which produces a lot of copying.

    I found that if I create the normalized object once, when the container class is created, the program only runs about 110% of the C++ (which I could live with) however, the code is not thread safe (which I can not live with). Ofcourse, this function is only one of may and I'm just using it to illustrate the issue.

    Is there a way to have a class allocated on the stack or is there a way to pass a struct by reference?

    Any alternative ways?

    Cheers!


  • User profile image
    Minh

    Look up the "ref" keyword. BTW, why do you say it's not thread safe? How are you using multi-threading?

  • User profile image
    MrJelly

    Cool! "ref" sounds like it will work for structs... But want I really want to do is create classes on the stack Smiley... any ideas?

    In regards to threads... if I did something like this...

    class Surface
    {
      Vector3D normalized = new Vector3D();
      double angle(Vector3D normal, Vector3D ray)
      {
        normalized.normalize(ray) ;
        return (normal.dot(normalized)) ;
      }
    }

    and called angle() from multiple threads on the same object (as I don't want to have multiple copies of Surface, one for each thread) then wouldn't both threads use normalised as their work variable and enter a race condition? That's what happens in Java and C++... is C# different?





  • User profile image
    MitchDenny

    Hi MrJelly (cool name BTW),

    Structs are actually your ticket. They are a first class .NET type designed specifically for high performance scenarios like yours.

    If for some reason you can't live with structs (there are lots of OO reasons), then you might like to consider using the [ThreadStatic] attribute which can make the normalized field static on a per-thread basis. That way somewhere in the initialisation logic for each thread you just need to prime the variable so it is created once for each thread.

    For example:
    public class Surface
    {
      [ThreadStatic]
      private static Vector3D m_Normalized;

      public void Init()
      {
        if (Surface.m_Normalized == null)
        {
          Surface.m_Normalized = new Vector3D();
        }
      }

      public double Angle(Vector3D normal, Vector3D ray)
      {
        Surface.m_Normalised.Normalize(ray);
        return normal.Dot(Surface.m_Normalized);
      }
    }

    // Note, I didn't compile this or anything.

  • User profile image
    MrJelly

    Thanks everyone for all the help on this... C# has some cool features! Smiley

    Cheers!

  • User profile image
    amotif

    MrJelly wrote:
    In regards to threads... if I did something like this...

    class Surface
    {
      Vector3D normalized = new Vector3D();
      double angle(Vector3D normal, Vector3D ray)
      {
        normalized.normalize(ray) ;
        return (normal.dot(normalized)) ;
      }
    }


    One thing that may be constraining your thinking here is how you appear to have implemented normalize(), which modifies its instance, right?  If normalize() returned a new struct you wouldn't be in a pickle regarding thread safety.  E.g.,

    class Surface
    {
      double angle(Vector3D normal, Vector3D ray)
      {
        Vector3D normalized = ray.normalize();
        return normal.dot(normalized);
      }
    }

    Of course that depends on whether you can make it performant to your satisfaction.  [Edit:] If you do go this route, you'll probably want to treat Vector3D as immutable over all its operations.

  • User profile image
    Minh

    [ThreadStatic] looks very useful.

    but if Vector3D is a struct, couldn't you do something like:

    public double Angle(Vector3D normal, Vector3D ray)
    {
       Vector3D normalized;
       normalized.Normalize(ray);
       return normal.Dot(normalized);
    }

    or better yet, if Vector3D can self-normalize:

    public double Angle(Vector3D normal, Vector3D ray)
    {
       return normal.Dot(ray.Normalize());
    }


    But is "normal" the Surface's normal? If so, that's odd that Surface needs somebody else to tell its normal. (but I don't know your code -- just curious)

  • User profile image
    MrJelly

    The function was given as an example of a problem with temporary objects (the implementation of the function is not the issue, nor is it correct… I admit that). Sorry if that caused some confusion…

    If the following code where used…

    public double Angle(Vector3D normal, Vector3D ray)
    {
       return normal.Dot(ray.Normalize());
    }

    My understanding of C# is that if Vector3D is a class then the function ray.normalize() will reference the original object and modify it (not good). Alternatively, if Normalize() returns a new normalised ray, then it will have to create a new Vector3D e.g. “return (new Vector3D(….))” and the performance problem is back.

    If Vector3D is a struct (and I don’t pass it using “ref”) then it gets passed by value with means copies of the entire object get made which is also a performance problem.

    The issue is that when programming for performance (where ever cycle counts) you need to avoid (1) the new() operation and (2) minimise memory copying. I think the using the “ref” operation (thanks minh) is my best bet.

    Cheers

  • User profile image
    amotif

    Absolutely.

    Regarding the threading issue, you can a) make your type immutable so threading isn't an issue; b) share one instance of 'normalized' for performance and suffer through synchronization; c) use one instance of 'normalized' per calling thread; d) or do something else altogether.

    Yes, in C# we have to deal with the same thread safety design issues we deal with in C++ and Java.

  • User profile image
    Frank Hileman

    Right now C# doesn't optimize temporary structs well, but hopefully it will in the future. They are still faster than classes in many situations because GC always gets new memory, decreasing locality of reference.

    One thing to watch out for: don't put any performance critical code in a MarshsalByRefObject derived class: that means Windows.Forms.Control, Form, UserControl, etc. MarshsalByRefObject kills inlining and can have a bad impact.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.