1998-12-17 10:00:17 +03:00
|
|
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; -*-
|
|
|
|
*
|
1999-11-02 09:38:29 +03:00
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
1998-12-17 10:00:17 +03:00
|
|
|
*
|
1999-11-02 09:38:29 +03:00
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
1998-12-17 10:00:17 +03:00
|
|
|
*
|
1999-11-02 09:38:29 +03:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1998-12-17 10:00:17 +03:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-02 09:38:29 +03:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
1998-12-17 10:00:17 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
S P O R T M O D E L
|
|
|
|
_____
|
|
|
|
____/_____\____
|
|
|
|
/__o____o____o__\ __
|
|
|
|
\_______________/ (@@)/
|
|
|
|
/\_____|_____/\ x~[]~
|
|
|
|
~~~~~~~~~~~/~~~~~~~|~~~~~~~\~~~~~~~~/\~~~~~~~~~
|
|
|
|
|
|
|
|
Advanced Technology Garbage Collector
|
|
|
|
Copyright (c) 1997 Netscape Communications, Inc. All rights reserved.
|
|
|
|
Author: Warren Harris
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
#include "plhash.h"
|
|
|
|
#include "dynahash.h"
|
|
|
|
#include "openhash.h"
|
|
|
|
#include "prlog.h"
|
|
|
|
#include "FastHashTable.h" // Electrical Fire s
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#define ITERATIONS 10000
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
//#define HASH_ALLOC 1
|
|
|
|
|
|
|
|
static PLHashNumber
|
|
|
|
HashFunction(const void *key)
|
|
|
|
{
|
|
|
|
return (PLHashNumber)key;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRIntn
|
|
|
|
HashKeyComparator(const void *v1, const void *v2)
|
|
|
|
{
|
|
|
|
return (int)v1 == (int)v2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRIntn
|
|
|
|
HashValueComparator(const void *v1, const void *v2)
|
|
|
|
{
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
return *(PRUword*)v1 == *(PRUword*)v2;
|
|
|
|
#else
|
|
|
|
return (PRUword)v1 == (PRUword)v2;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
HashTableAdd(PLHashTable* ht, PRUword i)
|
|
|
|
{
|
|
|
|
void* elem;
|
|
|
|
void* value;
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
value = malloc(sizeof(PRUword));
|
|
|
|
*(PRUword*)value = i;
|
|
|
|
#else
|
|
|
|
value = (void*)i;
|
|
|
|
#endif
|
|
|
|
elem = PL_HashTableAdd(ht, (const void*)i, value);
|
|
|
|
PR_ASSERT(elem != NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
HashTableLookup(PLHashTable* ht, PRUword i)
|
|
|
|
{
|
|
|
|
void* value;
|
|
|
|
PRUword v;
|
|
|
|
value = PL_HashTableLookup(ht, (const void*)i);
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
v = *(PRUword*)value;
|
|
|
|
#else
|
|
|
|
v = (PRUword)value;
|
|
|
|
#endif
|
|
|
|
PR_ASSERT(v == i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
HashTableDelete(PLHashTable* ht, PRUword i)
|
|
|
|
{
|
|
|
|
PRBool wasFound;
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
PLHashEntry* entry = *PL_HashTableRawLookup(ht, i, (const void*)i);
|
|
|
|
free(entry->value);
|
|
|
|
#endif
|
|
|
|
wasFound = PL_HashTableRemove(ht, (const void*)i);
|
|
|
|
PR_ASSERT(wasFound);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
TestHashTable(int initialSize)
|
|
|
|
{
|
|
|
|
PRUword i;
|
|
|
|
PRIntervalTime t1, t2;
|
|
|
|
PLHashTable* ht;
|
|
|
|
|
|
|
|
ht = PL_NewHashTable(initialSize, HashFunction, HashKeyComparator,
|
|
|
|
HashValueComparator, NULL, NULL);
|
|
|
|
PR_ASSERT(ht);
|
|
|
|
fprintf(stdout, "prhash\t%d", initialSize);
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
HashTableAdd(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
HashTableLookup(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
HashTableDelete(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus\n", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
PL_HashTableDestroy(ht);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
typedef struct MyHashElement {
|
|
|
|
PLDynahashElement hashElement; /* must be first */
|
|
|
|
PRUint32 key;
|
|
|
|
PRUint32 value;
|
|
|
|
} MyHashElement;
|
|
|
|
|
|
|
|
static PRUint32
|
|
|
|
Dynahash_HashKey(void* context, MyHashElement* x)
|
|
|
|
{
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma unused(context)
|
|
|
|
#endif
|
|
|
|
return x->key;
|
|
|
|
}
|
|
|
|
|
|
|
|
static PRBool
|
|
|
|
Dynahash_Equals(void* context, MyHashElement* x, MyHashElement* y)
|
|
|
|
{
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma unused(context)
|
|
|
|
#endif
|
|
|
|
return (PRBool)(x->key == y->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Dynahash_Destroy(void* context, MyHashElement* x)
|
|
|
|
{
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma unused(context)
|
|
|
|
#endif
|
|
|
|
free(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
DynahashAdd(PLDynahash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
PRStatus status;
|
|
|
|
MyHashElement* oldElem;
|
|
|
|
MyHashElement* elem;
|
|
|
|
elem = (MyHashElement*)malloc(sizeof(MyHashElement));
|
|
|
|
PR_ASSERT(elem != NULL);
|
|
|
|
elem->hashElement.next = NULL;
|
|
|
|
elem->key = i;
|
|
|
|
elem->value = i;
|
|
|
|
status = PL_DynahashAdd(ht, (PLDynahashElement*)elem, PR_FALSE,
|
|
|
|
(PLDynahashElement**)&oldElem);
|
|
|
|
PR_ASSERT(status == PR_SUCCESS);
|
|
|
|
free(oldElem);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DynahashLookup(PLDynahash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
MyHashElement elem;
|
|
|
|
MyHashElement* found;
|
|
|
|
PRBool wasFound;
|
|
|
|
elem.hashElement.next = NULL;
|
|
|
|
elem.key = i;
|
|
|
|
found = (MyHashElement*)PL_DynahashLookup(ht, (PLDynahashElement*)&elem);
|
|
|
|
PR_ASSERT(found);
|
|
|
|
wasFound = (PRBool)(found->value == i);
|
|
|
|
PR_ASSERT(wasFound);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
DynahashDelete(PLDynahash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
MyHashElement elem;
|
|
|
|
MyHashElement* found;
|
|
|
|
PRBool wasFound = PR_FALSE;
|
|
|
|
elem.hashElement.next = NULL;
|
|
|
|
elem.key = i;
|
|
|
|
found = (MyHashElement*)PL_DynahashRemove(ht, (PLDynahashElement*)&elem);
|
|
|
|
PR_ASSERT(found);
|
|
|
|
wasFound = (PRBool)(found->value == i);
|
|
|
|
PR_ASSERT(wasFound);
|
|
|
|
free(found);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
TestDynahash(int initialSize)
|
|
|
|
{
|
|
|
|
PRUword i;
|
|
|
|
PRIntervalTime t1, t2;
|
|
|
|
PLDynahash* ht;
|
|
|
|
|
|
|
|
ht = PL_NewDynahash(initialSize,
|
|
|
|
(PLHashFun)Dynahash_HashKey,
|
|
|
|
(PLEqualFun)Dynahash_Equals,
|
|
|
|
(PLDestroyFun)Dynahash_Destroy,
|
|
|
|
NULL);
|
|
|
|
PR_ASSERT(ht);
|
|
|
|
fprintf(stdout, "dyna\t%d", initialSize);
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
DynahashAdd(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
DynahashLookup(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
DynahashDelete(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus\n", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
PL_DynahashDestroy(ht);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
Openhash_Destroy(void* context, PLOpenhashElement* elem)
|
|
|
|
{
|
|
|
|
#ifdef XP_MAC
|
|
|
|
#pragma unused(context)
|
|
|
|
#endif
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
free(elem->value);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
OpenhashAdd(PLOpenhash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
void* elem = malloc(sizeof(PRUword));
|
|
|
|
PR_ASSERT(elem != NULL);
|
|
|
|
*(PRUword*)elem = i;
|
|
|
|
#else
|
|
|
|
void* elem = (void*)i;
|
|
|
|
#endif
|
|
|
|
PL_OpenhashAdd(ht, i, elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
OpenhashLookup(PLOpenhash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
void* elem = PL_OpenhashLookup(ht, i);
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
PR_ASSERT(elem);
|
|
|
|
PR_ASSERT(*(PRUword*)elem == i);
|
|
|
|
#else
|
|
|
|
PR_ASSERT((PRUword)elem == i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
TestOpenhash(int initialSize)
|
|
|
|
{
|
|
|
|
PRUword i;
|
|
|
|
PRIntervalTime t1, t2;
|
|
|
|
PLOpenhash* ht;
|
|
|
|
|
|
|
|
ht = PL_NewOpenhash(initialSize,
|
|
|
|
(PLOpenhashHashFun)NULL,
|
|
|
|
(PLOpenhashEqualFun)NULL,
|
|
|
|
(PLOpenhashDestroyFun)Openhash_Destroy,
|
|
|
|
NULL);
|
|
|
|
PR_ASSERT(ht);
|
|
|
|
fprintf(stdout, "open\t%d", initialSize);
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
OpenhashAdd(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
OpenhashLookup(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus\n", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
PL_OpenhashDestroy(ht);
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
class EFHash : public FastHashTable<void*> {
|
|
|
|
public:
|
|
|
|
EFHash(Pool& pool) : FastHashTable<void*>(pool) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
EFHashAdd(EFHash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
void* elem = malloc(sizeof(PRUword));
|
|
|
|
PR_ASSERT(elem != NULL);
|
|
|
|
*(PRUword*)elem = i;
|
|
|
|
#else
|
|
|
|
void* elem = (void*)i;
|
|
|
|
#endif
|
|
|
|
ht->add((const char*)i, elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
EFHashLookup(EFHash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
void* elem;
|
|
|
|
bool found = ht->get((const char*)i, &elem);
|
|
|
|
PR_ASSERT(found);
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
PR_ASSERT(*(PRUword*)elem == i);
|
|
|
|
#else
|
|
|
|
PR_ASSERT((PRUword)elem == i);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
EFHashDelete(EFHash* ht, PRUword i)
|
|
|
|
{
|
|
|
|
#ifdef HASH_ALLOC
|
|
|
|
void* elem;
|
|
|
|
bool found = ht->get((const char*)i, &elem);
|
|
|
|
free(elem);
|
|
|
|
#endif
|
|
|
|
ht->remove((const char*)i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
TestEFHash()
|
|
|
|
{
|
|
|
|
PRUword i;
|
|
|
|
PRIntervalTime t1, t2;
|
|
|
|
EFHash* ht;
|
|
|
|
|
|
|
|
Pool* pool = new Pool();
|
|
|
|
PR_ASSERT(pool);
|
|
|
|
ht = new EFHash(*pool);
|
|
|
|
|
|
|
|
PR_ASSERT(ht);
|
|
|
|
fprintf(stdout, "efhash\t");
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
EFHashAdd(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
EFHashLookup(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
t1 = PR_IntervalNow();
|
|
|
|
for (i = 0; i < ITERATIONS; i++) {
|
|
|
|
EFHashDelete(ht, i);
|
|
|
|
}
|
|
|
|
t2 = PR_IntervalNow();
|
|
|
|
fprintf(stdout, "\t%ldus\n", PR_IntervalToMicroseconds(t2 - t1));
|
|
|
|
|
|
|
|
delete ht;
|
|
|
|
delete pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
int
|
|
|
|
main(void)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
PRBool success = PL_DynahashTest();
|
|
|
|
fprintf(stdout, "DynahashTest => %s\n", success ? "true" : "false");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fprintf(stdout, "SportModel: Hash table comparison tests\n");
|
|
|
|
|
|
|
|
fprintf(stdout, "\tsize\tadd\tlookup\tremove\n");
|
|
|
|
|
|
|
|
TestHashTable(1024 * 8 - 8);
|
|
|
|
TestHashTable(1024 - 8);
|
|
|
|
TestHashTable(8);
|
|
|
|
|
|
|
|
TestDynahash(1024 * 8 - 8);
|
|
|
|
TestDynahash(1024 - 8);
|
|
|
|
TestDynahash(8);
|
|
|
|
|
|
|
|
TestOpenhash(1024 * 256);
|
|
|
|
TestOpenhash(1024 * 128);
|
|
|
|
TestOpenhash(1024 * 16);
|
|
|
|
|
|
|
|
TestEFHash();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|