Home | History | Annotate | Download | only in xray
      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 /* Hashtable for XRay */
      7 
      8 #include <stdint.h>
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include "xray/xray_priv.h"
     13 
     14 #if defined(XRAY)
     15 
     16 struct XRayHashTableEntry {
     17   void* data;
     18   uint32_t key;
     19 };
     20 
     21 
     22 struct XRayHashTable {
     23   int capacity;
     24   int count;
     25   struct XRayHashTableEntry* array;
     26 };
     27 
     28 
     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,
     32     int32_t capacity);
     33 
     34 #define HASH_HISTO 1024
     35 int g_hash_histo[HASH_HISTO];
     36 
     37 
     38 /* Hashes a 32bit key into a 32bit value. */
     39 uint32_t XRayHashTableHashKey(uint32_t x) {
     40   uint32_t y = x * 7919;
     41   uint32_t z;
     42   size_t c;
     43   uint8_t* s = (uint8_t*)&y;
     44   /* based on djb2 hash function */
     45   uint32_t h = 5381;
     46   for (c = 0; c < sizeof(y); ++c) {
     47     z = s[c];
     48     h = ((h << 5) + h) + z;
     49   }
     50   return h;
     51 }
     52 
     53 
     54 int XRayHashTableGetCapacity(struct XRayHashTable* table) {
     55   return table->capacity;
     56 }
     57 
     58 
     59 int XRayHashTableGetCount(struct XRayHashTable* table) {
     60   return table->count;
     61 }
     62 
     63 
     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;
     68   uint32_t j = h & m;
     69   uint32_t i;
     70   int z = 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) {
     74       ++g_hash_histo[0];
     75       return NULL;
     76     }
     77     /* Search for address */
     78     if (table->array[j].key == key) {
     79       if (z >= HASH_HISTO)
     80         z = HASH_HISTO - 1;
     81       ++g_hash_histo[z];
     82       return table->array[j].data;
     83     }
     84     j = (j + 1) & m;
     85     ++z;
     86   }
     87   /* Table was full, and there wasn't a match. */
     88   return NULL;
     89 }
     90 
     91 
     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;
     97   uint32_t j = h & m;
     98   uint32_t i;
     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) {
    103       void* ret;
    104       float ratio;
    105       table->array[j].data = data;
    106       table->array[j].key = key;
    107       ++table->count;
    108       ret = data;
    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);
    113       return ret;
    114     }
    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;
    118     }
    119     j = (j + 1) & m;
    120   }
    121   /* Table was full */
    122   return NULL;
    123 }
    124 
    125 
    126 void* XRayHashTableAtIndex(struct XRayHashTable* table, int i) {
    127   if ((i < 0) || (i >= table->capacity))
    128     return NULL;
    129   return table->array[i].data;
    130 }
    131 
    132 
    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;
    139   int i;
    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;
    144     if (NULL != data) {
    145       uint32_t key = old_array[i].key;
    146       XRayHashTableInsert(table, data, key);
    147     }
    148   }
    149   XRayFree(old_array);
    150 }
    151 
    152 
    153 void XRayHashTableInit(struct XRayHashTable* table, int32_t capacity) {
    154   size_t bytes;
    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/  */
    159     capacity--;
    160     capacity |= capacity >> 1;
    161     capacity |= capacity >> 2;
    162     capacity |= capacity >> 4;
    163     capacity |= capacity >> 8;
    164     capacity |= capacity >> 16;
    165     capacity++;
    166   }
    167   bytes = sizeof(table->array[0]) * capacity;
    168   table->capacity = capacity;
    169   table->count = 0;
    170   table->array = (struct XRayHashTableEntry*)XRayMalloc(bytes);
    171 }
    172 
    173 
    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);
    180   return table;
    181 }
    182 
    183 
    184 /* Prints hash table performance to file; for debugging. */
    185 void XRayHashTableHisto(FILE* f) {
    186   int i;
    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]);
    190   }
    191 }
    192 
    193 
    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);
    198   table->capacity = 0;
    199   table->count = 0;
    200   table->array = NULL;
    201   XRayFree(table);
    202 }
    203 
    204 #endif  /* XRAY */
    205 
    206