开发者

Is there a shift and copy cpu instruction that can be accessed from c#?

开发者 https://www.devze.com 2023-04-06 05:37 出处:网络
I need to take an 8 bit number on a 64 bit cpu and shift it to the right 8 times. Each time I shift the number I need to shift the same 8 bit number in behind it so that I end up with the same 8 bit n

I need to take an 8 bit number on a 64 bit cpu and shift it to the right 8 times. Each time I shift the number I need to shift the same 8 bit number in behind it so that I end up with the same 8 bit number repeating 8 times. This would end up being shift, add 8, shift add 8... etc. which ends up being 40+ cycles (correct me if I'm wrong).

Is there a way to do this operation (of shift and copy) in 1 cycle so that I end up with the same value in the end?

long _value = 0;
byte _number = 7;
for (int i = 0; i < 8; i++) {
    _value = (_value << 8) + _number;
}

EDIT: I'm trying to compare a stream of chars开发者_StackOverflow中文版 to detect keywords. I can't use string.contains because the string value may be across the boundary of the buffer. Also, the application has to run on embedded ARM cpus as well as desktop and server CPUs. Memory usage and cpu cycles are very important.


Nowadays, there is no direct connection between number of instructions performed and the number of cpu cycles which are needed to execute them. You also seem to assume that a statement in C# corresponds to a single assembly/cpu instruction which also is wrong.

Your code seem correctly do what your algorithm description says (note that long is signed, use ulong for unsigned behaviour).

If you want to use specialized cpu extensions (like mmx,sse,whatever) that can do add-shift-assignment in one instruction, you need to use assembly code. But I am not sure if such a specific instruction exist. This may depend on the type of CPU you have.

You cannot use assembly code directly together with c#, but you can use assembly together with c (either as linked object file use make it inline assembly). The compiled c-code can be used from c#/.net with interop.

But the first and important question for you should be: What are you trying to accomplish?

I doubt that performance is this critical for your app, and even if, you should honestly ask yourself if c# is the best language for your goal.


Another idea would be to precompute all for all values of byte a lookup table.

var lu = new long[256];
// init
var n = 7;
var v = lu[n];

Update

Some benchmark results (in ms per 100000000 iterations):

  • Loop: 272
  • Unrolled: 207
  • Unsafe: 351
  • Lookup: 250
  • HenkH: 216

The unrolled version is:

long _value = 0;
byte _number = 7;

_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;
_value = (_value + _number) << 8;

The unsafe version is:

long _value = 0;
byte _number = 7;

byte* p = (byte*)&_value;

*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;
*p++ = _number;

Sadly not performing :(

The lookup is just a read to an array.

All compiled for x64/release.


When you want it to be fast you could at least unroll your loop:

ulong _value = 0;
byte _number = 7;

_value = _number;
_value = (_value <<  8) + _value;
_value = (_value << 16) + _value;
_value = (_value << 32) + _value;

This would have fewer branches too.

0

精彩评论

暂无评论...
验证码 换一张
取 消