Haszowanie stringa

Haszowanie stringów z wykorzystaniem prostego algorytmu Roberta Sedgwicks z książki "Algorithms in C".
Według testów różnych prostych algorytmów opublikowanych na stronie Hash Function Efficiency, można zauważyć ze właśnie RS jest prostym i małokolizyjnym algorytmem.

Dlatego właśnie go wybrałem do użycia w swoim projekcie, do haszowania nazw funkcji serwisowych eventów, hooków.

Implementacja w C++:

unsigned int RSHash(char* str) {
	unsigned int a = 63689;
	unsigned int b = 378551;
	unsigned int hash = 0;
 
	while (*str) {
		hash = hash * a + static_cast<unsigned char>(*str);
		a = a * b;
		str++;
	}
 
	return hash;
}

W źródłach mirandy, użyty przez nią algorytm znalazłem w wersji C i Asemblera, więc naszła mnie mała ochota, aby mój algorytm również nieco zoptymalizować i przy okazji przypomnieć sobie bebechy asemblera ;)

Tak też zrobiłem i wygenerowany asm przez g++ bez flag optymalizacyjnych doprowadziłem do postaci:

xor	eax, eax
mov	ebx, 63689
mov	esi, [ebp+8]
hL:
imul	eax, ebx
movzx	edx, BYTE PTR [esi]
add	eax, edx
imul	ebx, 378551
inc	esi
cmp	BYTE PTR [esi], 0
jg	hL

Efekt ciekawy, ale założyłem ze str jest różny od NULL, aby nieco ułatwić sprawę i pozbyć się kilku "nadmiarowych" poleceń i skoków.

G++ się postarał z optymalizacją, do porównania wersja z flagą O2:

push	ebx
mov	ecx, DWORD PTR [ebp+8]
mov	ebx, 63689
jmp	L7
.p2align 4,,7
L9:
imul	edx, ebx
movzx	eax, al
imul	ebx, ebx, 378551
inc	ecx
add	edx, eax
L7:
movzx	eax, BYTE PTR [ecx]
test	al, al
jne	L9
pop	ebx
mov	eax, edx

Przy okazji poruszając temat STLa, standard zaleca w make_pair przekazywać elementy przez referencje, a kochane gcc wspomina o tym, ale "robi" przez wartość ;)

Przez co proste dodanie elementu do mapa z wykorzystaniem make_pair w postaci:

std::pair<my_map_type::iterator, bool> ret = my_map.insert(std::make_pair(key, value));

doprowadziło do 4-krotnego kopiowania obiektu.

Zmiana na:

std::pair<my_map_type::iterator, bool> ret = my_map.insert(my_map_type::value_type(key, value));

zredukowała kopiowanie do 2.

Jak to ładnie ktoś rozwinął na pl.comp.lang.c skrót STL do Slow Template Library ;)

Dodano @ 20:49:34

Poprawiłem jeszcze swój kod, porównując go do zoptymalizowanej wersji z gcc. Powinien teraz być wydajniejszy i formalnie poprawniejszy ;)

xor	eax, eax
mov	ebx, 63689
mov	ecx, 378551
mov	esi, DWORD PTR [ebp+8]
jmp	C
L:
imul	eax, ebx
add	eax, edx
imul	ebx, ecx
inc	esi
C:
movzx	edx, BYTE PTR [esi]
test	edx, edx
jnz	L
; porownywanie
test	rej, rej
; jest szybsze od
cmp	rej, 0

W porównaniu do wersji gcc, w pętli mamy 1 instrukcje mniej, oraz wrzuciliśmy do rejestru wartość stałej b, co powinno przyśpieszyć działanie, bo w pętli procesor operuje na samych rejestrach ;)

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *