1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file. */
6 /* Hashtable for XRay */
12 #include "xray/xray_priv.h"
16 struct XRayHashTableEntry
{
22 struct XRayHashTable
{
25 struct XRayHashTableEntry
* array
;
29 XRAY_NO_INSTRUMENT
void XRayHashTableGrow(struct XRayHashTable
* table
);
30 XRAY_NO_INSTRUMENT
uint32_t XRayHashTableHashKey(uint32_t key
);
31 XRAY_NO_INSTRUMENT
void XRayHashTableInit(struct XRayHashTable
* table
,
34 #define HASH_HISTO 1024
35 int g_hash_histo
[HASH_HISTO
];
38 /* Hashes a 32bit key into a 32bit value. */
39 uint32_t XRayHashTableHashKey(uint32_t x
) {
40 uint32_t y
= x
* 7919;
43 uint8_t* s
= (uint8_t*)&y
;
44 /* based on djb2 hash function */
46 for (c
= 0; c
< sizeof(y
); ++c
) {
48 h
= ((h
<< 5) + h
) + z
;
54 int XRayHashTableGetCapacity(struct XRayHashTable
* table
) {
55 return table
->capacity
;
59 int XRayHashTableGetCount(struct XRayHashTable
* table
) {
64 /* Looks up key in hashtable and returns blind data. */
65 void* XRayHashTableLookup(struct XRayHashTable
* table
, uint32_t key
) {
66 uint32_t h
= XRayHashTableHashKey(key
);
67 uint32_t m
= table
->capacity
- 1;
71 for (i
= 0; i
< m
; ++i
) {
72 /* An empty entry means the {key, data} isn't in the table. */
73 if (NULL
== table
->array
[j
].data
) {
77 /* Search for address */
78 if (table
->array
[j
].key
== key
) {
82 return table
->array
[j
].data
;
87 /* Table was full, and there wasn't a match. */
92 /* Inserts key & data into hash table. No duplicates. */
93 void* XRayHashTableInsert(struct XRayHashTable
* table
,
94 void* data
, uint32_t key
) {
95 uint32_t h
= XRayHashTableHashKey(key
);
96 uint32_t m
= table
->capacity
- 1;
99 for (i
= 0; i
< m
; ++i
) {
100 /* Take the first empty entry. */
101 /* (the key,data isn't already in the table) */
102 if (NULL
== table
->array
[j
].data
) {
105 table
->array
[j
].data
= data
;
106 table
->array
[j
].key
= key
;
109 ratio
= (float)table
->count
/ (float)table
->capacity
;
110 /* Double the capacity of the symtable if we've hit the ratio. */
111 if (ratio
> XRAY_SYMBOL_TABLE_MAX_RATIO
)
112 XRayHashTableGrow(table
);
115 /* If the key is already present, return the data in the table. */
116 if (table
->array
[j
].key
== key
) {
117 return table
->array
[j
].data
;
126 void* XRayHashTableAtIndex(struct XRayHashTable
* table
, int i
) {
127 if ((i
< 0) || (i
>= table
->capacity
))
129 return table
->array
[i
].data
;
133 /* Grows the hash table by doubling its capacity, */
134 /* then re-inserts all the elements into the new table. */
135 void XRayHashTableGrow(struct XRayHashTable
* table
) {
136 struct XRayHashTableEntry
* old_array
= table
->array
;
137 int old_capacity
= table
->capacity
;
138 int new_capacity
= old_capacity
* 2;
140 printf("XRay: Growing a hash table...\n");
141 XRayHashTableInit(table
, new_capacity
);
142 for (i
= 0; i
< old_capacity
; ++i
) {
143 void* data
= old_array
[i
].data
;
145 uint32_t key
= old_array
[i
].key
;
146 XRayHashTableInsert(table
, data
, key
);
153 void XRayHashTableInit(struct XRayHashTable
* table
, int32_t capacity
) {
155 if (0 != (capacity
& (capacity
- 1))) {
156 printf("Xray: Hash table capacity should be a power of 2!\n");
157 /* Round capacity up to next power of 2 */
158 /* see http://aggregate.org/MAGIC/ */
160 capacity
|= capacity
>> 1;
161 capacity
|= capacity
>> 2;
162 capacity
|= capacity
>> 4;
163 capacity
|= capacity
>> 8;
164 capacity
|= capacity
>> 16;
167 bytes
= sizeof(table
->array
[0]) * capacity
;
168 table
->capacity
= capacity
;
170 table
->array
= (struct XRayHashTableEntry
*)XRayMalloc(bytes
);
174 /* Creates & inializes hash table. */
175 struct XRayHashTable
* XRayHashTableCreate(int capacity
) {
176 struct XRayHashTable
* table
;
177 table
= (struct XRayHashTable
*)XRayMalloc(sizeof(*table
));
178 XRayHashTableInit(table
, capacity
);
179 memset(&g_hash_histo
[0], 0, sizeof(g_hash_histo
[0]) * HASH_HISTO
);
184 /* Prints hash table performance to file; for debugging. */
185 void XRayHashTableHisto(FILE* f
) {
187 for (i
= 0; i
< HASH_HISTO
; ++i
) {
188 if (0 != g_hash_histo
[i
])
189 fprintf(f
, "hash_iterations[%d] = %d\n", i
, g_hash_histo
[i
]);
194 /* Frees hash table. */
195 /* Note: Does not free what the hash table entries point to. */
196 void XRayHashTableFree(struct XRayHashTable
* table
) {
197 XRayFree(table
->array
);