Tuesday, May 14, 2013

C# CLR JIT Optimization - Register allocation for primitives

Today I have come across a strange effect in C#

This code took 30 ms to run, and C++ version took 5-8msec. How come?

void Runtest()
{
   const int CNT = 10000000;//ten million
   long sum = 0;

   var w = Stopwatch.StartNew();

    for(int i=0; i < CNT, i++)
    {
       sum += 1;
    }
   w.Stop();

   var rate = CNT / (w.Elapsed.TotalSeconds);

   Text = string.Format("Total: {0} in {1} ms  at {2}/sec ", CNT, 
                         w.Elapsed.TotalMilliseconds, rate);

   Text+= sum.ToString();
}


The loop body does not do anything, and hopefully CLR JITs it into registers right?

If yes, why is it so many times slower than C++?

The answer lies with the last line:  "s.ToString();".  It treats "sum" as a struct, because structs are not really primitive types, although "long" fits in the register 1:1,
 the "objecty" nature of the "sum.ToString()" makes JIT generate memory-accessing code.I have confirmed this in WinDBG. The loop control var "i" is stored in the register but "sum" is not.

Solution:

      var s = sum;
   Text += s.ToString();


Result: 2 msec per 10,000,000 iterations instead of 30 ms. 15 times faster.


Here I have put an upper loop bound to Int.MaxValue for the code to run a bit longer so I can manage to ctrl+break in debugger.

Disassembly (loop body is highlighted):

000007ff`0014055d 33c0            xor     eax,eax         //i=0
000007ff`0014055f 33ed            xor     ebp,ebp         //sum=0
LOOP LABEL:
000007ff`00140561 48ffc5          inc     rbp               //sum++  
000007ff`00140564 ffc0            inc     eax               //i++  
000007ff`00140566 3dffffff7f      cmp     eax,7FFFFFFFh      //check int.Max 
000007ff`0014056b 7cf4            jl      000007ff`00140561 //jmp if less  LOOP LABEL

CAN not beat that!

The bottom line is this: JIT does optimize primitives in CPU registers just like C++ does, however because of unified type system it is easy to treat a primitive as struct or object - and that introduces penalty.
The truth of the matter is that until the loop exit they (Microsoft) could have kept it in register and then moved to RAM, but there are many edge cases like this and who knows what other issues JIT developers had to solve.

Saturday, January 21, 2012

How to display a progress message aka "hourglass" in Android around long running tasks, really moving that long running tasks to a different thread but obstructing your activity with a curtain from progress so messages are processed and everything shows. Here is a snippet:


ProgressDialog dialog = ProgressDialog.show(this, "Title",
"Your message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();

}
};

Thread export = new Thread() {
public void run() {

// LONG TASK CALL
// callLongTask();

handler.sendEmptyMessage(0);
}
};
export.start();

Saturday, September 24, 2011

Enumerated Types in Java Script

Who said that JavaScript lacks enumerated types? Really it does, however due to very flexible nature of the language enums are easily done like so (example taken from ITAdapter Geometry Library):
function GeometryNamespace() //in the Geometry namespace
{
var geometry = this;
...
... ...
this.MapDirection = {
North: {Name: "North"},
NorthEast: {Name: "NorthEast"},
East: {Name: "East"},
SouthEast: {Name: "SouthEast"},
South: {Name: "South"},
SouthWest: {Name: "SouthWest"},
West: {Name: "West"},
NorthWest: {Name: "NorthWest"}
};
.............
And then later:
/** * Converts map direction to angular coordinate in radians */

this.mapDirectionToAngle = function(direction)
{
switch (direction)
{
case geometry.MapDirection.North: return 4/16 * PI2;
case geometry.MapDirection.South: return 12/16 * PI2;
case geometry.MapDirection.East: return 0.0;
case geometry.MapDirection.West: return 8/16 * PI2;
case geometry.MapDirection.NorthEast: return 2/16 * PI2;
case geometry.MapDirection.NorthWest: return 6/16 * PI2;
case geometry.MapDirection.SouthEast: return 14/16 * PI2;
case geometry.MapDirection.SouthWest: return 10/16 * PI2;
default: return 0.0;
}
}

Coming back to js enums topic, one can easily display enum as:
var dir = MapDirection.South;
var name = dir.Name; //"South"

Wednesday, April 13, 2011

IE10? WTF?

Only like 1 month has passed and MS is publishing new IE10 beta assembly?

Check this out:

So, once again they talk HTML5...hm where is Silverlight guys? Well, that's right looks like Silverlight is finally going to fall from the stage.
Why would anyone even invest in SL at this point? Mobile? Gimme a break, HTML5 rulez there too - check out PhoneGap www.phonegap.com

Saturday, January 8, 2011

How To Draw a Circle in HTML <5 (without Canvas/SVG)

The following tiny script allows to draw circles in "regular" pre-HTML 5 document, it is so fast that it really allows for animations in real time.

Example:

   drawCircle(500, 500, 150, "red", 50, 1);

This will draw a  red circle, 50% transparent, with 150 px radius at the point (500,500). The circle will be drawn using 1px-fine pen (granularity).
The wider is the "pen" the faster is the routine. I usually increase granularity to 4px while dragging/sizing for speed and then re-render with 1px granularity upon drag grip release.


Here is the self-sufficient(does not rely on any libs) procedural source code:


//classic one
function isIE()
{
 return (navigator.appName.indexOf("Microsoft")!=-1);
}

function drawCircle(cx, cy, r, clr, op, gran)
{
 var x = 0;
 var div; 
 
 var dc = document.createElement("DIV");//aka "Device Context" wich is a DIV in doc tree
 dc.style.position="absolute";
 dc.innerHTML = "&nbsp;";
 dc.style.left = cx - r; 
 dc.style.top =  cy - r; 
 
 cx = r; cy = r;
 
 if (gran<1) gran = 1;
 
 if ((r/gran)> 280) gran = Math.round(r / 280);
  
 for(var y=0; y<=r; y+=gran)
 {
  x = Math.sqrt((r*r) - (y*y));
  
  div = document.createElement("DIV");
    
  div.style.position="absolute";
  div.style.background = clr;
  div.style.left = cx - x;
  div.style.top = cy+y;
  div.style.width= x*2;
  div.style.height=gran;
  div.style.fontSize=1;
  div.innerHTML = "&nbsp;";
  setObjectOpacity(div, op);
  dc.appendChild(div);
  
  div = document.createElement("DIV");
  div.style.position="absolute";
  div.style.background = clr;
  div.style.left = cx - x;
  div.style.top = cy-y-gran;
  div.style.width= x*2;
  div.style.height=gran;
  div.style.fontSize=1;
  div.innerHTML = "&nbsp;";
  setObjectOpacity(div, op);
  dc.appendChild(div);
  
 }
 
 return dc;
}//drawCircle

//semi-transparent through CSS/filter
function setObjectOpacity(obj, opacity) 
{
  //IE
  if (isIE())
   obj.style.filter = "alpha(opacity:"+opacity+")";
  else
  {
    opacity = (opacity == 100)?99.999:opacity;//99.9 for Firefox flicker bug
  
    // Konqueror, Safari
    obj.style.KHTMLOpacity = opacity / 100;
    // Old Mozilla and Firefox
    obj.style.MozOpacity = opacity / 100;
    // CSS3,  Safari , new Firefox (Gecko)
    obj.style.opacity = opacity / 100;
  }//else
}//setObjectOpacity


As you can see, this approach uses DIVs as a vehicle for graphics delivery. Also, one may ask why I did not use squares to reduce
 the number of DIVs - the answer is - flicker - squares would have overlapped and would have worked slower than interlaced DIVs.

Use as you please!