From patchwork Sun Mar 22 22:03:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Emil Velikov X-Patchwork-Id: 6067791 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 76F2C9F2A9 for ; Sun, 22 Mar 2015 22:00:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E93B22022D for ; Sun, 22 Mar 2015 22:00:46 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 4816D20220 for ; Sun, 22 Mar 2015 22:00:45 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 9B6506E3C4; Sun, 22 Mar 2015 15:00:44 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-wi0-f169.google.com (mail-wi0-f169.google.com [209.85.212.169]) by gabe.freedesktop.org (Postfix) with ESMTP id A9F256E3C7 for ; Sun, 22 Mar 2015 15:00:42 -0700 (PDT) Received: by wibgn9 with SMTP id gn9so43919790wib.1 for ; Sun, 22 Mar 2015 15:00:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=x+1TxJ5R7GWYkrcLTw6NQant18QBX0t3t96niF2sy/Q=; b=CatANAzK/NJebfIHdL9LRO2MysUV/5kvRucYD6ElLQU+xvvH1XAqsrId3ijns+XFnd Hwb0hoW2VlyqZ6ArLY++wGcuw1sRbwC1OyASSvMStyqAybhuP22CRN0qBEWWZvIstMK5 ZIo97u8jvkBcVjvJgkGDZW62it/iwn/aczhWJrM/uco66Dfi4byVtMZ15dphbtN6GHCu tbkN4Veh8S9wgtBQO6IADIFzj+UNCaVod3qCuL4y9M1iG6BNcScXcJpdyvTgECr1ir0O B9/bal8PKSZrpJoLzLtxKMOy6qXXRRNEi6sQ1K2ou1FrCNEGpkNLa4lEHImFWOKW4li+ BLmg== X-Received: by 10.194.157.39 with SMTP id wj7mr142312884wjb.57.1427061642017; Sun, 22 Mar 2015 15:00:42 -0700 (PDT) Received: from arch-x220.localdomain (cpc12-croy20-2-0-cust52.croy.cable.virginm.net. [82.44.54.53]) by mx.google.com with ESMTPSA id dq8sm8281654wib.9.2015.03.22.15.00.40 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 22 Mar 2015 15:00:41 -0700 (PDT) From: Emil Velikov To: dri-devel@lists.freedesktop.org Subject: [PATCH libdrm 2/9] tests/hash: extract test out of xf86drmHash.c Date: Sun, 22 Mar 2015 22:03:38 +0000 Message-Id: <1427061825-27470-3-git-send-email-emil.l.velikov@gmail.com> X-Mailer: git-send-email 2.3.1 In-Reply-To: <1427061825-27470-1-git-send-email-emil.l.velikov@gmail.com> References: <1427061825-27470-1-git-send-email-emil.l.velikov@gmail.com> Cc: emil.l.velikov@gmail.com X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This way with follow up commits we can fix it and wire it up to make check Signed-off-by: Emil Velikov --- tests/Makefile.am | 3 +- tests/hash.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ xf86drmHash.c | 174 +++---------------------------------------- 3 files changed, 231 insertions(+), 165 deletions(-) create mode 100644 tests/hash.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 10f54e3..ea826b5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -29,7 +29,8 @@ LDADD = $(top_builddir)/libdrm.la check_PROGRAMS = \ dristat \ - drmstat + drmstat \ + hash if HAVE_NOUVEAU SUBDIRS += nouveau diff --git a/tests/hash.c b/tests/hash.c new file mode 100644 index 0000000..d57d2dc --- /dev/null +++ b/tests/hash.c @@ -0,0 +1,219 @@ +/* xf86drmHash.c -- Small hash table support for integer -> integer mapping + * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith + * + * DESCRIPTION + * + * This file contains a straightforward implementation of a fixed-sized + * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for + * collision resolution. There are two potentially interesting things + * about this implementation: + * + * 1) The table is power-of-two sized. Prime sized tables are more + * traditional, but do not have a significant advantage over power-of-two + * sized table, especially when double hashing is not used for collision + * resolution. + * + * 2) The hash computation uses a table of random integers [Hanson97, + * pp. 39-41]. + * + * FUTURE ENHANCEMENTS + * + * With a table size of 512, the current implementation is sufficient for a + * few hundred keys. Since this is well above the expected size of the + * tables for which this implementation was designed, the implementation of + * dynamic hash tables was postponed until the need arises. A common (and + * naive) approach to dynamic hash table implementation simply creates a + * new hash table when necessary, rehashes all the data into the new table, + * and destroys the old table. The approach in [Larson88] is superior in + * two ways: 1) only a portion of the table is expanded when needed, + * distributing the expansion cost over several insertions, and 2) portions + * of the table can be locked, enabling a scalable thread-safe + * implementation. + * + * REFERENCES + * + * [Hanson97] David R. Hanson. C Interfaces and Implementations: + * Techniques for Creating Reusable Software. Reading, Massachusetts: + * Addison-Wesley, 1997. + * + * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: + * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. + * + * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April + * 1988, pp. 446-457. + * + */ + +#include +#include + +#include "xf86drm.h" + +#define HASH_SIZE 512 /* Good for about 100 entries */ + /* If you change this value, you probably + have to change the HashHash hashing + function! */ + +typedef struct HashBucket { + unsigned long key; + void *value; + struct HashBucket *next; +} HashBucket, *HashBucketPtr; + +typedef struct HashTable { + unsigned long magic; + unsigned long entries; + unsigned long hits; /* At top of linked list */ + unsigned long partials; /* Not at top of linked list */ + unsigned long misses; /* Not in table */ + HashBucketPtr buckets[HASH_SIZE]; + int p0; + HashBucketPtr p1; +} HashTable, *HashTablePtr; + +#define DIST_LIMIT 10 +static int dist[DIST_LIMIT]; + +static void clear_dist(void) { + int i; + + for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; +} + +static int count_entries(HashBucketPtr bucket) +{ + int count = 0; + + for (; bucket; bucket = bucket->next) ++count; + return count; +} + +static void update_dist(int count) +{ + if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; + else ++dist[count]; +} + +static void compute_dist(HashTablePtr table) +{ + int i; + HashBucketPtr bucket; + + printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", + table->entries, table->hits, table->partials, table->misses); + clear_dist(); + for (i = 0; i < HASH_SIZE; i++) { + bucket = table->buckets[i]; + update_dist(count_entries(bucket)); + } + for (i = 0; i < DIST_LIMIT; i++) { + if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); + else printf("other %10d\n", dist[i]); + } +} + +static void check_table(HashTablePtr table, + unsigned long key, unsigned long value) +{ + unsigned long retval = 0; + int retcode = drmHashLookup(table, key, &retval); + + switch (retcode) { + case -1: + printf("Bad magic = 0x%08lx:" + " key = %lu, expected = %lu, returned = %lu\n", + table->magic, key, value, retval); + break; + case 1: + printf("Not found: key = %lu, expected = %lu returned = %lu\n", + key, value, retval); + break; + case 0: + if (value != retval) + printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", + key, value, retval); + break; + default: + printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", + retcode, key, value, retval); + break; + } +} + +int main(void) +{ + HashTablePtr table; + int i; + + printf("\n***** 256 consecutive integers ****\n"); + table = drmHashCreate(); + for (i = 0; i < 256; i++) drmHashInsert(table, i, i); + for (i = 0; i < 256; i++) check_table(table, i, i); + for (i = 256; i >= 0; i--) check_table(table, i, i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 consecutive integers ****\n"); + table = drmHashCreate(); + for (i = 0; i < 1024; i++) drmHashInsert(table, i, i); + for (i = 0; i < 1024; i++) check_table(table, i, i); + for (i = 1024; i >= 0; i--) check_table(table, i, i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); + table = drmHashCreate(); + for (i = 0; i < 1024; i++) drmHashInsert(table, i*4096, i); + for (i = 0; i < 1024; i++) check_table(table, i*4096, i); + for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 random integers ****\n"); + table = drmHashCreate(); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) drmHashInsert(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) check_table(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) check_table(table, random(), i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 5000 random integers ****\n"); + table = drmHashCreate(); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) drmHashInsert(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) check_table(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) check_table(table, random(), i); + compute_dist(table); + drmHashDestroy(table); + + return 0; +} diff --git a/xf86drmHash.c b/xf86drmHash.c index 82cbc2a..82512a8 100644 --- a/xf86drmHash.c +++ b/xf86drmHash.c @@ -71,11 +71,7 @@ #include #include -#define HASH_MAIN 0 - -#if !HASH_MAIN -# include "xf86drm.h" -#endif +#include "xf86drm.h" #define HASH_MAGIC 0xdeadbeef #define HASH_DEBUG 0 @@ -84,23 +80,6 @@ have to change the HashHash hashing function! */ -#if HASH_MAIN -#define HASH_ALLOC malloc -#define HASH_FREE free -#define HASH_RANDOM_DECL -#define HASH_RANDOM_INIT(seed) srandom(seed) -#define HASH_RANDOM random() -#define HASH_RANDOM_DESTROY -#else -#define HASH_ALLOC drmMalloc -#define HASH_FREE drmFree -#define HASH_RANDOM_DECL void *state -#define HASH_RANDOM_INIT(seed) state = drmRandomCreate(seed) -#define HASH_RANDOM drmRandom(state) -#define HASH_RANDOM_DESTROY drmRandomDestroy(state) - -#endif - typedef struct HashBucket { unsigned long key; void *value; @@ -118,14 +97,6 @@ typedef struct HashTable { HashBucketPtr p1; } HashTable, *HashTablePtr; -#if HASH_MAIN -extern void *drmHashCreate(void); -extern int drmHashDestroy(void *t); -extern int drmHashLookup(void *t, unsigned long key, unsigned long *value); -extern int drmHashInsert(void *t, unsigned long key, unsigned long value); -extern int drmHashDelete(void *t, unsigned long key); -#endif - static unsigned long HashHash(unsigned long key) { unsigned long hash = 0; @@ -135,10 +106,10 @@ static unsigned long HashHash(unsigned long key) int i; if (!init) { - HASH_RANDOM_DECL; - HASH_RANDOM_INIT(37); - for (i = 0; i < 256; i++) scatter[i] = HASH_RANDOM; - HASH_RANDOM_DESTROY; + void *state; + state = drmRandomCreate(37); + for (i = 0; i < 256; i++) scatter[i] = drmRandom(state); + drmRandomDestroy(state); ++init; } @@ -159,7 +130,7 @@ void *drmHashCreate(void) HashTablePtr table; int i; - table = HASH_ALLOC(sizeof(*table)); + table = drmMalloc(sizeof(*table)); if (!table) return NULL; table->magic = HASH_MAGIC; table->entries = 0; @@ -183,11 +154,11 @@ int drmHashDestroy(void *t) for (i = 0; i < HASH_SIZE; i++) { for (bucket = table->buckets[i]; bucket;) { next = bucket->next; - HASH_FREE(bucket); + drmFree(bucket); bucket = next; } } - HASH_FREE(table); + drmFree(table); return 0; } @@ -245,7 +216,7 @@ int drmHashInsert(void *t, unsigned long key, void *value) if (HashFind(table, key, &hash)) return 1; /* Already in table */ - bucket = HASH_ALLOC(sizeof(*bucket)); + bucket = drmMalloc(sizeof(*bucket)); if (!bucket) return -1; /* Error */ bucket->key = key; bucket->value = value; @@ -270,7 +241,7 @@ int drmHashDelete(void *t, unsigned long key) if (!bucket) return 1; /* Not found */ table->buckets[hash] = bucket->next; - HASH_FREE(bucket); + drmFree(bucket); return 0; } @@ -301,128 +272,3 @@ int drmHashFirst(void *t, unsigned long *key, void **value) table->p1 = table->buckets[0]; return drmHashNext(table, key, value); } - -#if HASH_MAIN -#define DIST_LIMIT 10 -static int dist[DIST_LIMIT]; - -static void clear_dist(void) { - int i; - - for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; -} - -static int count_entries(HashBucketPtr bucket) -{ - int count = 0; - - for (; bucket; bucket = bucket->next) ++count; - return count; -} - -static void update_dist(int count) -{ - if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; - else ++dist[count]; -} - -static void compute_dist(HashTablePtr table) -{ - int i; - HashBucketPtr bucket; - - printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", - table->entries, table->hits, table->partials, table->misses); - clear_dist(); - for (i = 0; i < HASH_SIZE; i++) { - bucket = table->buckets[i]; - update_dist(count_entries(bucket)); - } - for (i = 0; i < DIST_LIMIT; i++) { - if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); - else printf("other %10d\n", dist[i]); - } -} - -static void check_table(HashTablePtr table, - unsigned long key, unsigned long value) -{ - unsigned long retval = 0; - int retcode = drmHashLookup(table, key, &retval); - - switch (retcode) { - case -1: - printf("Bad magic = 0x%08lx:" - " key = %lu, expected = %lu, returned = %lu\n", - table->magic, key, value, retval); - break; - case 1: - printf("Not found: key = %lu, expected = %lu returned = %lu\n", - key, value, retval); - break; - case 0: - if (value != retval) - printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", - key, value, retval); - break; - default: - printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", - retcode, key, value, retval); - break; - } -} - -int main(void) -{ - HashTablePtr table; - int i; - - printf("\n***** 256 consecutive integers ****\n"); - table = drmHashCreate(); - for (i = 0; i < 256; i++) drmHashInsert(table, i, i); - for (i = 0; i < 256; i++) check_table(table, i, i); - for (i = 256; i >= 0; i--) check_table(table, i, i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 1024 consecutive integers ****\n"); - table = drmHashCreate(); - for (i = 0; i < 1024; i++) drmHashInsert(table, i, i); - for (i = 0; i < 1024; i++) check_table(table, i, i); - for (i = 1024; i >= 0; i--) check_table(table, i, i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); - table = drmHashCreate(); - for (i = 0; i < 1024; i++) drmHashInsert(table, i*4096, i); - for (i = 0; i < 1024; i++) check_table(table, i*4096, i); - for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 1024 random integers ****\n"); - table = drmHashCreate(); - srandom(0xbeefbeef); - for (i = 0; i < 1024; i++) drmHashInsert(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 1024; i++) check_table(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 1024; i++) check_table(table, random(), i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 5000 random integers ****\n"); - table = drmHashCreate(); - srandom(0xbeefbeef); - for (i = 0; i < 5000; i++) drmHashInsert(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 5000; i++) check_table(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 5000; i++) check_table(table, random(), i); - compute_dist(table); - drmHashDestroy(table); - - return 0; -} -#endif