To be honest there isn't any, but i found an old graphical effect which i had
coded which suffered from the same problems. I hoisted all for-loop variables
and the performance increase was truly impressive. I'll give you the code
whole code for the class, just cut'n paste :-)
// --- Field.cs
using System;
using System.Drawing;
using System.Drawing. Imaging;
using System.Collecti ons;
using System.Componen tModel;
using System.Windows. Forms;
using System.Threadin g;
namespace Field
{
public unsafe sealed class Field : System.Windows. Forms.Form
{
private const int MAXAMP=20, MINAMP=5;
private System.Componen tModel.Containe r components = null;
private Graphics _hDC;
private Bitmap _buffer;
private int _numPixelsInbuf fer;
private int _bufferWidth, _bufferHeight;
private uint [] _palette;
private int [] _hBaseMap, _hRunnerMap;
private Thread _runner;
private bool _done;
public Field()
{
InitializeCompo nent();
this.SetStyle(C ontrolStyles.Al lPaintingInWmPa int | ControlStyles.U serPaint
| ControlStyles.O paque, true);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Disp ose();
}
}
base.Dispose( disposing );
}
/// <summary>
/// Generates a heightmap
/// </summary>
/// <param name="map">Map to generate</param>
private void generateHeightM ap(ref int [] map, int minamp, int maxamp)
{
Random r = new Random();
int [] xBaseSine = new int[_bufferWidth];
double freqX = r.Next((_buffer Width-10)/5)+10;
int amplitudeX = r.Next(maxamp-minamp)+minamp;
double freqY = r.Next((_buffer Height-10)/5)+10;
int amplitudeY = r.Next(maxamp-minamp)+minamp;
fixed (int* pMap = map, pBase = xBaseSine)
{
int* pM = pMap;
int* pB = pBase;
for (int x = 0; x < _bufferWidth; x++ )
{
*pB = (int)(Math.Sin( x/freqX)*amplitud eX);
pB++;
}
for ( int y = 0; y < _bufferHeight; y++ )
{
pB = pBase;
int yBaseSine = (int)(Math.Sin( y/freqY)*amplitud eY);
for ( int x = 0; x < _bufferWidth; x++ )
{
*pM = yBaseSine+*pB;
pM++; pB++;
}
}
}
}
/// <summary>
/// Initializes our palette with shades of blue
/// </summary>
private uint[] initializePalet te(int size)
{
uint[] palette = new uint[size];
double blueDecrPrStep = 255f/size;
for (int i = 0; i < size; i++)
palette[i] = 0xFF000000 | (byte)(255f-i*blueDecrPrSte p);
return palette;
}
private void run()
{
const int FADE=1, ZEROPOINT = 2*MAXAMP;
bool regenerate = true;
int[] tmpArrayPointer ;
_palette = initializePalet te(4*MAXAMP);
_hRunnerMap = new int[_numPixelsInbuf fer];
_hBaseMap = new int[_numPixelsInbuf fer];
generateHeightM ap(ref _hRunnerMap, MINAMP, MAXAMP);
while(!_done)
{
if (regenerate)
{
tmpArrayPointer = _hBaseMap;
_hBaseMap = _hRunnerMap;
_hRunnerMap = tmpArrayPointer ;
generateHeightM ap(ref _hRunnerMap, MINAMP, MAXAMP);
}
regenerate = true;
fixed (int* pBaseMap = _hBaseMap, pRMap = _hRunnerMap)
{
int* pB = pBaseMap; // phMap is read only
int* pR = pRMap; // prHMap is read only
BitmapData bData = _buffer.LockBit s(new Rectangle(0, 0, _buffer.Width,
_buffer.Height) ,
ImageLockMode.W riteOnly, _buffer.PixelFo rmat);
uint* pPixel = (uint*)bData.Sc an0.ToPointer() ;
for ( int i = 0; i < _numPixelsInbuf fer; i++ )
{
*pPixel = _palette[*pB+ZEROPOINT];
++pPixel;
if (*pR > *pB)
{
*pB += FADE;
regenerate = false;
}
else if (*pR < *pB)
{
*pB -= FADE;
regenerate = false;
}
pB++;
pR++;
}
_buffer.UnlockB its(bData);
}
_hDC.DrawImage( _buffer,0,0);
}
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeCompo nent()
{
//
// Field
//
this.AutoScaleB aseSize = new System.Drawing. Size(5, 13);
this.ClientSize = new System.Drawing. Size(492, 371);
this.Name = "Field";
this.Text = "Field";
this.Closing += new
System.Componen tModel.CancelEv entHandler(this .Field_Closing) ;
this.Load += new System.EventHan dler(this.Field _Load);
}
#endregion
private void Field_Load(obje ct sender, System.EventArg s e)
{
_hDC = this.CreateGrap hics();
_buffer = new Bitmap(this.Cli entSize.Width, this.ClientSize .Height, _hDC);
_numPixelsInbuf fer = _buffer.Width*_ buffer.Height;
_bufferWidth = _buffer.Width;
_bufferHeight = _buffer.Height;
_runner = new Thread(new ThreadStart(thi s.run));
_runner.Start() ;
}
private void Field_Closing(o bject sender,
System.Componen tModel.CancelEv entArgs e)
{
_done = true;
// wait for thread to end naturally
while (_runner.IsAliv e) {}
}
}
}
"Willy Denoyette [MVP]" wrote:
"MariusI" <Ma*****@discus sions.microsoft .com> wrote in message
news:7E******** *************** ***********@mic rosoft.com...I stumbled over an optimization (or lack of one, to be specific) when
viewing
IL opcodes generated by the compiler using ms .net 2003. I was testing
fast
pixel manipulation using Bitmap.LockBits and unsafe pointers to iterate
over
an image's pixels. The inner-loop looked like this:
for (int x = 0; x < _buffer.Width*_ buffer.Height; x++)
{
// do manipulations here..
}
I noticed how the for-loop performed extremely slow, and ildasm revealed
that the "x < _buffer.Width*_ buffer.Height" was computed at each
iteration,
resulting in two virtual calls and one mul. The use of /optimize did not
improve the matter, so the solution was to calculate
_buffer.Width*_ buffer.Height outside of the for-loop. I was under the
impression that the compiler performed hoisting automatically, am I
missing
something here?
It's not the C# compiler that performs hoisting, it's the JIT compilers that
does a limited form of hoisting but this depends on what's been done in the
loop. Mind to share the code in the loop?
Willy.