Entwickler-Ecke
Basistechnologien - Schnelles Byte-Reversal
Christian S. - Mo 24.01.11 11:43
Titel: Schnelles Byte-Reversal
Hallo!
Ich suche nach der schnellsten Methode, um Bytes in einem UInt16 umzudrehen.
Der Hintergrund ist folgender:
- Ich lese 16bit-Daten als Byte-Array (_Bytes) von einer Kamera.
- Dann wird das ganze in ein Array von UInt16 kopiert.
Das Array heißt _BytereversedLinearData, dazu gibt es noch einen Pin _LinearDataPin, kopiert wird dann so: Marshal.Copy(_Bytes, 0, _LinearDataPin.AddrOfPinnedObject(), _Bytes.Length);
Jetzt möchte ich gerne die korrekten UInt16 haben, also im Prinzip in jedem Element von
_BytereversedLinearData die Bytes rumdrehen. Das in jedem Element über das Shiften und "verodern" der Bits zu machen, ist einfach richtig langsam.
Kennt jemand eine schnellere Methode?
Grüße
Christian
Christian S. - Mo 24.01.11 12:10
Diese Lösung scheint recht schnell zu sein:
C#-Quelltext
1: 2: 3:
| Array.Reverse(_Bytes); Marshal.Copy(_Bytes, 0, _LinearDataPin.AddrOfPinnedObject(), _Bytes.Length); Array.Reverse(_BytereversedLinearData); |
Kha - Mo 24.01.11 12:29
Hehe, interessante Lösung; schneller gehen dürfte es trotzdem noch :) . Wie genau hängen denn _LinearDataPin und _BytereversedLinearData zusammen :gruebel: ? Bzw. kannst du die Bytes nicht schon in _Bytes umdrehen?
Christian S. - Mo 24.01.11 12:33
Kha hat folgendes geschrieben : |
| Hehe, interessante Lösung; schneller gehen dürfte es trotzdem noch :) . |
Das wäre schön :-)
Kha hat folgendes geschrieben : |
| Wie genau hängen denn _LinearDataPin und _BytereversedLinearData zusammen :gruebel: ? |
Oh, ich dachte das mit dem Pin wäre eindeutig:
_LinearDataPin = GCHandle.Alloc(_BytereversedLinearData , GCHandleType.Pinned);
Kha hat folgendes geschrieben : |
| Bzw. kannst du die Bytes nicht schon in _Bytes umdrehen? |
Ja, schon, aber ich bezweifle, dass das performanter ist, weil ich dann ja doch wieder jedes Element anfassen muss. Werde es aber nach der Mittagspause mal ausprobieren :-)
Kha - Mo 24.01.11 14:07
Christian S. hat folgendes geschrieben : |
Kha hat folgendes geschrieben : | | Wie genau hängen denn _LinearDataPin und _BytereversedLinearData zusammen :gruebel: ? |
Oh, ich dachte das mit dem Pin wäre eindeutig: _LinearDataPin = GCHandle.Alloc(_BytereversedLinearData , GCHandleType.Pinned); |
Ah, im Zusammenhang mit Hardware hat es mein Hirn nicht ganz von "Pin" nach "Pinned" geschafft :lol: .
Christian S. hat folgendes geschrieben : |
Kha hat folgendes geschrieben : | | Bzw. kannst du die Bytes nicht schon in _Bytes umdrehen? |
Ja, schon, aber ich bezweifle, dass das performanter ist |
Ich muss mich wohl geschlagen geben - zumindest unter x86 ;) .
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| x86 -- TotalReversal: 1850 ms Unsafe: 2331 ms UnsafeInline: 2026 ms // Das Pinnen allein scheint nicht viel auszumachen... Safe: 2026 ms // ...und die Bounds Checks überhaupt nichts
x64 -- TotalReversal: 2042 ms Unsafe: 1416 ms UnsafeInline: 1034 ms Safe: 1354 ms |
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70:
| static ushort[] TotalReversal(byte[] bytes) { Array.Reverse(bytes); var ret = new ushort[bytes.Length / 2];
var h = GCHandle.Alloc(ret, GCHandleType.Pinned); Marshal.Copy(bytes, 0, h.AddrOfPinnedObject(), bytes.Length); h.Free();
Array.Reverse(ret); return ret; }
static unsafe ushort[] Unsafe(byte[] bytes) { var ret = new ushort[bytes.Length / 2]; fixed (byte* p = &bytes[0]) fixed (ushort* q = &ret[0]) { byte* p2 = p; ushort* q2 = q; for (int i = 0; i < ret.Length; i++) *q2++ = (ushort)(*p2++ + *p2++ << 8); }
return ret; }
static unsafe void UnsafeInline(byte* p2, ushort* q2, int length) { for (int i = 0; i < length; i++) *q2++ = (ushort)(*p2++ + *p2++ << 8); }
static ushort[] Safe(byte[] bytes) { var ret = new ushort[bytes.Length / 2]; for (int i = 0; i < ret.Length; i++) ret[i] = (ushort)(bytes[2 * i] + bytes[2 * i + 1] << 8);
return ret; }
static unsafe void Main(string[] args) { var bytes = Enumerable.Range(0, (int)100e6).Select(i => (byte)i).ToArray(); var sw = Stopwatch.StartNew(); var ret = new ushort[bytes.Length / 2]; fixed (byte* p = &bytes[0]) fixed (ushort* q = &ret[0]) { for (int i = 0; i < 10; i++) TotalReversal(bytes); Console.WriteLine("TotalReversal: " + sw.ElapsedMilliseconds + " ms");
sw.Restart(); for (int i = 0; i < 10; i++) Unsafe(bytes); Console.WriteLine("Unsafe: " + sw.ElapsedMilliseconds + " ms");
sw.Restart(); for (int i = 0; i < 10; i++) UnsafeInline(p, q, ret.Length); Console.WriteLine("UnsafeInline: " + sw.ElapsedMilliseconds + " ms");
sw.Restart(); for (int i = 0; i < 10; i++) Safe(bytes); Console.WriteLine("Safe: " + sw.ElapsedMilliseconds + " ms"); } |
Einen Moment, das sollte sich doch sogar linear parallelisieren lassen :D ...
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!