Multi-ApplicationOnlineProfiling  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Hash_Table.c
Go to the documentation of this file.
1 /* ############################ MALP License ############################## */
2 /* # Fri Jan 18 14:00:00 CET 2013 # */
3 /* # Copyright or (C) or Copr. Commissariat a l'Energie Atomique # */
4 /* # # */
5 /* # This software is governed by the CeCILL-C license under French law # */
6 /* # and abiding by the rules of distribution of free software. You can # */
7 /* # use, modify and/ or redistribute the software under the terms of # */
8 /* # the CeCILL-C license as circulated by CEA, CNRS and INRIA at the # */
9 /* # following URL http://www.cecill.info. # */
10 /* # # */
11 /* # The fact that you are presently reading this means that you have # */
12 /* # had knowledge of the CeCILL-C license and that you accept its # */
13 /* # terms. # */
14 /* # # */
15 /* # Authors: # */
16 /* # - BESNARD Jean-Baptiste jean-baptiste.besnard@cea.fr # */
17 /* # # */
18 /* ######################################################################## */
19 #include "Hash_Table.h"
20 
21 //Basic Hash----------------------------------------------------------------------------------------------------
22 void Hash_Table_init_Internal( void *phi, uint64_t coll_avoid, uint64_t intern_payload_size )
23 {
24  struct Hash_Table_Internal *h_intern = (struct Hash_Table_Internal *) phi;
25  h_intern->count = 0;
26  h_intern->lock = 0;
27  Chained_List_init( &h_intern->next_pl, coll_avoid, intern_payload_size );
28 }
29 
30 void Hash_Table_release_Internal( void *phi )
31 {
32  struct Hash_Table_Internal *h_intern = (struct Hash_Table_Internal *) phi;
33 
34  Chained_List_release(&h_intern->next_pl);
35 
36  h_intern->count = 0;
37 }
38 
39 //coll_avoid is the number of elems (obvious isn't it ?)
40 void Hash_Table_init( struct Hash_Table *ht, size_t sizeof_payload, uint64_t table_size, uint8_t coll_avoid )
41 {
42 
43  ht->need_lock = 0;
44  ht->sizeof_payload = sizeof_payload;
45  ht->table_size = table_size;
46  ht->coll_avoid = coll_avoid;
47 
48  ht->intern_payload_size = ( sizeof_payload - sizeof( struct Hash_Table_Internal) ) / ht->coll_avoid;
49 
50  //printf("Allocating a %.2f MB hashing table \n", (float)(sizeof_payload * table_size ) / (1024*1024) );
51  ht->payload = malloc( table_size * sizeof_payload + table_size );
52 
53  if( !ht->payload ) {
54  printf("Failled to alloc a %ld byte Hash table in %s at %d \n",table_size * sizeof_payload , __FILE__, __LINE__);
55  abort();
56  }
57 
58  int i = 0;
59 
60  for( i = 0 ; i < table_size ; i++) {
61  Hash_Table_init_Internal( (char *)ht->payload + (i * ht->sizeof_payload), ht->coll_avoid, ht->intern_payload_size );
62  }
63 
64 }
65 
66 
67 void Hash_Table_release( struct Hash_Table *ht, void (*free_f)(void *) )
68 {
69  int i = 0;
70 
71  struct Hash_Table_Internal *phi = NULL;
72 
73 
74  if( free_f )
75  Hash_Table_walkthrought( ht, free_f);
76 
77 
78 
79  for( i = 0 ; i < ht->table_size ; i++) {
80  phi = (struct Hash_Table_Internal *)( (char *)ht->payload + (i * ht->sizeof_payload) );
81  if( ht->coll_avoid <= phi->count )
83  }
84 
85  free( ht->payload );
86 
87  memset( ht, 0, sizeof( struct Hash_Table ) );
88 
89 }
90 
91 
92 
93 static inline void * get_cell_at( struct Hash_Table *ht, uint64_t key )
94 {
95 
96  uint64_t hash = MALP_Trace_crc64( (char *)&key, sizeof( uint64_t) );
97 
98  // printf(" key : %lld || size : %lld || hash: %llu || cell : %lld\n", key, ht->table_size, hash, hash % (uint64_t)ht->table_size);
99 
100  return ( (char *)ht->payload + ( ((uint64_t)hash % (uint64_t)ht->table_size) * ht->sizeof_payload) );
101 }
102 
103 
104 
105 void Hash_Table_lock_cell( struct Hash_Table *ht, uint64_t key )
106 {
107 
108 
109  struct Hash_Table_Internal *phi = NULL;
110 
111  phi = (struct Hash_Table_Internal *)get_cell_at( ht, key );
112 
113  MALP_Spinlock_lock(&phi->lock);
114 
115 }
116 
117 void Hash_Table_unlock_cell( struct Hash_Table *ht, uint64_t key )
118 {
119  struct Hash_Table_Internal *phi = NULL;
120 
121  phi = (struct Hash_Table_Internal *)get_cell_at( ht, key );
122 
123  MALP_Spinlock_unlock(&phi->lock);
124 }
125 
126 
127 
128 void * Hash_Table_get( struct Hash_Table *ht, uint64_t key , void *extra_arg, int (*test_func)(void *, uint64_t, void * ))
129 {
130 
131  struct Hash_Table_Internal *phi = NULL;
132 
133  int i = 0;
134 
135  if( !test_func )
136  return NULL;
137 
138  if( ht->table_size == 0 )
139  return NULL;
140 
141  phi = (struct Hash_Table_Internal *)get_cell_at( ht, key );
142 
143  //this scheme allows some collisions with low overhead
144  if( ht->need_lock )
145  MALP_Spinlock_lock( &phi->lock );
146 
147 
148  void *payload_ptr = ( (struct Hash_Table_Internal *)phi + 1);
149  void *ptr = NULL;
150 
151  for( i = 0 ; (i < phi->count) && (i < ht->coll_avoid) ; i++ ) {
152  //printf("INTERN %d \n", i);
153  ptr = (char *)payload_ptr + (i * ht->intern_payload_size);
154 
155  if( test_func( ptr , key, extra_arg ) ) {
156  if( ht->need_lock )
157  MALP_Spinlock_unlock( &phi->lock );
158  return ptr;
159  }
160  }
161 
162  int cc_len = Chained_List_count( &phi->next_pl );
163 
164  struct chained_list_view clv;
165  chained_list_view_init( &clv );
166 
167  for( i = 0 ; i < cc_len ; i++) {
168  //printf("LIST %d \n", i);
169  ptr = Chained_List_get_nth_seq( &phi->next_pl , &clv , i);
170 
171  if( test_func( ptr , key, extra_arg ) ) {
172  if( ht->need_lock )
173  MALP_Spinlock_unlock( &phi->lock );
174  return ptr;
175  }
176  }
177 
178  if( ht->need_lock )
179  MALP_Spinlock_unlock( &phi->lock );
180  return NULL;
181 }
182 
183 
184 void * Hash_Table_push_unique( struct Hash_Table *ht, void *payload , uint64_t key, void *extra_arg, int (*test_func)(void *, uint64_t, void * ) )
185 {
186  void *ret = Hash_Table_get( ht, key , extra_arg, test_func);
187 
188  if( !ret ) {
189  ret = Hash_Table_push( ht, payload , key );
190  } else {
191  memcpy( ret, payload, ht->intern_payload_size );
192  }
193 
194  return ret;
195 }
196 
197 
198 void * Hash_Table_push( struct Hash_Table *ht, void *payload , uint64_t key )
199 {
200 
201  struct Hash_Table_Internal *phi = NULL;
202  void *dest_ptr = NULL;
203 
204  phi = (struct Hash_Table_Internal *)get_cell_at( ht, key );
205 
206  if( ht->need_lock )
207  MALP_Spinlock_lock( &phi->lock );
208 
209  void *payload_ptr = phi + 1;
210 
211 
212  if( phi->count < ht->coll_avoid ) {
213  dest_ptr = (char *)payload_ptr + (phi->count * ht->intern_payload_size);
214 
215  memcpy( dest_ptr, payload, ht->intern_payload_size );
216  } else {
217  dest_ptr = Chained_List_push( &phi->next_pl, payload);
218  //printf("New collision of %d \n", phi->count);
219  }
220 
221  phi->count++;
222 
223  if( ht->need_lock )
224  MALP_Spinlock_unlock( &phi->lock );
225 
226  return dest_ptr;
227 }
228 
229 
230 
231 
232 void Hash_Table_walkthrought_cond( struct Hash_Table *ht, void (*action)(void *), int (*test_func)(void *, void * ), void *test_value )
233 {
234 
235  int i = 0, j = 0, k=0;
236  struct Hash_Table_Internal *phi;
237  void *payload = NULL;
238 
239  if( !action )
240  return;
241 
242  for( i = 0 ; i < ht->table_size ; i++) {
243  phi = (struct Hash_Table_Internal *)( (char* )ht->payload + (i * ht->sizeof_payload ) );
244 
245  if( phi->count == 0 )
246  continue;
247 
248  payload = ( phi + 1 );
249 
250  for( j = 0 ; j < ht->coll_avoid && j < phi->count ; j++ ) {
251  //printf("Pl over %d \n", j);
252 
253  if( !test_func ) {
254  (action) ( (char *)payload + (j * ht->intern_payload_size) );
255  } else if( (test_func )( (char *)payload + (j * ht->intern_payload_size), test_value ) ) {
256  (action) ( (char *)payload + (j * ht->intern_payload_size) );
257  }
258 
259  }
260 
261 
262 
263  int cc_len = Chained_List_count( &phi->next_pl );
264 
265  struct chained_list_view clv;
266  chained_list_view_init( &clv );
267 
268 
269  for( k = 0 ; k < cc_len ; k++) {
270  //printf("%d is cclen doing %d \n", cc_len, k);
271  payload = Chained_List_get_nth_seq( &phi->next_pl, &clv , k);
272 
273  if( !test_func ) {
274  (action) ( payload );
275  } else if( (test_func )( payload , test_value ) ) {
276  (action) ( payload );
277  }
278  }
279  }
280 }
281 
282 void Hash_Table_walkthrought_cond_2p( struct Hash_Table *ht, void *second_arg, void (*action)(void *, void *), int (*test_func)(void *, void * ), void *test_value )
283 {
284 
285  if( !action )
286  return;
287 
288  int i = 0, j = 0, k=0;
289  struct Hash_Table_Internal *phi;
290  void *payload = NULL;
291 
292  for( i = 0 ; i < ht->table_size ; i++) {
293  phi = (struct Hash_Table_Internal *)( (char* )ht->payload + (i * ht->sizeof_payload ) );
294 
295  if( phi->count == 0 )
296  continue;
297 
298  payload = ( phi + 1 );
299 
300  for( j = 0 ; j < ht->coll_avoid && j < phi->count ; j++ ) {
301  //printf("Pl over %d \n", j);
302  if( !test_func ) {
303  (action) ( (char *)payload + (j * ht->intern_payload_size), second_arg );
304  } else if( (test_func )( (char *)payload + (j * ht->intern_payload_size), test_value ) ) {
305  (action) ( (char *)payload + (j * ht->intern_payload_size), second_arg );
306  }
307  }
308 
309  int cc_len = Chained_List_count( &phi->next_pl );
310 
311  struct chained_list_view clv;
312  chained_list_view_init( &clv );
313 
314  for( k = 0 ; k < cc_len ; k++) {
315  //printf("%d is cclen doing %d \n", cc_len, k);
316  payload = Chained_List_get_nth_seq( &phi->next_pl, &clv , k);
317 
318  if( !test_func ) {
319  (action) ( payload , second_arg);
320  } else if( (test_func )( payload , test_value ) ) {
321  (action) ( payload, second_arg);
322  }
323  }
324 
325  }
326 }
327 
328 
330 {
331  int i = 0, j = 0;
332  struct Hash_Table_Internal *phi;
333  void *payload = NULL;
334 
335  for( i = 0 ; i < ht->table_size ; i++) {
336  phi = (struct Hash_Table_Internal *)( (char* )ht->payload + (i * ht->sizeof_payload ) );
337 
338  if( phi->count == 0 )
339  continue;
340 
341  payload = ( phi + 1 );
342 
343  return ( (char *)payload + (j * ht->intern_payload_size) );
344  }
345 
346  return NULL;
347 }
348 
349 
350 void Hash_Table_walkthrought( struct Hash_Table *ht, void (*action)(void *) )
351 {
352 
353  int i = 0, j = 0, k=0;
354  struct Hash_Table_Internal *phi;
355  void *payload = NULL;
356 
357  for( i = 0 ; i < ht->table_size ; i++) {
358  phi = (struct Hash_Table_Internal *)( (char* )ht->payload + (i * ht->sizeof_payload ) );
359 
360  if( phi->count == 0 )
361  continue;
362 
363  payload = ( phi + 1 );
364 
365 
366  for( j = 0 ; j < ht->coll_avoid && j < phi->count ; j++ ) {
367  (action) ( (char *)payload + (j * ht->intern_payload_size) );
368  }
369 
370 
371  int cc_len = Chained_List_count( &phi->next_pl );
372 
373  struct chained_list_view clv;
374  chained_list_view_init( &clv );
375 
376  for( k = 0 ; k < cc_len ; k++) {
377  //printf("%d is cclen doing %d \n", cc_len, k);
378  payload = Chained_List_get_nth_seq( &phi->next_pl, &clv , k);
379  (action) ( payload );
380  }
381  }
382 }
383 
384 
385 void Hash_Table_walkthrought_2p( struct Hash_Table *ht, void *second_arg, void (*action)(void *, void *) )
386 {
387 
388  int i = 0, j = 0, k=0;
389  struct Hash_Table_Internal *phi;
390  void *payload = NULL;
391 
392  for( i = 0 ; i < ht->table_size ; i++) {
393  phi = (struct Hash_Table_Internal *)( (char* )ht->payload + (i * ht->sizeof_payload ) );
394 
395  if( phi->count == 0 )
396  continue;
397 
398  payload = ( phi + 1 );
399 
400  for( j = 0 ; j < ht->coll_avoid && j < phi->count ; j++ ) {
401  //printf("Pl over %d \n", j);
402  (action) ( (char *)payload + (j * ht->intern_payload_size), second_arg );
403  }
404 
405  int cc_len = Chained_List_count( &phi->next_pl );
406 
407  struct chained_list_view clv;
408  chained_list_view_init( &clv );
409 
410  for( k = 0 ; k < cc_len ; k++) {
411  //printf("%d is cclen doing %d \n", cc_len, k);
412  payload = Chained_List_get_nth_seq( &phi->next_pl, &clv , k);
413  (action) ( payload , second_arg );
414  }
415  }
416 }
417 
418 
419 void ___Hash_Table_count_by_walk(void *elem, void *pcounter)
420 {
421  uint64_t *counter = (uint64_t *)pcounter;
422  *counter = *counter + 1;
423 }
424 
426 {
427  uint64_t ret = 0;
428 
430 
431  return ret;
432 }
433 
434 
435 void Hash_Table_walkthrought_3p( struct Hash_Table *ht, void *second_arg, void *third_arg, void (*action)(void *, void *, void *) )
436 {
437 
438  int i = 0, j = 0, k=0;
439  struct Hash_Table_Internal *phi;
440  void *payload = NULL;
441 
442  for( i = 0 ; i < ht->table_size ; i++) {
443  phi = (struct Hash_Table_Internal *)( (char* )ht->payload + (i * ht->sizeof_payload ) );
444 
445  if( phi->count == 0 )
446  continue;
447 
448  payload = ( phi + 1 );
449 
450  for( j = 0 ; j < ht->coll_avoid && j < phi->count ; j++ ) {
451  //printf("Pl over %d \n", j);
452  (action) ( (char *)payload + (j * ht->intern_payload_size), second_arg, third_arg );
453  }
454 
455  int cc_len = Chained_List_count( &phi->next_pl );
456 
457  struct chained_list_view clv;
458  chained_list_view_init( &clv );
459 
460  for( k = 0 ; k < cc_len ; k++) {
461  //printf("%d is cclen doing %d \n", cc_len, k);
462  payload = Chained_List_get_nth_seq( &phi->next_pl, &clv , k);
463  (action) ( payload , second_arg , third_arg);
464  }
465 
466  }
467 }
468 
static uint64_t MALP_Trace_crc64(char *source, uint64_t size)
Computes the hash of a given data.
Definition: CRC64.h:54
int count
the number of elements
Definition: Hash_Table.h:47
This struct is used to improve performance when sequentially walking through.
Definition: Chained_List.h:133
static void * get_cell_at(struct Hash_Table *ht, uint64_t key)
Definition: Hash_Table.c:93
static void chained_list_view_init(struct chained_list_view *clv)
Initializes a chained_list_view.
Definition: Chained_List.h:142
void ___Hash_Table_count_by_walk(void *elem, void *pcounter)
Definition: Hash_Table.c:419
This is the structure used to store the clusters (items that have the same hash)
Definition: Hash_Table.h:44
void Hash_Table_walkthrought_cond(struct Hash_Table *ht, void(*action)(void *), int(*test_func)(void *, void *), void *test_value)
Executes a function on every stored elements that satisfy a condition.
Definition: Hash_Table.c:232
uint8_t coll_avoid
maximum number of elements stored in the cluster static array
Definition: Hash_Table.h:59
void Hash_Table_release_Internal(void *phi)
Releases internal hashtable data.
Definition: Hash_Table.c:30
size_t intern_payload_size
the size of the internal static array (coll_avoid * sizeof_payload)
Definition: Hash_Table.h:56
void Hash_Table_lock_cell(struct Hash_Table *ht, uint64_t key)
Locks a cell at given key.
Definition: Hash_Table.c:105
void * Hash_Table_push(struct Hash_Table *ht, void *payload, uint64_t key)
adds an element to a hashtable
Definition: Hash_Table.c:198
void * Hash_Table_push_unique(struct Hash_Table *ht, void *payload, uint64_t key, void *extra_arg, int(*test_func)(void *, uint64_t, void *))
Adds an element into the hashtable. Replaces already existing element at key.
Definition: Hash_Table.c:184
static void Chained_List_init(struct Chained_List *list, uint64_t chunk_size, size_t payload_size)
Initializes a Chained_List.
Definition: Chained_List.h:286
void Hash_Table_walkthrought_cond_2p(struct Hash_Table *ht, void *second_arg, void(*action)(void *, void *), int(*test_func)(void *, void *), void *test_value)
Executes a function on every stored elements that satisfy a condition.
Definition: Hash_Table.c:282
int MALP_Spinlock_unlock(MALP_Spinlock *mutex)
Unlocks the given MALP_Spinlock.
Definition: Spinlock.c:41
static uint64_t Chained_List_count(struct Chained_List *list)
Counts the elements in the list.
Definition: Chained_List.h:328
size_t sizeof_payload
the size of stored elements
Definition: Hash_Table.h:55
static void * Chained_List_push(struct Chained_List *list, void *payload)
Adds an element to the list.
Definition: Chained_List.h:312
void Hash_Table_unlock_cell(struct Hash_Table *ht, uint64_t key)
Unlocks a cell at given key.
Definition: Hash_Table.c:117
This is the main hask table structure.
Definition: Hash_Table.h:53
void Hash_Table_init(struct Hash_Table *ht, size_t sizeof_payload, uint64_t table_size, uint8_t coll_avoid)
Hash_Table initialization.
Definition: Hash_Table.c:40
void Hash_Table_walkthrought_2p(struct Hash_Table *ht, void *second_arg, void(*action)(void *, void *))
Executes a function on every stored elements.
Definition: Hash_Table.c:385
void * Hash_Table_get(struct Hash_Table *ht, uint64_t key, void *extra_arg, int(*test_func)(void *, uint64_t, void *))
retrieves an element from the hashtable
Definition: Hash_Table.c:128
uint64_t Hash_Table_count_by_walk(struct Hash_Table *ht)
counts the elements in the hashtable by walking through all the elements
Definition: Hash_Table.c:425
void Hash_Table_release(struct Hash_Table *ht, void(*free_f)(void *))
Hash_Table release.
Definition: Hash_Table.c:67
int MALP_Spinlock_lock(MALP_Spinlock *mutex)
Locks the given MALP_Spinlock.
Definition: Spinlock.c:29
void * payload
where data is stored (Hash_Table_Internal + cluster static array)
Definition: Hash_Table.h:54
uint64_t table_size
the size of the table
Definition: Hash_Table.h:57
void * Hash_Table_get_an_entry(struct Hash_Table *ht)
Retrieves the first found element of the hash table.
Definition: Hash_Table.c:329
static void Chained_List_release(struct Chained_List *list)
Clears a Chained_List.
Definition: Chained_List.h:298
uint8_t need_lock
set to 1 if internals need to use a lock before access
Definition: Hash_Table.h:58
MALP_Spinlock lock
a lock for concurrent access
Definition: Hash_Table.h:45
struct Chained_List next_pl
the actual chained list (containing elements)
Definition: Hash_Table.h:46
void Hash_Table_walkthrought(struct Hash_Table *ht, void(*action)(void *))
Executes a function on every stored elements.
Definition: Hash_Table.c:350
void Hash_Table_init_Internal(void *phi, uint64_t coll_avoid, uint64_t intern_payload_size)
Initializes internal hashtable data.
Definition: Hash_Table.c:22
static void * Chained_List_get_nth_seq(struct Chained_List *cl, struct chained_list_view *view, uint64_t n)
Get a reference to the nth element of the chained list (optimised for sequential) ...
Definition: Chained_List.h:401
void Hash_Table_walkthrought_3p(struct Hash_Table *ht, void *second_arg, void *third_arg, void(*action)(void *, void *, void *))
Executes a function on every stored elements.
Definition: Hash_Table.c:435