hashtable.c revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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. 4 */ 5 6 7/* Hashtable for XRay */ 8 9#include <stdint.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include "xray/xray_priv.h" 14 15#if defined(XRAY) 16 17struct XRayHashTableEntry { 18 void* data; 19 uint32_t key; 20}; 21 22 23struct XRayHashTable { 24 int capacity; 25 int count; 26 struct XRayHashTableEntry* array; 27}; 28 29 30XRAY_NO_INSTRUMENT void XRayHashTableGrow(struct XRayHashTable* table); 31XRAY_NO_INSTRUMENT uint32_t XRayHashTableHashKey(uint32_t key); 32XRAY_NO_INSTRUMENT void XRayHashTableInit(struct XRayHashTable* table, 33 int32_t capacity); 34 35#define HASH_HISTO 1024 36int g_hash_histo[HASH_HISTO]; 37 38 39/* Hashes a 32bit key into a 32bit value. */ 40uint32_t XRayHashTableHashKey(uint32_t x) { 41 uint32_t y = x * 7919; 42 uint32_t z; 43 size_t c; 44 uint8_t* s = (uint8_t*)&y; 45 /* based on djb2 hash function */ 46 uint32_t h = 5381; 47 for (c = 0; c < sizeof(y); ++c) { 48 z = s[c]; 49 h = ((h << 5) + h) + z; 50 } 51 return h; 52} 53 54 55int XRayHashTableGetCapacity(struct XRayHashTable* table) { 56 return table->capacity; 57} 58 59 60int XRayHashTableGetCount(struct XRayHashTable* table) { 61 return table->count; 62} 63 64 65/* Looks up key in hashtable and returns blind data. */ 66void* XRayHashTableLookup(struct XRayHashTable* table, uint32_t key) { 67 uint32_t h = XRayHashTableHashKey(key); 68 uint32_t m = table->capacity - 1; 69 uint32_t j = h & m; 70 uint32_t i; 71 int z = 1; 72 for (i = 0; i < m; ++i) { 73 /* An empty entry means the {key, data} isn't in the table. */ 74 if (NULL == table->array[j].data) { 75 ++g_hash_histo[0]; 76 return NULL; 77 } 78 /* Search for address */ 79 if (table->array[j].key == key) { 80 if (z >= HASH_HISTO) 81 z = HASH_HISTO - 1; 82 ++g_hash_histo[z]; 83 return table->array[j].data; 84 } 85 j = (j + 1) & m; 86 ++z; 87 } 88 /* Table was full, and there wasn't a match. */ 89 return NULL; 90} 91 92 93/* Inserts key & data into hash table. No duplicates. */ 94void* XRayHashTableInsert(struct XRayHashTable* table, 95 void* data, uint32_t key) { 96 uint32_t h = XRayHashTableHashKey(key); 97 uint32_t m = table->capacity - 1; 98 uint32_t j = h & m; 99 uint32_t i; 100 for (i = 0; i < m; ++i) { 101 /* Take the first empty entry. */ 102 /* (the key,data isn't already in the table) */ 103 if (NULL == table->array[j].data) { 104 void* ret; 105 float ratio; 106 table->array[j].data = data; 107 table->array[j].key = key; 108 ++table->count; 109 ret = data; 110 ratio = (float)table->count / (float)table->capacity; 111 /* Double the capacity of the symtable if we've hit the ratio. */ 112 if (ratio > XRAY_SYMBOL_TABLE_MAX_RATIO) 113 XRayHashTableGrow(table); 114 return ret; 115 } 116 /* If the key is already present, return the data in the table. */ 117 if (table->array[j].key == key) { 118 return table->array[j].data; 119 } 120 j = (j + 1) & m; 121 } 122 /* Table was full */ 123 return NULL; 124} 125 126 127void* XRayHashTableAtIndex(struct XRayHashTable* table, int i) { 128 if ((i < 0) || (i >= table->capacity)) 129 return NULL; 130 return table->array[i].data; 131} 132 133 134/* Grows the hash table by doubling its capacity, */ 135/* then re-inserts all the elements into the new table. */ 136void XRayHashTableGrow(struct XRayHashTable* table) { 137 struct XRayHashTableEntry* old_array = table->array; 138 int old_capacity = table->capacity; 139 int new_capacity = old_capacity * 2; 140 int i; 141 printf("XRay: Growing a hash table...\n"); 142 XRayHashTableInit(table, new_capacity); 143 for (i = 0; i < old_capacity; ++i) { 144 void* data = old_array[i].data; 145 if (NULL != data) { 146 uint32_t key = old_array[i].key; 147 XRayHashTableInsert(table, data, key); 148 } 149 } 150 XRayFree(old_array); 151} 152 153 154void XRayHashTableInit(struct XRayHashTable* table, int32_t capacity) { 155 size_t bytes; 156 if (0 != (capacity & (capacity - 1))) { 157 printf("Xray: Hash table capacity should be a power of 2!\n"); 158 /* Round capacity up to next power of 2 */ 159 /* see http://aggregate.org/MAGIC/ */ 160 capacity--; 161 capacity |= capacity >> 1; 162 capacity |= capacity >> 2; 163 capacity |= capacity >> 4; 164 capacity |= capacity >> 8; 165 capacity |= capacity >> 16; 166 capacity++; 167 } 168 bytes = sizeof(table->array[0]) * capacity; 169 table->capacity = capacity; 170 table->count = 0; 171 table->array = (struct XRayHashTableEntry*)XRayMalloc(bytes); 172} 173 174 175/* Creates & inializes hash table. */ 176struct XRayHashTable* XRayHashTableCreate(int capacity) { 177 struct XRayHashTable* table; 178 table = (struct XRayHashTable*)XRayMalloc(sizeof(*table)); 179 XRayHashTableInit(table, capacity); 180 memset(&g_hash_histo[0], 0, sizeof(g_hash_histo[0]) * HASH_HISTO); 181 return table; 182} 183 184 185/* Prints hash table performance to file; for debugging. */ 186void XRayHashTableHisto(FILE* f) { 187 int i; 188 for (i = 0; i < HASH_HISTO; ++i) { 189 if (0 != g_hash_histo[i]) 190 fprintf(f, "hash_iterations[%d] = %d\n", i, g_hash_histo[i]); 191 } 192} 193 194 195/* Frees hash table. */ 196/* Note: Does not free what the hash table entries point to. */ 197void XRayHashTableFree(struct XRayHashTable* table) { 198 XRayFree(table->array); 199 table->capacity = 0; 200 table->count = 0; 201 table->array = NULL; 202 XRayFree(table); 203} 204 205#endif /* XRAY */ 206 207