Sign in to follow this  
cronocr

Unity Optimizing code statements into expressions?

Recommended Posts

cronocr    756
Hi! I'm looking for ideas on how to convert code into expressions in C# for Unity. We have this basic list of statements:
 
Simple statements:
  • assignment: A:= A + 5
  • call: CLEARSCREEN()
  • return: return 5;
 
 
Compound statements:
  • if-statement: if A > 3 then WRITELN(A) else WRITELN("NOT YET"); end
  • switch-statement: switch (c) { case 'a': alert(); break; case 'q': quit(); break; }
  • while-loop: while NOT EOF DO begin READLN end
  • do-loop: do { computation(&i); } while (i < 10);
  • for-loop: for A:=1 to 10 do WRITELN(A) end
 
 
The expressions that replace these statements should be chained, for example using And operators (expression1 && expression2 && .. expresionN), so the order of execution is respected. Also the ?: operator is allowed.
 
Assignment
 
If we have this statement:
 
int a = 100;
 
Can be converted into:
 
((a = 100) == a)
 
Yet not perfect, since the comparison is not optimized in IL code. I also tried:
 
((a = 100) is int)
 
This throws a warning, the comparison is optimized but the assignment is removed too. Any other idea that only produces the assignment in IL code?
 
Call
 
A call is automatically converted into a expression, right? Well, not exactly. How do you chain a void function?
 
Also if you pass parameters by reference, you will need a variable external to the expression.
 
Return
 
This one is directly converted:
 
return 5;
(5)
 
If and Switch statements
 
The ?: operator replaces them:
 
if (a == 5) { b = "yes"; } else { b = "no"; }
((a == 5) ? "yes" : "no")
 
While, Do and For loops
 
Loop unwinding could be used here, if the number of iterations is fixed. Any ideas for variable length loops?

Share this post


Link to post
Share on other sites
cronocr    756

Because C# doesn't support code inlining, and converting statements into expressions will remove boxing/unboxing which is pretty expensive and fragments the heap (in Unity this causes brain cancer), will remove calls to functions, and will allow the compiler to optimize some of the code of the inlined routine. I built a code processor that inlines C# code, so the optimization will be deeper if I can convert more statements smile.png

Edited by cronocr

Share this post


Link to post
Share on other sites
frob    44920

How is this actually slowing your program?

 

How is this something that actually needs a programmer to optimize it?

 

 

 

You are right that boxing is somewhat slow, so DON'T DO IT.  If you end up needing to routinely convert integers and bools into objects, you are likely doing something wrong at the algorithm level.  

 

Similarly, the 'is' operator is not exactly fast, and its presence is a generally symptom of a more significant fundamental design problem.  Casting an object to some type and then discarding the results is horrible anyway; if you cannot fix your algorithm's underlying problem that requires the cast, at least have the decency to perform the cast with 'as' and keep the successful results around.

 

Next up, chaining doesn't necessarily mean better performance -- each item is dependent on the previous results which is bad for the pipeline.  You can get pipeline bubbles or poor use of speculative execution and branch prediction if you make it too tight.  On modern hardware keeping it loose is usually better.  

 

 

 

You might manage to save a cycle or two if you hunt for things like this, but hunting for spare nanoseconds is not generally a good use of time.

 

Code optimization is generally about saving microseconds or bigger time units.

Share this post


Link to post
Share on other sites
cronocr    756

How is this actually slowing your program?
 
How is this something that actually needs a programmer to optimize it?

 

You might manage to save a cycle or two if you hunt for things like this, but hunting for spare nanoseconds is not generally a good use of time.

 

Code optimization is generally about saving microseconds or bigger time units.

 

At the level I'm currently optimizing the system, everything is slowing it down. I already designed an optimized solution, and profiled the system to the "smallest" millisecond. Now I'm ready for the nanoseconds. Why doing this? Because it's cheap doing it with the automated inlining tool I have built.

 

 

You are right that boxing is somewhat slow, so DON'T DO IT.  If you end up needing to routinely convert integers and bools into objects, you are likely doing something wrong at the algorithm level.  

 

It's almost impossible not to generate boxing, not in a system with 9000+ lines of code. The way to actually get rid of it is inlining, so I'm going to do it.

 

 

Similarly, the 'is' operator is not exactly fast, and its presence is a generally symptom of a more significant fundamental design problem.  Casting an object to some type and then discarding the results is horrible anyway; if you cannot fix your algorithm's underlying problem that requires the cast, at least have the decency to perform the cast with 'as' and keep the successful results around.

 

Using the "is" operator is just a trick to convert the statement into a expression, the idea is finding a way for the compiler to remove it later, so it doesn't represent any cost.

 

 

Next up, chaining doesn't necessarily mean better performance -- each item is dependent on the previous results which is bad for the pipeline.  You can get pipeline bubbles or poor use of speculative execution and branch prediction if you make it too tight.  On modern hardware keeping it loose is usually better.  

 

We are not talking of the same thing here. I might have used a wrong term when referring to the AND operator, that "chains/adds/joins" expressions, so the execution sequence is respected.

Edited by cronocr

Share this post


Link to post
Share on other sites
Bacterius    13165

Now I'm ready for the nanoseconds. Why doing this? Because it's cheap doing it with the automated inlining tool I have built.

 

You know that the time you spent actually developing this tool and feeding your code into it probably outweighs any such performance benefit by a factor of hundreds, right?

 

is_it_worth_the_time.png

 

Unless you spent less than a couple seconds or so developing this tool, you've already wasted your time working on something that is costing more time and effort than it is saving you. And that's without paraphrasing the above members with your fundamentally broken optimization approach.

Share this post


Link to post
Share on other sites
cronocr    756

Unfortunately no one who has read this thread seems to know the answer to my question, and people started asking "why doing it". Well I'm giving you people a little light on the purpose of transforming statements into expressions, and one of the reasons is that there is no way to avoid boxing in a large project. I'm seeing it with a decompiler, I'm seeing it in the final build. I already tried to find different ways to remove boxing, but that makes the code un-elegant and difficult to maintain. There is no design flaw. So the way to further optimize is creating a workflow that allows me to work on the code elegantly, and an automated tool to do the dirty job by helping the compiler to do a deeper optimization. I'm already doing the inlining and I'm seeing the benefits, at the moment I just want to find if C# allows converting every statement into an expression. Too bad I probably touched a "language as religion" nerve here, because I'm getting lots of negativity from a simple question. You people can have lots of fun pushing the -1 vote, solving this problem is way more important to me. If you want to learn with me, welcome :)

 

Using another language is not an option (come on dry.png ). Using Expression Trees is not an option because it makes code unelegant, adds another library, and is not fully support on various platforms (Mono/Unity here). CodeDom in not an option because not being fully supported neither. Standard expressions with the language operators is available everywhere, are rather easy to generate, and not doubt are optimal. Any reason not to use them?

Share this post


Link to post
Share on other sites
cronocr    756

 

Now I'm ready for the nanoseconds. Why doing this? Because it's cheap doing it with the automated inlining tool I have built.

 

You know that the time you spent actually developing this tool and feeding your code into it probably outweighs any such performance benefit by a factor of hundreds, right?

 

is_it_worth_the_time.png

 

Unless you spent less than a couple seconds or so developing this tool, you've already wasted your time working on something that is costing more time and effort than it is saving you. And that's without paraphrasing the above members with your fundamentally broken optimization approach.

 

Let's see, it took me about 10 months to produce 9,000+ effective lines of code, and I expect to produce twice as much when I finish the project. Starting took me more effort (more time thinking on future implications, and less code production) because I was building the foundations. I'm making the optimization workflow part of the foundation, so I can define the guidelines to write further code and get the most of source processing. Now, it took me 1 week to build, test and fix the inlining tool in Perl. The tool takes around 3 seconds to shave these 9,000+ lines of code. Now, by defining the optimization guidelines I can put the razor aside, and work normally. That means I don't shave until the next 18,000+ lines. I'll get a Duck Dynasty's beard, but I can always shave at the end without cutting my nose smile.png It's a good moment to optimize.

Edited by cronocr

Share this post


Link to post
Share on other sites
ApochPiQ    23012
You keep harping on this 9000 line of code business. You do realize that's considered trivially small by most professional standards, right?

Also, you continually claim that this is actually a performance win. Show us profiling data.


This thread is heading south awful fast so you (OP) have one chance to redeem yourself before I close this for being painfully close to trolling.

Share this post


Link to post
Share on other sites
cronocr    756
Then close it, you will have the opportunity to see that this actually works in the near future. I prefer seeing my thread closed than my mind to new ideas. Cheers! ;)

Share this post


Link to post
Share on other sites
Telastyn    3777

There is no design flaw.

 

How naive...

 

You know enough to say that there will always be boxing/unboxing in non-trivial code but fail to realize that any non-trivial code will have design flaws or at the very least, sub-optimal design trade-offs.

 

Of all the possible performance improvements in C#, boxing is like 10th in modern codebases. Have you curtailed your allocations? Have you chosen the right collections/algorithms? Have you pre-allocated your collections? Have you looked into pre-JITing to your target platform? Have you looked to parallelize/memoize your common algorithms?

 

Have you actually compiled in release mode and benchmarked the differences?

 

Look OP: you may be right, but understand that we see literally hundreds of people coming in here complaining of performance issues or claiming they NEED to do these things that the best of the best universally see as frivolous. We're just playing the odds that you're not the sub-one percent that really do need to do these things...

Share this post


Link to post
Share on other sites
Nypyren    12065

OP, perhaps you should show us some of your actual code that you've been profiling.  We may be able to help you out with optimizations on the original code.  I have a feeling that getting more eyes on the original code would help you more than asking for ideas about turning statements into expressions.

 

Post some side-by-side blocks of C# and disassembly (x86/64 or RISC, whichever you're targeting, not the IL) and demonstrate the problems you're seeing.  And I mean full functions or algorithms, not just individual statements like your first post has.  Those are out of context and are not useful to optimization discussions.

Edited by Nypyren

Share this post


Link to post
Share on other sites
cronocr    756

It amazes me that I never received a straight answer to my question, which I considered pretty basic. Some commenters had the genuine intention of guiding me, thinking that there is a flaw since they really don't have a full picture of the system. I can understand that, but then many are just repeating the concerns of others, and are poisoning the thread to the extreme that my words are being taken out of context to produce more concern. Now you ask for an effort on my side to further explain my design... you haven't done a single effort to answer my question, so you get nothing. In conclusion all this evasion from my question leads me to believe that it's difficult to achieve full statement-to-expression with C#'s non-overridden operators, and that saves me some time investigating them actively, I'll do it passively. I'll determine if the task is impossible later on. Answering all your concerns I was able to proof test my system's design. Also, now I know that not many developers will adventure in this field due to the "don't program that way or I hit you with a stick" mentality. Answers were helpful but only indirectly, the thread will be closed since it's already poisoned. Thanks biggrin.png

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this