Jump to content
  • Advertisement
Sign in to follow this  
Skiller

Unity [Solved] Macro to replace namespaced function

This topic is 3536 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm re-writing my game engine atm (I made the stupid mistake of underestimating the difficulty of retrofitting thread safety) and decided I should take the opportunity to pretty up my code by using namespaces instead of 2-3 letter prefixes for each system. I'm also wanting to speed a few heavily used things up a bit like my math library but have run into a bit of a problem, I want to use macros for release builds instead of functions because they are faster but having the debug functions in namespaces is making things difficult :(. Is there a way to use macros to fake namespaces so something like the following would work?
namespace Math
{
#ifdef _DEBUG
    static float Max(const float value1, const float value2) {return ((value1 > value2) ? value1 : value2);}
#else
    #define Max(max, val) (((max) < (val)) ? (val) : (max))
#endif
};


void SomeFunction()
{
    float max = Math::Max(0.1f, 0.2f);
}

Obviously it all works fine for debug but in release it wont compile since macros aren't affected by namespaces :(. BTW before anyone says "inline functions are just as fast as macros" I have been profiling and no matter what I do the macro version will run nearly 2 times faster than the best version of the function I could come up with and in many situations as much as 10-100 times faster (like when using constants which will get compiled down to just an assignment). Though it is possible I'm doing something wrong that's preventing it inlining properly and if so then awesome, I can just use the much nicer/safer function rather than macros but I doubt that'll be the case :(. Thanks Edit: Solution is to enable optimization compiler switches and use functions instead. [Edited by - Skiller on October 12, 2008 5:30:15 AM]

Share this post


Link to post
Share on other sites
Advertisement
No, it's not possible; macros aren't aware of namespaces in any way.

Also, have you been profiling with full optimizations enabled? I wouldn't be surprised if the macro version were that faster in a debugging, unoptimized build -- seeing that kind of results in fully-optimized build stripped of any debugging seems rather strange to me.

Also, you don't need to write your own Math::Max, it's already been done for you: std::max.

Share this post


Link to post
Share on other sites
I'm gonna say it anyway; use the inline function. Yes, it is likely that you are doing something wrong if you get a 10-100 times difference, or you should get a decent compiler. For example, whole program optimization in Visual studio of later editions should have no problem inlining that function call.

Share this post


Link to post
Share on other sites
Quote:
Original post by Skiller(like when using constants which will get compiled down to just an assignment).


Which compiler are you using?

Share this post


Link to post
Share on other sites
Quote:
Original post by Skiller
BTW before anyone says "inline functions are just as fast as macros" I have been profiling and no matter what I do the macro version will run nearly 2 times faster than the best version of the function I could come up with and in many situations as much as 10-100 times faster (like when using constants which will get compiled down to just an assignment). Though it is possible I'm doing something wrong that's preventing it inlining properly and if so then awesome, I can just use the much nicer/safer function rather than macros but I doubt that'll be the case :(.

I'd like to see your test cases. Got an example where the macro version is faster than the inlined one?

Share this post


Link to post
Share on other sites
I think your basic problem with any performance metrics you might be trying to use is that your function isn't actually an inline function. Inline functions use the inline keyword or get declared inside the body of class definitions. What you've got a non-inline function declared as static. Static will make it link, but it'll also create a separate version of the function in each and every source file that uses that function definition. This leads to code bloat, which will also adversely affect performance.

Share this post


Link to post
Share on other sites
Here is the exact code I use for this if you can spot why it might not be inlineing properly then please let me know as I would much prefer to use functions. BTW std::Max is actually slower than the function I wrote, but only by an insignificant amount ;).

UtMath.h
[source="cpp"]#ifndef UT_MATH_H
#define UT_MATH_H


///////////////////////////////////////////////////////////////////////////////
/// Various math constants and functions.
///////////////////////////////////////////////////////////////////////////////
namespace Math
{
//Variouse other function and constants not relevant edited out

#define maxDefine(max, val) (((max) < (val)) ? (val) : (max))

inline float Max(const float& value1, const float& value2){return ((value1 > value2) ? value1 : value2);}
};


#endif //UT_MATH_H



Main.cpp (just shoved in here as a temperary measure while profiling)
[source="cpp"]for (UInt32 pass = 0; pass < 10; ++pass)
{
float val1 = pass * 0.01f;
float val2 = pass * 0.02f;
UtProfiler_BeginLoad("std::max");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = std::max(val1, val2);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Macro");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = maxDefine(val1, val2);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Function");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = Math::Max(val1, val2);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Function");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = Math::Max(val1, val2);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Macro");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = maxDefine(val1, val2);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("std::max");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = std::max(val1, val2);
}
UtProfiler_EndLoad();
}



I mixed up the order like that to see if it might have been a cache thing but results were still very consistent.
The profiler just does a QueryPerformanceCounter in UtProfiler_BeginLoad then another QueryPerformanceCounter in UtProfiler_EndLoad and traces out the difference.
I'm using a modder build config which I created, it's a copy of the release build config but with a _MODDER #define set that turns on all the profiling, asserts, memory tracking and other tools I have in debug but with compiler optimizations on, I'm also using the VS2008 compiler. In case you are wondering I plan to ship the modder build so content modders will get a heap of extra info on any potential problems their content may cause, and also if people are getting crashes then they can run the modder build and it'll probably throw an assert or trace out some extra info to help me track down the bug easier :).

Anyway the results:
Load complete: std::max, Completed in: 0.00483
Load complete: Macro, Completed in: 0.00215
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00441
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00442
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00225
Load complete: Function, Completed in: 0.00444
Load complete: Function, Completed in: 0.00439
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00222
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00440
Load complete: Macro, Completed in: 0.00234
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00219
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00441
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00460
Load complete: Macro, Completed in: 0.00221
Load complete: Function, Completed in: 0.00446
Load complete: Function, Completed in: 0.00440
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00452
Load complete: Macro, Completed in: 0.00212
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00442
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00234
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00440
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00219
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00440
Load complete: Macro, Completed in: 0.00235
Load complete: std::max, Completed in: 0.00449
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00227
Load complete: Function, Completed in: 0.00443
Load complete: Function, Completed in: 0.00441
Load complete: Macro, Completed in: 0.00233
Load complete: std::max, Completed in: 0.00447
Load complete: std::max, Completed in: 0.00451
Load complete: Macro, Completed in: 0.00212
Load complete: Function, Completed in: 0.00442
Load complete: Function, Completed in: 0.00442
Load complete: Macro, Completed in: 0.00233
Load complete: std::max, Completed in: 0.00447



Fairly consistently Macro > Function > std::max in terms of speed. If, as seems to be the case, there is no way to get the macros to work with namespaces I'll just use my function for both since CPUs should be fast enough for it to not make too big an impact on frame rate and I'd rather the type safety if I can get it, I'll also probably templatize the function if that doesn't have too big an impact on speed (which it shouldn't as far as I'm aware).



Edit: I re-did my profiling using the fast function and yer my results aren't anywhere near the 10-100 times faster when using constants I stated earlier, those figures must have been for the old function I was using that didn't seem to inline. But in an unexpected result but the function and std::max *increased* the time it took when using constants, the macro decreased to the point that the majority of the time is probably the time spent looping.
Main.cpp using constants:
[source="cpp"]for (UInt32 pass = 0; pass < 10; ++pass)
{
float val1 = pass * 0.01f;
float val2 = pass * 0.02f;
UtProfiler_BeginLoad("std::max");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = std::max(0.1f, 0.2f);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Macro");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = maxDefine(0.1f, 0.2f);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Function");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = Math::Max(0.1f, 0.2f);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Function");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = Math::Max(0.1f, 0.2f);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("Macro");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = maxDefine(0.1f, 0.2f);
}
UtProfiler_EndLoad();
UtProfiler_BeginLoad("std::max");
for (UInt32 i = 0; i < 1000000; ++i)
{
float maxVal = std::max(0.1f, 0.2f);
}
UtProfiler_EndLoad();
}


Results of using constants:
Load complete: std::max, Completed in: 0.00512
Load complete: Macro, Completed in: 0.00178
Load complete: Function, Completed in: 0.00580
Load complete: Function, Completed in: 0.00516
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00521
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00581
Load complete: Function, Completed in: 0.00517
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00523
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00568
Load complete: Function, Completed in: 0.00517
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00524
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00587
Load complete: Function, Completed in: 0.00516
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00516
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00555
Load complete: Function, Completed in: 0.00516
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00503
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00582
Load complete: Function, Completed in: 0.00517
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00568
Load complete: std::max, Completed in: 0.00522
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00569
Load complete: Function, Completed in: 0.00518
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00519
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00601
Load complete: Function, Completed in: 0.00517
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00568
Load complete: std::max, Completed in: 0.00521
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00567
Load complete: Function, Completed in: 0.00517
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567
Load complete: std::max, Completed in: 0.00519
Load complete: Macro, Completed in: 0.00177
Load complete: Function, Completed in: 0.00559
Load complete: Function, Completed in: 0.00516
Load complete: Macro, Completed in: 0.00177
Load complete: std::max, Completed in: 0.00567

Share this post


Link to post
Share on other sites
Quote:
Original post by Skiller
But in an unexpected result but the function and std::max *increased* the time it took when using constants, the macro decreased to the point that the majority of the time is probably the time spent looping.
The macro with constants probably caused the entire loop to be optimised out, so those results are pretty much useless.

Share this post


Link to post
Share on other sites
Problem is that you used a constant, and the compiler is free to optimize that out:

maxDefine(1, 2)
// will become
1 > 2 ? 1 : 2
// will become
2

And given that you never even do anything with the float itself, the compiler should technically be free to get rid of the whole loop.

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
Quote:
Original post by Skiller
But in an unexpected result but the function and std::max *increased* the time it took when using constants, the macro decreased to the point that the majority of the time is probably the time spent looping.
The macro with constants probably caused the entire loop to be optimised out, so those results are pretty much useless.


What's faster is faster that's all there is to it, it's a good thing that it gets optimized out and it's good to see how much faster it is in that case so I don't understand how those results are useless. If constants were used in the code then the results clearly show that a macro is the fastest option, though obviously it'd be much rarer for that to be the case which is why I'm only really concerned with the common use case of using variables.

Quote:
Original post by agi_shi
Problem is that you used a constant, and the compiler is free to optimize that out:

maxDefine(1, 2)
// will become
1 > 2 ? 1 : 2
// will become
2

And given that you never even do anything with the float itself, the compiler should technically be free to get rid of the whole loop.


It gets compiled down to just this:
			float maxVal = maxDefine(0.01f, 0.02f);
0040D6E9 fld dword ptr [__real@3ca3d70a (40F958h)]
0040D6EF fstp dword ptr [maxVal]

I don't understand assembly but that looks like it's probably just an assignment which would prove your theory, except compiling out the loop as that still gets done.

But as I said if it gets compiled out then that's the best possible solution as far as speed goes so that's not a problem, it just clearly shows macros are the best solution when using constants.



Anyway I'm not concerned about use with constants, I just put it there for those who were interested and to clear up the erroneous statement that I was getting 10-100 times the speed with constants which it's quite clear I'm not anymore since the function is much faster than when I last checked :).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By D34DPOOL
      Edit Your Profile D34DPOOL 0 Threads 0 Updates 0 Messages Network Mod DB GameFront Sign Out Add jobEdit jobDeleteC# Programmer for a Unity FPS at Anywhere   Programmers located Anywhere.
      Posted by D34DPOOL on May 20th, 2018
      Hello, my name is Mason, and I've been working on a Quake style arena shooter about destroying boxes on and off for about a year now. I have a proof of concept with all of the basic features, but as an artist with little programming skill I've reached the end of my abilities as a programmer haha. I need someone to help fix bugs, optomize code, and to implent new features into the game. As a programmer you will have creative freedom to suggest new features and modes to add into the game if you choose to, I'm usually very open to suggestions :).
      What is required:
      Skill using C#
      Experience with Unity
      Experience using UNET (since it is a multiplayer game), or the effort and ability to learn it
      Compensation:
      Since the game currently has no funding, we can split whatever revenue the game makes in the future. However if you would perfer I can create 2D and/or 3D assets for whatever you need in return for your time and work.
      It's a very open and chill enviornment, where you'll have relative creative freedom. I hope you are interested in joining the team, and have a good day!
       
      To apply email me at mangemason@yahoo.com
    • By davejones
      Is there a way to automatically change the start position of an animation? I have a bunch of animations set up on 3D models in unity. The issue is that I need to move the 3D models, however when I do so the animation start positions are not updated and I have to do it manually.

      Changing the transform of key frames is time consuming with the amount of animations I have, so I was wondering if there was a way to do it automatically?
    • By MoreLion
      hey all! We are looking for members for our Unity horror game! 
      Here’s the story:
      After a deadly virus plunges the world into chaos killing 85% of the human population there are now what they call “zones” these zones are watched very closely by the surviving government, people are checked every day for the virus, even if you touch the spit or any human waste or fluids of the victim who is infected, you will die. But one day, people in the west zone start to go missing, 1 woman goes outside the walls to uncover the mystery, is there more to the virus than meets the eye?, That is where your story starts.
      This game is not a long development game, I have loads other game ideas,
      I will also allow you to have a bit of creative freedom if you wish to add or share a idea!
      And no, it’s not a zombie game lol I feel like zombie games are too generic, in this game you will encounter terrifying beasts!
      There is some concept art one of our concept artists have made
      If interested email liondude12@gmail.com
    • By Canadian Map Makers
      GOVERNOR is a modernized version of the highly popular series of “Caesar” games. Our small team has already developed maps, written specifications, acquired music and performed the historical research needed to create a good base for the programming part of the project.

      Our ultimate goal is to create a world class multi-level strategic city building game, but to start with we would like to create some of the simpler modules to demonstrate proof of concept and graphical elegance.

       

      We would like programmers and graphical artists to come onboard to (initially) create:

      A module where Province wide infrastructure can be built on an interactive 3D map of one of the ancient Roman Provinces.
      A module where city infrastructure can be built on a real 3D interactive landscape.
      For both parts, geographically and historically accurate base maps will be prepared by our team cartographer. Graphics development will be using Blender. The game engine will be Unity.

       

      More information, and examples of the work carried out so far can be found at http://playgovernor.com/ (most of the interesting content is under the Encyclopedia tab).

       

      This project represents a good opportunity for upcoming programmers and 3D modeling artists to develop something for their portfolios in a relatively short time span, working closely with one of Canada’s leading cartographers. There is also the possibility of being involved in this project to the point of a finished game and commercial success! Above all, this is a fun project to work on.

       

      Best regards,

      Steve Chapman (Canadian Map Makers)

       
    • By Scouting Ninja
      So I have hundreds of moving objects that need to check there speed. One of the reasons they need to check there speed is so they don't accelerate into oblivion, as more and more force is added to each object.
      At first I was just using the Unity vector3.magnitude. However this is actually very slow; when used hundreds of times.
      Next I tried the dot-product check:  vector3.dot(this.transform.foward, ShipBody.velocity) The performance boost was fantastic. However this only measures speed in the forward direction. Resulting in bouncing objects accelerating way past the allowed limit.
       
      I am hoping someone else knows a good way for me to check the speed with accuracy, that is fast on the CPU. Or just any magnitude calculations that I can test when I get home later.
       
      What if I used  vector3.dot(ShipBody.velocity.normalized, ShipBody.velocity)?
      How slow is it to normalize a vector, compared to asking it's magnitude?
    • By Ds ds
      Hi, my name is Andres, I'm a programmer with a technician degree and a Diploma in C#, looking for a project in Unity to start my career in game development. I don't do it for a paid but a recognition and start a portfolio, preferably a 2D game. Thanks for read, have a nice day. 
       
    • By Victor Rodriguez
      Hi there! Is the first time that I'm posting here so I'm sorry if I'm doing it wrong ha. 
      So here it comes, my doubt is, I'm doing a game with different levels, each of these levels in one different scene. Each scene contains to cameras that you can change pressing a button. Everything works fine. 
      The only problem is that I would like it to look a bit more professional, and I would like that if you finish the level with camera2, the next level start the same way. I've been thinking about using dontdestroyonloadon both cameras, but obviously this cameras need to be attached to the player to make the movement work, what do you recommend? Sorry If I've explained it in a messy way, and feel free to dm me for anything. Thanks in advance! 
    • By Ike aka Dk
      Hello everyone 
      I am a programmer from Baku.
      I need a 3D Modeller for my shooter project in unity.I have 2 years Unity exp.
      Project will paid when we finish the work 
      If you interested write me on email:
      mr.danilo911@gmail.com
    • By markoal
      Hi,
      I'm Unity developer from Croatia and I'm looking to work on the paid project in my spare time.
      I have 5+ years of experience in Unity and I'm familiar with almost anything, including all platforms (also Switch, PS4 and Xbox).
      Feel free to contact me.
    • By bartekm777
      Hello
      About me
      Lvl 28   Programmer (day job: non-gamedev-programmer, making games as a hobby for about 2 years) Some vector art experience - tried to make some assets on my own using vector software and scripts   Some design experience (designing my own games ) About game
      Turn-based fantasy rpg inspired by games like Heroes 3 (also WoG mod), NEO Scavenger, Battle Brothers I would like to create easy to use editor for creating custom scenarios (similar to the one from Heroes 3) World and story are clean slate, I did some drafts but I'm not good at it so it's possibly subject to change I decided to create graphics using vector software + scripts to make it faster (rpg's tend to have lots of assets), also it's more precise and easier to create tileable graphics (for example: rivers, paths) No sound/music work has been done yet Who do I look for?
      Definitely someone with 2d art skills  I would like to focus more on programming 2D animator (skletal animations are preferred) Additional programmer could make development faster Someone for creating sounds/music/both It's a hobby project, I work on it in my free time. In case the project make it to the finish line and get shipped  - I can offer rev-share  
      Below should be few screens of what I already did (about 2 months of work) - some graphics, editor prototype screenshot and game prototype screenshot




  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631352
    • Total Posts
      2999487
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!