1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-29 23:12:55 +01:00
llvm-mirror/runtime/libtrace/tracelib.c
Vikram S. Adve a23754ed38 Pointer hash table reallocation code seems never to have been tested!
Unfortunately, reallocation also means that the pointer numbering will
change, so increase table size to try to avoid it.

llvm-svn: 7130
2003-07-08 18:42:44 +00:00

384 lines
11 KiB
C

/*===-- Libraries/tracelib.c - Runtime routines for tracing -----*- C++ -*--===
*
* Runtime routines for supporting tracing of execution
* for code generated by LLVM.
*
*===---------------------------------------------------------------------===*/
#include "tracelib.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef sun
#include <stdint.h>
#endif
/*===---------------------------------------------------------------------=====
* HASH FUNCTIONS
*===---------------------------------------------------------------------===*/
/* use #defines until we have inlining */
typedef int64_t Generic;
typedef uint64_t Index;
typedef uint64_t Pointer;
/* Index IntegerHashFunc(const Generic value, const Index size) */
#define IntegerHashFunc(value, size) \
(((value << 3) ^ (value >> 3)) % size)
/* Index IntegerRehashFunc(const Generic oldHashValue, const Index size) */
#define IntegerRehashFunc(oldHashValue, size) \
((oldHashValue+16) % size) /* 16 is relatively prime to a Mersenne prime! */
/* Index PointerHashFunc(const void* value, const Index size) */
#define PointerHashFunc(value, size) \
IntegerHashFunc((Pointer) value, size)
/* Index PointerRehashFunc(const void* value, const Index size) */
#define PointerRehashFunc(value, size) \
IntegerRehashFunc((Pointer) value, size)
/*===---------------------------------------------------------------------=====
* POINTER-TO-GENERIC HASH TABLE.
* These should be moved to a separate location: HashTable.[ch]
*===---------------------------------------------------------------------===*/
typedef enum { FIND, ENTER } ACTION;
typedef char FULLEMPTY;
const FULLEMPTY EMPTY = '\0';
const FULLEMPTY FULL = '\1';
const uint MAX_NUM_PROBES = 4;
typedef struct PtrValueHashEntry_struct {
void* key;
Generic value;
} PtrValueHashEntry;
typedef struct PtrValueHashTable_struct {
PtrValueHashEntry* table;
FULLEMPTY* fullEmptyFlags;
Index capacity;
Index size;
} PtrValueHashTable;
extern Generic LookupOrInsertPtr(PtrValueHashTable* ptrTable,
void* ptr, ACTION action);
extern void Insert(PtrValueHashTable* ptrTable, void* ptr, Generic value);
extern void Delete(PtrValueHashTable* ptrTable, void* ptr);
void
InitializeTable(PtrValueHashTable* ptrTable, Index newSize)
{
ptrTable->table = (PtrValueHashEntry*) calloc(newSize,
sizeof(PtrValueHashEntry));
ptrTable->fullEmptyFlags = (FULLEMPTY*) calloc(newSize, sizeof(FULLEMPTY));
ptrTable->capacity = newSize;
ptrTable->size = 0;
}
PtrValueHashTable*
CreateTable(Index initialSize)
{
PtrValueHashTable* ptrTable =
(PtrValueHashTable*) malloc(sizeof(PtrValueHashTable));
InitializeTable(ptrTable, initialSize);
return ptrTable;
}
void
ReallocTable(PtrValueHashTable* ptrTable, Index newSize)
{
if (newSize <= ptrTable->capacity)
return;
#ifndef NDEBUG
printf("\n***\n*** WARNING: REALLOCATING SPACE FOR POINTER HASH TABLE.\n");
printf("*** oldSize = %ld, oldCapacity = %ld\n***\n\n",
ptrTable->size, ptrTable->capacity);
printf("*** NEW SEQUENCE NUMBER FOR A POINTER WILL PROBABLY NOT MATCH ");
printf(" THE OLD ONE!\n***\n\n");
#endif
unsigned int i;
PtrValueHashEntry* oldTable = ptrTable->table;
FULLEMPTY* oldFlags = ptrTable->fullEmptyFlags;
Index oldSize = ptrTable->size;
Index oldCapacity = ptrTable->capacity;
/* allocate the new storage and flags and re-insert the old entries */
InitializeTable(ptrTable, newSize);
memcpy(ptrTable->table, oldTable,
oldCapacity * sizeof(PtrValueHashEntry));
memcpy(ptrTable->fullEmptyFlags, oldFlags,
oldCapacity * sizeof(FULLEMPTY));
ptrTable->size = oldSize;
#ifndef NDEBUG
for (i=0; i < oldCapacity; ++i) {
assert(ptrTable->fullEmptyFlags[i] == oldFlags[i]);
assert(ptrTable->table[i].key == oldTable[i].key);
assert(ptrTable->table[i].value == oldTable[i].value);
}
#endif
free(oldTable);
free(oldFlags);
}
void
DeleteTable(PtrValueHashTable* ptrTable)
{
free(ptrTable->table);
free(ptrTable->fullEmptyFlags);
memset(ptrTable, '\0', sizeof(PtrValueHashTable));
free(ptrTable);
}
void
InsertAtIndex(PtrValueHashTable* ptrTable, void* ptr, Generic value, Index index)
{
assert(ptrTable->fullEmptyFlags[index] == EMPTY && "Slot is in use!");
ptrTable->table[index].key = ptr;
ptrTable->table[index].value = value;
ptrTable->fullEmptyFlags[index] = FULL;
ptrTable->size++;
}
void
DeleteAtIndex(PtrValueHashTable* ptrTable, Index index)
{
assert(ptrTable->fullEmptyFlags[index] == FULL && "Deleting empty slot!");
ptrTable->table[index].key = NULL;
ptrTable->table[index].value = (Generic) NULL;
ptrTable->fullEmptyFlags[index] = EMPTY;
ptrTable->size--;
}
Index
FindIndex(PtrValueHashTable* ptrTable, void* ptr)
{
uint numProbes = 1;
Index index = PointerHashFunc(ptr, ptrTable->capacity);
if (ptrTable->fullEmptyFlags[index] == FULL)
{
if (ptrTable->table[index].key == ptr)
return index;
/* First lookup failed on non-empty slot: probe further */
while (numProbes < MAX_NUM_PROBES)
{
index = PointerRehashFunc(index, ptrTable->capacity);
if (ptrTable->fullEmptyFlags[index] == EMPTY)
break;
else if (ptrTable->table[index].key == ptr)
return index;
++numProbes;
}
}
/* Lookup failed: item is not in the table. */
/* If last slot is empty, use that slot. */
/* Otherwise, table must have been reallocated, so search again. */
if (numProbes == MAX_NUM_PROBES)
{ /* table is too full: reallocate and search again */
ReallocTable(ptrTable, 1 + 2*ptrTable->capacity);
return FindIndex(ptrTable, ptr);
}
else
{
assert(ptrTable->fullEmptyFlags[index] == EMPTY &&
"Stopped before finding an empty slot and before MAX probes!");
return index;
}
}
Generic
LookupOrInsertPtr(PtrValueHashTable* ptrTable, void* ptr, ACTION action)
{
Index index = FindIndex(ptrTable, ptr);
if (ptrTable->fullEmptyFlags[index] == FULL &&
ptrTable->table[index].key == ptr)
return ptrTable->table[index].value;
/* Lookup failed: item is not in the table */
if (action != ENTER)
return (Generic) NULL;
/* Insert item into the table and return its index */
InsertAtIndex(ptrTable, ptr, (Generic) NULL, index);
return (Generic) NULL;
}
/* Returns NULL if the item is not found. */
/* void* LookupPtr(PtrValueHashTable* ptrTable, void* ptr) */
#define LookupPtr(ptrTable, ptr) \
LookupOrInsertPtr(ptrTable, ptr, FIND)
void
Insert(PtrValueHashTable* ptrTable, void* ptr, Generic value)
{
Index index = FindIndex(ptrTable, ptr);
assert(ptrTable->fullEmptyFlags[index] == EMPTY &&
"ptr is already in the table: delete it first!");
InsertAtIndex(ptrTable, ptr, value, index);
}
void
Delete(PtrValueHashTable* ptrTable, void* ptr)
{
Index index = FindIndex(ptrTable, ptr);
if (ptrTable->fullEmptyFlags[index] == FULL &&
ptrTable->table[index].key == ptr)
{
DeleteAtIndex(ptrTable, index);
}
}
/*===---------------------------------------------------------------------=====
* RUNTIME ROUTINES TO MAP POINTERS TO SEQUENCE NUMBERS
*===---------------------------------------------------------------------===*/
PtrValueHashTable* SequenceNumberTable = NULL;
Index INITIAL_SIZE = 1 << 22;
#define MAX_NUM_SAVED 1024
typedef struct PointerSet_struct {
char* savedPointers[MAX_NUM_SAVED]; /* 1024 alloca'd ptrs shd suffice */
unsigned int numSaved;
struct PointerSet_struct* nextOnStack; /* implement a cheap stack */
} PointerSet;
PointerSet* topOfStack = NULL;
SequenceNumber
HashPointerToSeqNum(char* ptr)
{
static SequenceNumber count = 0;
SequenceNumber seqnum;
if (SequenceNumberTable == NULL) {
assert(MAX_NUM_PROBES < INITIAL_SIZE+1 && "Initial size too small");
SequenceNumberTable = CreateTable(INITIAL_SIZE);
}
seqnum = (SequenceNumber) LookupPtr(SequenceNumberTable, ptr);
if (seqnum == 0)
{
Insert(SequenceNumberTable, ptr, ++count);
seqnum = count;
}
return seqnum;
}
void
ReleasePointerSeqNum(char* ptr)
{ /* if a sequence number was assigned to this ptr, release it */
if (SequenceNumberTable != NULL)
Delete(SequenceNumberTable, ptr);
}
void
PushPointerSet()
{
PointerSet* newSet = (PointerSet*) malloc(sizeof(PointerSet));
newSet->numSaved = 0;
newSet->nextOnStack = topOfStack;
topOfStack = newSet;
}
void
PopPointerSet()
{
PointerSet* oldSet;
assert(topOfStack != NULL && "popping from empty stack!");
oldSet = topOfStack;
topOfStack = oldSet->nextOnStack;
assert(oldSet->numSaved == 0);
free(oldSet);
}
/* free the pointers! */
static void
ReleaseRecordedPointers(char* savedPointers[MAX_NUM_SAVED],
unsigned int numSaved)
{
unsigned int i;
for (i=0; i < topOfStack->numSaved; ++i)
ReleasePointerSeqNum(topOfStack->savedPointers[i]);
}
void
ReleasePointersPopSet()
{
ReleaseRecordedPointers(topOfStack->savedPointers, topOfStack->numSaved);
topOfStack->numSaved = 0;
PopPointerSet();
}
void
RecordPointer(char* ptr)
{ /* record pointers for release later */
if (topOfStack->numSaved == MAX_NUM_SAVED) {
printf("***\n*** WARNING: OUT OF ROOM FOR SAVED POINTERS."
" ALL POINTERS ARE BEING FREED.\n"
"*** THE SEQUENCE NUMBERS OF SAVED POINTERS WILL CHANGE!\n*** \n");
ReleaseRecordedPointers(topOfStack->savedPointers, topOfStack->numSaved);
topOfStack->numSaved = 0;
}
topOfStack->savedPointers[topOfStack->numSaved++] = ptr;
}
/*===---------------------------------------------------------------------=====
* TEST DRIVER FOR INSTRUMENTATION LIBRARY
*===---------------------------------------------------------------------===*/
#ifndef TEST_INSTRLIB
#undef TEST_INSTRLIB /* #define this to turn on by default */
#endif
#ifdef TEST_INSTRLIB
int
main(int argc, char** argv)
{
int i, j;
int doRelease = 0;
INITIAL_SIZE = 5; /* start with small table to test realloc's*/
if (argc > 1 && ! strcmp(argv[1], "-r"))
{
PushPointerSet();
doRelease = 1;
}
for (i=0; i < argc; ++i)
for (j=0; argv[i][j]; ++j)
{
printf("Sequence number for argc[%d][%d] (%c) = Hash(%p) = %d\n",
i, j, argv[i][j], argv[i]+j, HashPointerToSeqNum(argv[i]+j));
if (doRelease)
RecordPointer(argv[i]+j);
}
if (doRelease)
ReleasePointersPopSet();
/* print sequence numbers out again to compare with (-r) and w/o release */
for (i=argc-1; i >= 0; --i)
for (j=0; argv[i][j]; ++j)
printf("Sequence number for argc[%d][%d] (%c) = Hash(%p) = %d\n",
i, j, argv[i][j], argv[i]+j, HashPointerToSeqNum(argv[i]+j));
return 0;
}
#endif