Home All Groups Group Topic Archive Search About

BitConverter.ToInt32 - weird optimization?

Author
13 Feb 2007 12:41 PM
Morten B. Post
Now, if we take a look at the reflected BitConverter.ToInt32 method it looks
something like this:

public static unsafe int ToInt32(byte[] value, int startIndex)
{
      if (value == null)
      {
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
      }
      if (((ulong) startIndex) >= value.Length)
      {

ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex,
ExceptionResource.ArgumentOutOfRange_Index);
      }
      if (startIndex > (value.Length - 4))
      {

ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
      }
      fixed (byte* numRef1 = &(value[startIndex]))
      {
            if ((startIndex % 4) == 0)
            {
                  return *(((int*) numRef1));
            }
            if (BitConverter.IsLittleEndian)
            {
                  return (((numRef1[0] | (numRef1[1] << 8)) | (numRef1[2] <<
0x10)) | (numRef1[3] << 0x18));
            }
            return ((((numRef1[0] << 0x18) | (numRef1[1] << 0x10)) |
(numRef1[2] << 8)) | numRef1[3]);
      }
}

What I don't understand is this:

            if ((startIndex % 4) == 0)
            {
                  return *(((int*) numRef1));
            }

What prevents me from using this method when the remaining product isn't 0?
We already checked if there is 4 bytes to read so I should be able to.

Cheers

Morten

Author
13 Feb 2007 1:08 PM
Jon Skeet [C# MVP]
<=?Utf-8?B?TW9ydGVuIEIuIFBvc3Q=?= <Morten B.
P***@discussions.microsoft.com>> wrote:

<snip>

> What prevents me from using this method when the remaining product isn't 0?
> We already checked if there is 4 bytes to read so I should be able to.

My guess is that "something" doesn't like pointers which aren't aligned
on a word boundary.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
13 Feb 2007 1:17 PM
Morten B. Post
"Jon Skeet [C# MVP]" wrote:

>  <=?Utf-8?B?TW9ydGVuIEIuIFBvc3Q=?= <Morten B.
> P***@discussions.microsoft.com>> wrote:
>
> <snip>
>
> > What prevents me from using this method when the remaining product isn't 0?
> > We already checked if there is 4 bytes to read so I should be able to.
>
> My guess is that "something" doesn't like pointers which aren't aligned
> on a word boundary.

You mean double word? It might be that, but it would be super nice to know
WHAT doesn't like it :)

Show quote
>
> --
> Jon Skeet - <sk***@pobox.com>
> http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
> If replying to the group, please do not mail me too
>
Author
13 Feb 2007 1:57 PM
Jon Skeet [C# MVP]
Morten B. Post <MortenBP***@discussions.microsoft.com> wrote:
> > My guess is that "something" doesn't like pointers which aren't aligned
> > on a word boundary.
>
> You mean double word?

Sorry, I'm used to "word" meaning "32 bits" on a 32 bit architecture.
I'd forgotten the curious Windows heritage of it meaning 16 bits...

> It might be that, but it would be super nice to know
> WHAT doesn't like it :)

I suspect it's *somewhere* in the CLI spec, but I'm feeling too groggy
to check at the minute.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
13 Feb 2007 4:17 PM
Goran Sliskovic
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MPG.203bc890410e0a2698d861@msnews.microsoft.com...
....
> > What prevents me from using this method when the remaining product isn't
0?
> > We already checked if there is 4 bytes to read so I should be able to.
>
> My guess is that "something" doesn't like pointers which aren't aligned
> on a word boundary.
....

Processors don't like it, it's at least performance penalty, if not an
exception (on some processors). Code seen is on the safe side...

Goran
Author
13 Feb 2007 10:28 PM
Morten B. Post
Show quote
"Goran Sliskovic" wrote:

>
> "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
> news:MPG.203bc890410e0a2698d861@msnews.microsoft.com...
> ....
> > > What prevents me from using this method when the remaining product isn't
> 0?
> > > We already checked if there is 4 bytes to read so I should be able to.
> >
> > My guess is that "something" doesn't like pointers which aren't aligned
> > on a word boundary.
> ....
>
> Processors don't like it, it's at least performance penalty, if not an
> exception (on some processors). Code seen is on the safe side...
>
> Goran
>
>
>

I totally understand that. But we're talking about an array of bytes here
which are aligned by 1 byte? So lets say our CPU is using 32 bit cycles - it
would load 4 bytes to the register at a time - the the array offset is wrong
it would actually have to access two different blocks of memory and then
shift away the bits that aren't necessary. Or how do we know that the array
is properly alligned when it consists of. I hope someone can answer this.

On a final note. If .net is adding 3 padded bytes for each byte I'd be
really surprised hehe.
Author
13 Feb 2007 11:16 PM
Goran Sliskovic
Morten B. Post wrote:
>
....

>
> I totally understand that. But we're talking about an array of bytes here
> which are aligned by 1 byte? So lets say our CPU is using 32 bit cycles - it
> would load 4 bytes to the register at a time - the the array offset is wrong
> it would actually have to access two different blocks of memory and then
> shift away the bits that aren't necessary. Or how do we know that the array
> is properly alligned when it consists of. I hope someone can answer this.
>
> On a final note. If .net is adding 3 padded bytes for each byte I'd be
> really surprised hehe.

It's not adding 3 padded bytes per byte, rather all allocated buffers
are aligned on 4 byte boundary (even if you allocate 1 byte). OS
allocates all buffers aligned (VirtualAlloc).

From MSDN:
<quote>
VirtualAlloc

Reserves or commits a region of pages in the virtual address space of
the calling process. Memory allocated by this function is automatically
initialized to zero, unless MEM_RESET is specified.

To allocate memory in the address space of another process, use the
VirtualAllocEx function.

LPVOID VirtualAlloc(
   LPVOID lpAddress,
   SIZE_T dwSize,
   DWORD flAllocationType,
   DWORD flProtect
);

Parameters

lpAddress
     [in] The starting address of the region to allocate. If the memory
is being reserved, the specified address is rounded down to the nearest
multiple of the allocation granularity. If the memory is already
reserved and is being committed, the address is rounded down to the next
page boundary. To determine the size of a page and the allocation
granularity on the host computer, use the GetSystemInfo function. If
this parameter is NULL, the system determines where to allocate the region.
</quote>

if ((startIndex % 4) == 0)
{
     return *(((int*) numRef1));
}

since buffer is aligned on 4 bytes, all indexes % 4 == 0 are also, so
it's safe to cast to int and return, yielding performance gain. If not,
slow but safe calculation occures.

Regards,
Goran

AddThis Social Bookmark Button