@@ -307,21 +307,31 @@ void CLG_(init_obj_table)(void)
307307 obj_table [i ] = 0 ;
308308}
309309
310- #define HASH_CONSTANT 256
311-
312- static UInt str_hash (const HChar * s , UInt table_size )
310+ #define FNV_OFFSET_BASIS 2166136261u
311+ #define FNV_PRIME 16777619u
312+
313+ /* Compute a full 32-bit FNV-1a hash of a string.
314+ * FNV-1a provides excellent distribution, much better than the
315+ * original shift-by-8 hash which only considered the last 4 bytes
316+ * of each string. The improved distribution reduces chain lengths
317+ * in the hash tables and eliminates most strcmp calls when combined
318+ * with the stored-hash comparison in lookup functions.
319+ */
320+ static UInt str_hash_full (const HChar * s )
313321{
314- int hash_value = 0 ;
315- for ( ; * s ; s ++ )
316- hash_value = (HASH_CONSTANT * hash_value + * s ) % table_size ;
317- return hash_value ;
322+ UInt hash = FNV_OFFSET_BASIS ;
323+ for ( ; * s ; s ++ ) {
324+ hash ^= (UChar )* s ;
325+ hash *= FNV_PRIME ;
326+ }
327+ return hash ;
318328}
319329
320-
321330static const HChar * anonymous_obj = "???" ;
322331
323332static __inline__
324- obj_node * new_obj_node (DebugInfo * di , obj_node * next )
333+ obj_node * new_obj_node (DebugInfo * di , UInt objname_full_hash ,
334+ obj_node * next )
325335{
326336 Int i ;
327337 obj_node * obj ;
@@ -330,6 +340,7 @@ obj_node* new_obj_node(DebugInfo* di, obj_node* next)
330340 obj -> name = di ? VG_ (strdup )( "cl.fn.non.2" ,
331341 VG_ (DebugInfo_get_filename )(di ) )
332342 : anonymous_obj ;
343+ obj -> name_hash = objname_full_hash ;
333344 for (i = 0 ; i < N_FILE_ENTRIES ; i ++ ) {
334345 obj -> files [i ] = NULL ;
335346 }
@@ -359,35 +370,39 @@ obj_node* new_obj_node(DebugInfo* di, obj_node* next)
359370obj_node * CLG_ (get_obj_node )(DebugInfo * di )
360371{
361372 obj_node * curr_obj_node ;
373+ UInt objname_full_hash ;
362374 UInt objname_hash ;
363375 const HChar * obj_name ;
364376
365377 obj_name = di ? VG_ (DebugInfo_get_filename )(di ) : anonymous_obj ;
366378
367379 /* lookup in obj hash */
368- objname_hash = str_hash (obj_name , N_OBJ_ENTRIES );
380+ objname_full_hash = str_hash_full (obj_name );
381+ objname_hash = objname_full_hash % N_OBJ_ENTRIES ;
369382 curr_obj_node = obj_table [objname_hash ];
370- while (NULL != curr_obj_node &&
371- VG_ (strcmp )(obj_name , curr_obj_node -> name ) != 0 ) {
383+ while (NULL != curr_obj_node &&
384+ (curr_obj_node -> name_hash != objname_full_hash ||
385+ VG_ (strcmp )(obj_name , curr_obj_node -> name ) != 0 )) {
372386 curr_obj_node = curr_obj_node -> next ;
373387 }
374388 if (NULL == curr_obj_node ) {
375389 obj_table [objname_hash ] = curr_obj_node =
376- new_obj_node (di , obj_table [objname_hash ]);
390+ new_obj_node (di , objname_full_hash , obj_table [objname_hash ]);
377391 }
378392
379393 return curr_obj_node ;
380394}
381395
382396
383397static __inline__
384- file_node * new_file_node (const HChar * filename ,
398+ file_node * new_file_node (const HChar * filename , UInt filename_full_hash ,
385399 obj_node * obj , file_node * next )
386400{
387401 Int i ;
388402 file_node * file = (file_node * ) CLG_MALLOC ("cl.fn.nfn.1" ,
389403 sizeof (file_node ));
390404 file -> name = VG_ (strdup )("cl.fn.nfn.2" , filename );
405+ file -> name_hash = filename_full_hash ;
391406 for (i = 0 ; i < N_FN_ENTRIES ; i ++ ) {
392407 file -> fns [i ] = NULL ;
393408 }
@@ -403,6 +418,7 @@ file_node* CLG_(get_file_node)(obj_node* curr_obj_node,
403418 const HChar * dir , const HChar * file )
404419{
405420 file_node * curr_file_node ;
421+ UInt filename_full_hash ;
406422 UInt filename_hash ;
407423
408424 /* Build up an absolute pathname, if there is a directory available */
@@ -414,15 +430,17 @@ file_node* CLG_(get_file_node)(obj_node* curr_obj_node,
414430 VG_ (strcat )(filename , file );
415431
416432 /* lookup in file hash */
417- filename_hash = str_hash (filename , N_FILE_ENTRIES );
433+ filename_full_hash = str_hash_full (filename );
434+ filename_hash = filename_full_hash % N_FILE_ENTRIES ;
418435 curr_file_node = curr_obj_node -> files [filename_hash ];
419- while (NULL != curr_file_node &&
420- VG_ (strcmp )(filename , curr_file_node -> name ) != 0 ) {
436+ while (NULL != curr_file_node &&
437+ (curr_file_node -> name_hash != filename_full_hash ||
438+ VG_ (strcmp )(filename , curr_file_node -> name ) != 0 )) {
421439 curr_file_node = curr_file_node -> next ;
422440 }
423441 if (NULL == curr_file_node ) {
424442 curr_obj_node -> files [filename_hash ] = curr_file_node =
425- new_file_node (filename , curr_obj_node ,
443+ new_file_node (filename , filename_full_hash , curr_obj_node ,
426444 curr_obj_node -> files [filename_hash ]);
427445 }
428446
@@ -433,12 +451,13 @@ file_node* CLG_(get_file_node)(obj_node* curr_obj_node,
433451static void resize_fn_array (void );
434452
435453static __inline__
436- fn_node * new_fn_node (const HChar * fnname ,
454+ fn_node * new_fn_node (const HChar * fnname , UInt fnname_full_hash ,
437455 file_node * file , fn_node * next )
438456{
439457 fn_node * fn = (fn_node * ) CLG_MALLOC ("cl.fn.nfnnd.1" ,
440458 sizeof (fn_node ));
441459 fn -> name = VG_ (strdup )("cl.fn.nfnnd.2" , fnname );
460+ fn -> name_hash = fnname_full_hash ;
442461
443462 CLG_ (stat ).distinct_fns ++ ;
444463 fn -> number = CLG_ (stat ).distinct_fns ;
@@ -481,20 +500,23 @@ fn_node* get_fn_node_infile(file_node* curr_file_node,
481500 const HChar * fnname )
482501{
483502 fn_node * curr_fn_node ;
503+ UInt fnname_full_hash ;
484504 UInt fnname_hash ;
485505
486506 CLG_ASSERT (curr_file_node != 0 );
487507
488508 /* lookup in function hash */
489- fnname_hash = str_hash (fnname , N_FN_ENTRIES );
509+ fnname_full_hash = str_hash_full (fnname );
510+ fnname_hash = fnname_full_hash % N_FN_ENTRIES ;
490511 curr_fn_node = curr_file_node -> fns [fnname_hash ];
491- while (NULL != curr_fn_node &&
492- VG_ (strcmp )(fnname , curr_fn_node -> name ) != 0 ) {
512+ while (NULL != curr_fn_node &&
513+ (curr_fn_node -> name_hash != fnname_full_hash ||
514+ VG_ (strcmp )(fnname , curr_fn_node -> name ) != 0 )) {
493515 curr_fn_node = curr_fn_node -> next ;
494516 }
495517 if (NULL == curr_fn_node ) {
496518 curr_file_node -> fns [fnname_hash ] = curr_fn_node =
497- new_fn_node (fnname , curr_file_node ,
519+ new_fn_node (fnname , fnname_full_hash , curr_file_node ,
498520 curr_file_node -> fns [fnname_hash ]);
499521 }
500522
0 commit comments