Jump to content

  • Log In with Google      Sign In   
  • Create Account


Optimizing code statements into expressions?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • This topic is locked This topic is locked
16 replies to this topic

#1 cronocr   Members   -  Reputation: 751

Like
-4Likes
Like

Posted 24 May 2013 - 09:19 AM

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 © { 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?

Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


Sponsor:

#2 Waterlimon   Crossbones+   -  Reputation: 2443

Like
6Likes
Like

Posted 24 May 2013 - 09:42 AM

why...?


o3o


#3 cronocr   Members   -  Reputation: 751

Like
-5Likes
Like

Posted 24 May 2013 - 10:04 AM

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, 24 May 2013 - 10:05 AM.

Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


#4 frob   Moderators   -  Reputation: 19853

Like
4Likes
Like

Posted 24 May 2013 - 10:17 AM

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.


Check out my personal indie blog at bryanwagstaff.com.

#5 TheChubu   Crossbones+   -  Reputation: 3992

Like
1Likes
Like

Posted 24 May 2013 - 10:26 AM

why...?

 


"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

 

My journals: dustArtemis ECS framework and Making a Terrain Generator


#6 cronocr   Members   -  Reputation: 751

Like
-4Likes
Like

Posted 24 May 2013 - 10:51 AM

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, 24 May 2013 - 11:16 AM.

Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


#7 Mike.Popoloski   Crossbones+   -  Reputation: 2873

Like
9Likes
Like

Posted 24 May 2013 - 11:36 PM

There is so much wrong with this thread that it's mind boggling.

 

I have no idea why you think trying to force some random statement into an expression is going to make things faster, but it's really not. Trying to play tricky games with a language that compiles to an intermediate bytecode is also just laughably futile.

 

Furthermore, C# * absolutely* can be inlined, but you're not going to find it on the IL level, since it's a feature that's handled by the JIT and the CLR. It's also probably going to be a lot smarter about when to do it than you would be, taking into account the adverse affects it can have on polluting the instruction cache and potentially spilling registers in tight loops.

 

Additionally, boxing and unboxing are not going to have much of a performance hit on your application unless you're doing a ton of them. Allocations in a garbage collected environment are very fast, and small short-lived temporary objects are one of the best-case scenarios for the typical managed GC. It's unlikely to cause any fragmentation problems, considering that the GC moves objects in memory to avoid that very issue.

 

It's also not difficult to avoid boxing calls. Your nine thousand line program is actually pretty small as far as most games go, and it's absolutely possibly to avoid any boxing operations in a code length of that size, depending on what you're doing. As Frob said, if you find yourself needing to do it often, you need to critically rethink your design.

 

Despite all that, if you actually needed every single cycle available to you (and I'm not convinced that in your case you do), you should be working in a language that facilitates that kind of development, such as C++. Probably you're going to keep misguidedly doing what you're doing, but if nothing else this post should help others who might stumble upon this thread.


Edited by Mike.Popoloski, 24 May 2013 - 11:49 PM.

Mike Popoloski | Journal | SlimDX

#8 Nypyren   Crossbones+   -  Reputation: 4032

Like
5Likes
Like

Posted 25 May 2013 - 12:08 AM

OP, what you're saying is so...dissonant that I'm almost convinced you're trolling.

 

You should not be looking at the output IL.  You should be looking at the final JITted (with optimizations enabled) machine code.

 

Boxing will not be performance significant unless you're using the old weak-ass collections like ArrayList and Hashtable or have a HUGE design problem.

 

You can use C++ for large blocks of performance critical code and call it from C#, but that has its own set of issues and would probably just make this even more difficult.



#9 Bacterius   Crossbones+   -  Reputation: 8348

Like
4Likes
Like

Posted 25 May 2013 - 03:31 AM

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.


The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#10 cronocr   Members   -  Reputation: 751

Like
-3Likes
Like

Posted 25 May 2013 - 06:29 AM

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?


Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


#11 cronocr   Members   -  Reputation: 751

Like
-2Likes
Like

Posted 25 May 2013 - 07:44 AM

 

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, 25 May 2013 - 08:38 AM.

Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


#12 ApochPiQ   Moderators   -  Reputation: 14673

Like
2Likes
Like

Posted 25 May 2013 - 12:48 PM

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.

#13 cronocr   Members   -  Reputation: 751

Like
-3Likes
Like

Posted 25 May 2013 - 12:53 PM

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! ;)
Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


#14 Telastyn   Crossbones+   -  Reputation: 3726

Like
3Likes
Like

Posted 25 May 2013 - 01:10 PM

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...



#15 Nypyren   Crossbones+   -  Reputation: 4032

Like
4Likes
Like

Posted 25 May 2013 - 01:33 PM

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, 25 May 2013 - 01:34 PM.


#16 cronocr   Members   -  Reputation: 751

Like
-6Likes
Like

Posted 25 May 2013 - 05:18 PM

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


Unity3D, HTML5, Flash, PHP, Java, Objective C, DX/OGL and more...
Improving modern game mechanics: youtu.be/UJOQ3krzvWE

 


#17 ApochPiQ   Moderators   -  Reputation: 14673

Like
6Likes
Like

Posted 25 May 2013 - 07:10 PM

Don't labor under the delusion that I'm closing this because of anyone but you. Your attitude is horrific and you should seriously consider how you approach discussions with other people if you want to remain a part of this community.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS