Groups | Blog | Home
all groups > dotnet performance > august 2007 >

dotnet performance : byte[] to byte*... What is the fastest way?


Chris Mullins [MVP]
8/23/2007 1:04:51 PM
[quoted text, click to view]

I really hate to be pedantic, but I'm willing to bet that the difference in
how you iterate through your array makes little to no difference in the
overall performance of your code.

People frequently are guilting of over-optimizing things that are already
"Fast Enough". Unless you've verified this section is slow via a Profiler,
you're better off not getting fancy with optimizations.

--
Chris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP
http://www.coversant.com/blogs/cmullins

UL-Tomten
8/23/2007 1:27:57 PM

On Aug 23, 10:05 pm, "ThunderMusic"
[quoted text, click to view]

It can't happen.

Now, how's that for optimization?
Chris Mullins [MVP]
8/23/2007 1:45:51 PM
I understand well the "This code it called alot, therefore it needs to be
optimized." frame of mind. I build big, high-performance, network socket
servers for a living. I know this space really well, and have done lots in
both TCP & UDP land at scales that are pretty signfigant.

Put a profiler on this, and you'll likley find that this chunk of code won't
even show up. Certainly the difference between the two (pointer vs iterator)
is unlikley to show up at all.

--
Chris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP
http://www.coversant.com/blogs/cmullins

[quoted text, click to view]

ThunderMusic
8/23/2007 3:36:18 PM
Hi,
The subject says it all... I want to use a byte[] and use it as byte* so I
can increment the pointer to iterate through it.

What is the fastest way of doing so in C#?

Thanks

ThunderMusic

Nicholas Paldino [.NET/C# MVP]
8/23/2007 3:54:29 PM
ThunderMusic,

Use unsafe code:

byte[] bytes = ...;

unsafe
{
fixed (byte* p = bytes)
{
// Work with pointer here.
}
}

As a matter of fact, that's the only way to do it, as you need to pin
down the location of the array to prevent the reference from moving around.

Is there a reason you need the pointer, or are you just looking for a
faster way to iterate through the array?


--
- Nicholas Paldino [.NET/C# MVP]
- mvp@spam.guard.caspershouse.com

[quoted text, click to view]

Ignacio Machin ( .NET/ C# MVP )
8/23/2007 4:01:59 PM
Hi,

[quoted text, click to view]

Out of curiosity, why you want to do that?

What is wrong with using a indexer like
for( int i=0; i< buffer.Lengh; i++
buffer[i] .....


ThunderMusic
8/23/2007 4:05:52 PM
hi,
thanks for the really quick answer... Your solution works, but I can't
do p++ because it's fixed. So I must use another pointer like byte* p2 = p;
so now I can do p2++;...

Actually, I'm looking for a faster way to compute a checksum on a byte
array... For now, I'm using the Adler-32 algorithm, but I'm open to advises
on a performant checksum algorithm. It will be for an error checking
mecanism for tcp and udp communication on a closed network environment. So
it doesn't need to be human-modification resistant, it's just to prevent
modification due to the noise on the line (if it can happen)...

Thanks

ThunderMusic

"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard.caspershouse.com> wrote in
message news:uezij7b5HHA.5360@TK2MSFTNGP03.phx.gbl...
[quoted text, click to view]

r norman
8/23/2007 4:08:53 PM
On Thu, 23 Aug 2007 15:36:18 -0400, "ThunderMusic"
[quoted text, click to view]

I have recently started with C#, converting C++ applications that must
communicate with external equipment using protocols with rigidly fixed
byte sequences. Initially I was terribly frustrated abandoning my
precious pointer manipulation and access to byte arrays. But I
developed a bunch of utilities to create managed code byte[] arrays
from pieces and extract appropriate values from them and can now avoid
all unmanaged code. Look into Encoding.Convert for converting between
ASCII byte sequences and Unicode, MemoryStream.Write and ToArray along
with BinaryWriter.Write for creating byte[] data and the BitConverter
set of methods to extract values from byte[].

I keep telling myself that staying entirely within managed code is
worth all that effort, but I am still early in the process. Some old
timers here can probably fill you in on much more detail, including
the virtues of doing so.



Nicholas Paldino [.NET/C# MVP]
8/23/2007 4:13:51 PM
ThunderMusic,

If you are looking to tune this algoritm, I would say that the iteration
through the bytes is NOT the way to do it. There are probably a bunch of
other areas that can be improved upon.


--
- Nicholas Paldino [.NET/C# MVP]
- mvp@spam.guard.caspershouse.com

[quoted text, click to view]

ThunderMusic
8/23/2007 4:34:21 PM
hi,
I know it may be overoptimizing, but this part of the code will be called
many many many times per seconds, so I'm must make sure it's as optimized as
it can be. It's for a checksum mecanism, so each time a message must be
sent, it is called to compute the checksum to append to the message and will
be computed again when the client receives it so it can verify the validity
of the message.

Thanks for the comment tought...

ThunderMusic

[quoted text, click to view]

ThunderMusic
8/23/2007 4:41:36 PM
hi,
So, here is the code to get my checksum. If you see something that can be
optimized, let me know.

thanks

ThunderMusic

[Code]

private const UInt16 MOD_ADLER = 65521;
private unsafe uint GetChecksum(byte[] databytes)
{
UInt32 a = 1, b = 0;
fixed (byte* tmpdata = databytes)
{
byte* data = tmpdata;
int len = databytes.Length; /* Length in bytes */
while (len > 0)
{
int tlen = len > 5550 ? 5550 : len;
len -= tlen;
do
{
a += *(data++);
b += a;
} while ((--tlen) > 0);
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
}
/* It can be shown that a <= 0x1013a here, so a single subtract will
do. */
if (a >= MOD_ADLER)
a -= MOD_ADLER;
/* It can be shown that b can reach 0xffef1 here. */
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
if (b >= MOD_ADLER)
b -= MOD_ADLER;
}
return ((b << 16) | a);
}

[/Code]





"Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard.caspershouse.com> wrote in
message news:ewAkXGc5HHA.4712@TK2MSFTNGP04.phx.gbl...
[quoted text, click to view]

Ignacio Machin ( .NET/ C# MVP )
8/23/2007 4:41:40 PM
Hi,

[quoted text, click to view]

Why don't you do something, try using the "vanila" for statement versus the
pointer arithmetic you want to use, I will be surprised if you find any
noticeable difference.

Mattias Sjögren
8/23/2007 9:50:41 PM
[quoted text, click to view]

The fixed statement?


Mattias

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Willy Denoyette [MVP]
8/24/2007 1:42:16 AM
[quoted text, click to view]

You can try to do some partial loop unrolling, this is what a C++ compiler
does and what the C# compiler/JIT unfortunately fails to do.

UInt32 a = 1, b = 0;
fixed (byte* tmpdata = databytes)
{
byte* data = tmpdata;
int len = databytes.Length; /* Length in bytes */
while(len > 0)
{
int tlen = len > 5550 ? 5550 : len;
len -= tlen;
for(int c = 0; c < tlen / 4; c++)
{
a += *(data++);
b += a;
a += *(data++);
b += a;
a += *(data++);
b += a;
a += *(data++);
b += a;
}
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
for(int c = 0; c < tlen % 4; c++)
{
a += *(data++);
b += a;
}
a = (a & 0xffff) + (a >> 16) * (65536 - MOD_ADLER);
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
}
if (a >= MOD_ADLER)
a -= MOD_ADLER;
/* It can be shown that b can reach 0xffef1 here. */
b = (b & 0xffff) + (b >> 16) * (65536 - MOD_ADLER);
if (b >= MOD_ADLER)
b -= MOD_ADLER;
}
return ((b << 16) | a);


Willy.
AddThis Social Bookmark Button