2009-08-31 14 views
5

Mam tablicę typów-uint w języku C#, Po sprawdzeniu, czy program działa na maszynie little-endian, chcę przekonwertować dane na big-endian rodzaj. Ponieważ ilość danych może stać się bardzo duża, ale zawsze jest równa, pomyślałem o rozważeniu dwóch typów uint jako typu ulong, dla lepszej wydajności i zaprogramowania go w ASM, więc szukam bardzo szybko (najszybciej, jeśli to możliwe) Assembler-algorytm do konwersji little-endian w big-endian.Szybka konwersja little-endian do big-endian w ASM

+0

zdefiniować dla mnie "bardzo duży"? –

+0

co najmniej 1 000 000 cykli (być może trochę mniej, ale może się powiększyć) –

Odpowiedz

6

Dla dużej ilości danych, instrukcja do bswap (dostępna w języku Visual C++ pod indeksem _byteswap_ushort, _byteswap_ulong, and _byteswap_uint64) jest drogą do zrobienia. To nawet przewyższy ręczne złożenie. To nie są dostępne w czystym C# bez P/Invoke, więc:

  1. to wykorzystać tylko jeśli masz dużo bajt danych do wymiany.
  2. Powinieneś poważnie rozważyć napisanie aplikacji I/O na najniższym poziomie w zarządzanym C++, abyś mógł dokonać zamiany przed przeniesieniem danych do zarządzanej tablicy. Musisz już napisać bibliotekę C++, więc nie ma wiele do stracenia i ominiesz wszystkie problemy związane z wydajnością P/Invoke dla algorytmów o niskiej złożoności działających na dużych zestawach danych.

PS: Wiele osób nie zdaje sobie sprawy z wewnętrznej swobody bajtów. Ich wydajność jest zdumiewająca, podwójnie dla danych zmiennoprzecinkowych, ponieważ przetwarza je jako liczby całkowite. Nie ma sposobu na pokonanie go bez ręcznego kodowania obciążeń rejestru dla każdego przypadku użycia pojedynczej partycji wymiany, a jeśli spróbujesz, prawdopodobnie poniesiesz większe trafienie w optymalizatorze, niż kiedykolwiek zauważysz.

1

Myślałam rozważyć dwa uint typy jako Ulong typu

Dobrze, że również zamienić dwie wartości uint który może nie być pożądane ...

Mogłabyś spróbuj trochę kodu C# w niebezpiecznym trybie, który może rzeczywiście dobrze działać. Na przykład:

public static unsafe void SwapInts(uint[] data) { 
    int cnt = data.Length; 
    fixed (uint* d = data) { 
     byte* p = (byte*)d; 
     while (cnt-- > 0) { 
     byte a = *p; 
     p++; 
     byte b = *p; 
     *p = *(p + 1); 
     p++; 
     *p = b; 
     p++; 
     *(p - 3) = *p; 
     *p = a; 
     p++; 
     } 
    } 
} 

Na moim komputerze przepustowość wynosi około 2 GB na sekundę.

2

Być może zechcesz po prostu ponownie przemyśleć problem, który nie powinien być wąskim gardłem. Weź algorytm naiwny (napisany w zespole CLI, tylko dla zabawy). Załóżmy liczbę chcemy jest numer lokalny 0

LDLOC 0 
SHL 24 
LDLOC 0 
LDC.i4 0x0000ff00 
SHL 8 
OR 
LDLOC 0 
LDC.i4 0x00ff0000 
SHL.UN 8 
OR 
LDLOC 0 
SHL.UN 24 
OR 

Co najwyżej to 13 instrukcji (x86) Montaż na numer (i najprawdopodobniej tłumacza będzie jeszcze mądrzejszy za pomocą sprytnych rejestrów). I nie jest bardziej naiwny.

Teraz porównaj to z kosztami

  • Pierwsze dane załadowane (w tym cokolwiek peryferia pracy z!)
  • Maniuplation danych (robi porównań, na przykład)
  • Wyprowadzanie wynik (cokolwiek to jest)

Jeśli 13 instrukcji na numer to znaczący kawałek czasu realizacji, a następnie robisz zadanie BARDZO wysokiej wydajności i powinno mieć twoje dane wejściowe we właściwym formacie! Prawdopodobnie nie używałbyś zarządzanego języka, ponieważ potrzebowałbyś znacznie większej kontroli nad buforami danych i tego, co nie, i bez dodatkowych sprawdzeń granic tablic.

Jeśli ta tablica danych trafi do sieci, to spodziewałbym się, że będą znacznie większe koszty związane z zarządzaniem gniazdami niż z przerzucania klatek w kolejności bajtów, jeśli jest to dysk z dysku, rozważ wstępne odwrócenie przed uruchomieniem tego programu.