From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28394 invoked by alias); 8 Jul 2004 19:16:57 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 28305 invoked from network); 8 Jul 2004 19:16:46 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org with SMTP; 8 Jul 2004 19:16:46 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.12.10/8.12.10) with ESMTP id i68JB5e1032199 for ; Thu, 8 Jul 2004 15:11:12 -0400 Received: from pobox.toronto.redhat.com (pobox.toronto.redhat.com [172.16.14.4]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id i68JB2001286 for ; Thu, 8 Jul 2004 15:11:02 -0400 Received: from touchme.toronto.redhat.com (IDENT:postfix@touchme.toronto.redhat.com [172.16.14.9]) by pobox.toronto.redhat.com (8.12.8/8.12.8) with ESMTP id i68JB0vU007432 for ; Thu, 8 Jul 2004 15:11:00 -0400 Received: from toenail (toenail.toronto.redhat.com [172.16.14.211]) by touchme.toronto.redhat.com (Postfix) with ESMTP id 2396C8001D0 for ; Thu, 8 Jul 2004 15:11:00 -0400 (EDT) Received: from toenail.toronto.redhat.com (localhost.localdomain [127.0.0.1]) by toenail (8.12.10/8.12.5) with ESMTP id i68JAxxj032649 for ; Thu, 8 Jul 2004 15:10:59 -0400 Received: (from fche@localhost) by toenail.toronto.redhat.com (8.12.10/8.12.10/Submit) id i68JAwSk032647 for gcc-patches@gcc.gnu.org; Thu, 8 Jul 2004 15:10:59 -0400 Date: Thu, 08 Jul 2004 20:07:00 -0000 From: "Frank Ch. Eigler" To: gcc-patches@gcc.gnu.org Subject: [libmudflap] splay tree improvements Message-ID: <20040708191058.GA32637@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i X-SW-Source: 2004-07/txt/msg00826.txt.bz2 Hi - I've been in discussion with RMS about how to let the splay-tree code be used in libmudflap (recall the gpl vs libgcc licensing issue that some brought up). It appears to be leading toward acceptance if the code is specialized more, in essence forked, for use in libmudflap. So I've been making numerous specialization changes toward this end in the interim. One big change is to let the code tolerate degenerate access patterns without running out of stack space with its recursive algorithms. The attached patch includes code to back out of excessive recursion during searches, rebalance the entire binary tree, and try again. A test case submitted by a contributor illustrates how easily such degenerate tree topologies can be created. - FChE 2004-07-08 Frank Ch. Eigler ANSI C conversion, libmudflap specialization, recursion limiting. * splay-tree.h (splay_tree_{de,}allocate_fn): Remove allocation_data argument and indirection function pointers, update callers. (splay_tree_s): Add statistics and recursion control fields num_keys, max_depth, depth, rebalance_p. * splay-tree.c (splay_tree_splay_helper): Track recursion depth. Back out of search if it exceeds limit. (splay_tree_splay): Manage recursion limiting with rebalancing as needed. (splay_tree_new): More initialization. (splay_tree_rebalance): New function. (splay_tree_foreach): Rewrite using nonrecursive logic. (splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate): Remove. Point indirect calls to mf-runtime.c's routines. (splay_tree_compare_ints, splay_tree_compare_pointers): Remove unused functions. (splay_tree_delete, splay_tree_delete_helper): Ditto. * testsuite/heap-scalestress.c: New test based on one from Eyal Lebedinsky : Index: splay-tree.c =================================================================== RCS file: /cvs/gcc/gcc/libmudflap/splay-tree.c,v retrieving revision 1.1 diff -c -p -s -w -r1.1 splay-tree.c *** splay-tree.c 29 Jun 2004 22:30:53 -0000 1.1 --- splay-tree.c 8 Jul 2004 18:58:30 -0000 *************** Boston, MA 02111-1307, USA. */ *** 38,57 **** #include #include "splay-tree.h" ! static void splay_tree_delete_helper PARAMS((splay_tree, ! splay_tree_node)); ! static void splay_tree_splay PARAMS((splay_tree, ! splay_tree_key)); ! static splay_tree_node splay_tree_splay_helper ! PARAMS((splay_tree, splay_tree_key, splay_tree_node*, splay_tree_node*, ! splay_tree_node*)); ! static int splay_tree_foreach_helper PARAMS((splay_tree, ! splay_tree_node, ! splay_tree_foreach_fn, ! void*)); --- 38,53 ---- #include #include "splay-tree.h" ! ! static void splay_tree_delete_helper (splay_tree, splay_tree_node); ! static void splay_tree_splay (splay_tree, splay_tree_key); ! static splay_tree_node splay_tree_splay_helper (splay_tree, splay_tree_key, splay_tree_node *, splay_tree_node *, ! splay_tree_node *); ! static void *splay_tree_xmalloc (size_t size); ! static void splay_tree_free (void *object); *************** compare_uintptr_t (splay_tree_key k1, sp *** 68,99 **** } - - /* Deallocate NODE (a member of SP), and all its sub-trees. */ - - static void - splay_tree_delete_helper (sp, node) - splay_tree sp; - splay_tree_node node; - { - if (!node) - return; - - splay_tree_delete_helper (sp, node->left); - splay_tree_delete_helper (sp, node->right); - (*sp->deallocate) ((char*) node, sp->allocate_data); - } - /* Help splay SP around KEY. PARENT and GRANDPARENT are the parent and grandparent, respectively, of NODE. */ static splay_tree_node ! splay_tree_splay_helper (sp, key, node, parent, grandparent) ! splay_tree sp; ! splay_tree_key key; ! splay_tree_node *node; ! splay_tree_node *parent; ! splay_tree_node *grandparent; { splay_tree_node *next; splay_tree_node n; --- 64,78 ---- } /* Help splay SP around KEY. PARENT and GRANDPARENT are the parent and grandparent, respectively, of NODE. */ static splay_tree_node ! splay_tree_splay_helper (splay_tree sp, ! splay_tree_key key, ! splay_tree_node * node, ! splay_tree_node * parent, ! splay_tree_node * grandparent) { splay_tree_node *next; splay_tree_node n; *************** splay_tree_splay_helper (sp, key, node, *** 118,129 **** if (next) { /* Continue down the tree. */ n = splay_tree_splay_helper (sp, key, next, node, parent); /* The recursive call will change the place to which NODE points. */ ! if (*node != n) return n; } --- 97,118 ---- if (next) { + /* Check whether our recursion depth is too high. Abort this search, + and signal that a rebalance is required to continue. */ + if (sp->depth > sp->max_depth) + { + sp->rebalance_p = 1; + return n; + } + /* Continue down the tree. */ + sp->depth ++; n = splay_tree_splay_helper (sp, key, next, node, parent); + sp->depth --; /* The recursive call will change the place to which NODE points. */ ! if (*node != n || sp->rebalance_p) return n; } *************** splay_tree_splay_helper (sp, key, node, *** 196,312 **** } } - /* Splay SP around KEY. */ ! static void ! splay_tree_splay (sp, key) ! splay_tree sp; ! splay_tree_key key; { ! if (sp->root == 0) ! return; - /* If we just splayed the tree with the same key, do nothing. */ - if (sp->last_splayed_key_p && - compare_uintptr_t (sp->last_splayed_key, key) == 0) - return; ! splay_tree_splay_helper (sp, key, &sp->root, ! /*grandparent=*/0, /*parent=*/0); ! /* Cache this splay key. */ ! sp->last_splayed_key = key; ! sp->last_splayed_key_p = 1; } - /* Call FN, passing it the DATA, for every node below NODE, all of - which are from SP, following an in-order traversal. If FN every - returns a non-zero value, the iteration ceases immediately, and the - value is returned. Otherwise, this function returns 0. */ ! static int ! splay_tree_foreach_helper (sp, node, fn, data) ! splay_tree sp; ! splay_tree_node node; ! splay_tree_foreach_fn fn; ! void* data; { ! int val; ! if (!node) ! return 0; ! val = splay_tree_foreach_helper (sp, node->left, fn, data); ! if (val) ! return val; ! val = (*fn)(node, data); ! if (val) ! return val; ! return splay_tree_foreach_helper (sp, node->right, fn, data); } ! /* An allocator and deallocator based on xmalloc. */ ! static void * ! splay_tree_xmalloc_allocate (size, data) ! int size; ! void *data ATTRIBUTE_UNUSED; { ! return (void *) xmalloc (size); } ! static void ! splay_tree_xmalloc_deallocate (object, data) ! void *object; ! void *data ATTRIBUTE_UNUSED; ! { ! free (object); } - /* Allocate a new splay tree, using COMPARE_FN to compare nodes, - DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate - values. Use xmalloc to allocate the splay tree structure, and any - nodes added. */ splay_tree splay_tree_new () { ! splay_tree_allocate_fn allocate_fn = splay_tree_xmalloc_allocate; ! splay_tree_deallocate_fn deallocate_fn = splay_tree_xmalloc_deallocate; ! void *allocate_data = NULL; ! splay_tree sp = (splay_tree) (*allocate_fn) (sizeof (struct splay_tree_s), ! allocate_data); ! sp->root = 0; ! sp->allocate = allocate_fn; ! sp->deallocate = deallocate_fn; ! sp->allocate_data = allocate_data; sp->last_splayed_key_p = 0; return sp; } - /* Deallocate SP. */ - void - splay_tree_delete (sp) - splay_tree sp; - { - splay_tree_delete_helper (sp, sp->root); - (*sp->deallocate) ((char*) sp, sp->allocate_data); - } /* Insert a new node (associating KEY with DATA) into SP. If a previous node with the indicated KEY exists, its data is replaced with the new value. Returns the new node. */ - splay_tree_node ! splay_tree_insert (sp, key, value) ! splay_tree sp; ! splay_tree_key key; ! splay_tree_value value; { int comparison = 0; --- 185,312 ---- } } ! ! static int ! splay_tree_rebalance_helper1 (splay_tree_node n, void *array_ptr) { ! splay_tree_node **p = array_ptr; ! *(*p) = n; ! (*p)++; ! return 0; ! } ! static splay_tree_node ! splay_tree_rebalance_helper2 (splay_tree_node * array, unsigned low, ! unsigned high) ! { ! unsigned middle = low + (high - low) / 2; ! splay_tree_node n = array[middle]; ! /* Note that since we're producing a balanced binary tree, it is not a problem ! that this function is recursive. */ ! if (low + 1 <= middle) ! n->left = splay_tree_rebalance_helper2 (array, low, middle - 1); ! else ! n->left = NULL; ! ! if (middle + 1 <= high) ! n->right = splay_tree_rebalance_helper2 (array, middle + 1, high); ! else ! n->right = NULL; ! ! return n; } ! /* Rebalance the entire tree. Do this by copying all the node ! pointers into an array, then cleverly re-linking them. */ ! void ! splay_tree_rebalance (splay_tree sp) { ! splay_tree_node *all_nodes, *all_nodes_1; ! if (sp->num_keys <= 2) ! return; ! all_nodes = splay_tree_xmalloc (sizeof (splay_tree_node) * sp->num_keys); ! /* Traverse all nodes to copy their addresses into this array. */ ! all_nodes_1 = all_nodes; ! splay_tree_foreach (sp, splay_tree_rebalance_helper1, ! (void *) &all_nodes_1); ! ! /* Relink all the nodes. */ ! sp->root = splay_tree_rebalance_helper2 (all_nodes, 0, sp->num_keys - 1); ! splay_tree_free (all_nodes); } ! /* Splay SP around KEY. */ ! static void ! splay_tree_splay (splay_tree sp, splay_tree_key key) ! { ! if (sp->root == 0) ! return; ! ! /* If we just splayed the tree with the same key, do nothing. */ ! if (sp->last_splayed_key_p && ! compare_uintptr_t (sp->last_splayed_key, key) == 0) ! return; ! ! /* Compute a maximum recursion depth for a splay tree with NUM nodes. ! The idea is to limit excessive stack usage if we're facing ! degenerate access patterns. Unfortunately such patterns can occur ! e.g. during static initialization, where many static objects might ! be registered in increasing address sequence, or during a case where ! large tree-like heap data structures are allocated quickly. ! ! On x86, this corresponds to roughly 200K of stack usage. ! XXX: For libmudflapth, this could be a function of __mf_opts.thread_stack. */ ! sp->max_depth = 2500; ! sp->rebalance_p = sp->depth = 0; ! ! splay_tree_splay_helper (sp, key, &sp->root, NULL, NULL); ! if (sp->rebalance_p) { ! splay_tree_rebalance (sp); ! ! sp->rebalance_p = sp->depth = 0; ! splay_tree_splay_helper (sp, key, &sp->root, NULL, NULL); ! ! if (sp->rebalance_p) ! abort (); } ! ! /* Cache this splay key. */ ! sp->last_splayed_key = key; ! sp->last_splayed_key_p = 1; } + /* Allocate a new splay tree. */ splay_tree splay_tree_new () { ! splay_tree sp = splay_tree_xmalloc (sizeof (struct splay_tree_s)); ! sp->root = NULL; sp->last_splayed_key_p = 0; + sp->num_keys = 0; return sp; } /* Insert a new node (associating KEY with DATA) into SP. If a previous node with the indicated KEY exists, its data is replaced with the new value. Returns the new node. */ splay_tree_node ! splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value) { int comparison = 0; *************** splay_tree_insert (sp, key, value) *** 326,337 **** /* Create a new node, and insert it at the root. */ splay_tree_node node; ! node = ((splay_tree_node) ! (*sp->allocate) (sizeof (struct splay_tree_node_s), ! sp->allocate_data)); node->key = key; node->value = value; ! if (!sp->root) node->left = node->right = 0; else if (comparison < 0) --- 326,335 ---- /* Create a new node, and insert it at the root. */ splay_tree_node node; ! node = splay_tree_xmalloc (sizeof (struct splay_tree_node_s)); node->key = key; node->value = value; ! sp->num_keys++; if (!sp->root) node->left = node->right = 0; else if (comparison < 0) *************** splay_tree_insert (sp, key, value) *** 357,385 **** /* Remove KEY from SP. It is not an error if it did not exist. */ void ! splay_tree_remove (sp, key) ! splay_tree sp; ! splay_tree_key key; { splay_tree_splay (sp, key); sp->last_splayed_key_p = 0; - if (sp->root && compare_uintptr_t (sp->root->key, key) == 0) { splay_tree_node left, right; - left = sp->root->left; right = sp->root->right; - /* Delete the root node itself. */ ! (*sp->deallocate) (sp->root, sp->allocate_data); ! /* One of the children is now the root. Doesn't matter much which, so long as we preserve the properties of the tree. */ if (left) { sp->root = left; - /* If there was a right child as well, hang it off the right-most leaf of the left child. */ if (right) --- 355,377 ---- /* Remove KEY from SP. It is not an error if it did not exist. */ void ! splay_tree_remove (splay_tree sp, splay_tree_key key) { splay_tree_splay (sp, key); sp->last_splayed_key_p = 0; if (sp->root && compare_uintptr_t (sp->root->key, key) == 0) { splay_tree_node left, right; left = sp->root->left; right = sp->root->right; /* Delete the root node itself. */ ! splay_tree_free (sp->root); ! sp->num_keys--; /* One of the children is now the root. Doesn't matter much which, so long as we preserve the properties of the tree. */ if (left) { sp->root = left; /* If there was a right child as well, hang it off the right-most leaf of the left child. */ if (right) *************** splay_tree_remove (sp, key) *** 398,409 **** otherwise. */ splay_tree_node ! splay_tree_lookup (sp, key) ! splay_tree sp; ! splay_tree_key key; { splay_tree_splay (sp, key); - if (sp->root && compare_uintptr_t (sp->root->key, key) == 0) return sp->root; else --- 390,398 ---- otherwise. */ splay_tree_node ! splay_tree_lookup (splay_tree sp, splay_tree_key key) { splay_tree_splay (sp, key); if (sp->root && compare_uintptr_t (sp->root->key, key) == 0) return sp->root; else *************** splay_tree_lookup (sp, key) *** 413,446 **** /* Return the node in SP with the greatest key. */ splay_tree_node ! splay_tree_max (sp) ! splay_tree sp; { splay_tree_node n = sp->root; - if (!n) return NULL; - while (n->right) n = n->right; - return n; } /* Return the node in SP with the smallest key. */ splay_tree_node ! splay_tree_min (sp) ! splay_tree sp; { splay_tree_node n = sp->root; - if (!n) return NULL; - while (n->left) n = n->left; - return n; } --- 402,427 ---- /* Return the node in SP with the greatest key. */ splay_tree_node ! splay_tree_max (splay_tree sp) { splay_tree_node n = sp->root; if (!n) return NULL; while (n->right) n = n->right; return n; } /* Return the node in SP with the smallest key. */ splay_tree_node ! splay_tree_min (splay_tree sp) { splay_tree_node n = sp->root; if (!n) return NULL; while (n->left) n = n->left; return n; } *************** splay_tree_min (sp) *** 448,479 **** predecessor. KEY need not be present in the tree. */ splay_tree_node ! splay_tree_predecessor (sp, key) ! splay_tree sp; ! splay_tree_key key; { int comparison; splay_tree_node node; - /* If the tree is empty, there is certainly no predecessor. */ if (!sp->root) return NULL; - /* Splay the tree around KEY. That will leave either the KEY itself, its predecessor, or its successor at the root. */ splay_tree_splay (sp, key); comparison = compare_uintptr_t (sp->root->key, key); - /* If the predecessor is at the root, just return it. */ if (comparison < 0) return sp->root; - /* Otherwise, find the rightmost element of the left subtree. */ node = sp->root->left; if (node) while (node->right) node = node->right; - return node; } --- 429,453 ---- predecessor. KEY need not be present in the tree. */ splay_tree_node ! splay_tree_predecessor (splay_tree sp, splay_tree_key key) { int comparison; splay_tree_node node; /* If the tree is empty, there is certainly no predecessor. */ if (!sp->root) return NULL; /* Splay the tree around KEY. That will leave either the KEY itself, its predecessor, or its successor at the root. */ splay_tree_splay (sp, key); comparison = compare_uintptr_t (sp->root->key, key); /* If the predecessor is at the root, just return it. */ if (comparison < 0) return sp->root; /* Otherwise, find the rightmost element of the left subtree. */ node = sp->root->left; if (node) while (node->right) node = node->right; return node; } *************** splay_tree_predecessor (sp, key) *** 481,525 **** successor. KEY need not be present in the tree. */ splay_tree_node ! splay_tree_successor (sp, key) ! splay_tree sp; ! splay_tree_key key; { int comparison; splay_tree_node node; - /* If the tree is empty, there is certainly no successor. */ if (!sp->root) return NULL; - /* Splay the tree around KEY. That will leave either the KEY itself, its predecessor, or its successor at the root. */ splay_tree_splay (sp, key); comparison = compare_uintptr_t (sp->root->key, key); - /* If the successor is at the root, just return it. */ if (comparison > 0) return sp->root; - /* Otherwise, find the leftmost element of the right subtree. */ node = sp->root->right; if (node) while (node->left) node = node->left; - return node; } /* Call FN, passing it the DATA, for every node in SP, following an in-order traversal. If FN every returns a non-zero value, the iteration ceases immediately, and the value is returned. ! Otherwise, this function returns 0. */ int ! splay_tree_foreach (sp, fn, data) ! splay_tree sp; ! splay_tree_foreach_fn fn; ! void *data; { ! return splay_tree_foreach_helper (sp, sp->root, fn, data); } --- 455,565 ---- successor. KEY need not be present in the tree. */ splay_tree_node ! splay_tree_successor (splay_tree sp, splay_tree_key key) { int comparison; splay_tree_node node; /* If the tree is empty, there is certainly no successor. */ if (!sp->root) return NULL; /* Splay the tree around KEY. That will leave either the KEY itself, its predecessor, or its successor at the root. */ splay_tree_splay (sp, key); comparison = compare_uintptr_t (sp->root->key, key); /* If the successor is at the root, just return it. */ if (comparison > 0) return sp->root; /* Otherwise, find the leftmost element of the right subtree. */ node = sp->root->right; if (node) while (node->left) node = node->left; return node; } /* Call FN, passing it the DATA, for every node in SP, following an in-order traversal. If FN every returns a non-zero value, the iteration ceases immediately, and the value is returned. ! Otherwise, this function returns 0. + This function simulates recursion using dynamically allocated + arrays, since it may be called from splay_tree_rebalance(), which + in turn means that the tree is already uncomfortably deep for stack + space limits. */ int ! splay_tree_foreach (splay_tree st, splay_tree_foreach_fn fn, void *data) { ! splay_tree_node *stack1; ! char *stack2; ! unsigned sp; ! int val = 0; ! enum s { s_left, s_here, s_right, s_up }; ! ! if (st->root == NULL) /* => num_keys == 0 */ ! return 0; ! ! stack1 = splay_tree_xmalloc (sizeof (splay_tree_node) * st->num_keys); ! stack2 = splay_tree_xmalloc (sizeof (char) * st->num_keys); ! ! sp = 0; ! stack1 [sp] = st->root; ! stack2 [sp] = s_left; ! ! while (1) ! { ! splay_tree_node n; ! enum s s; ! ! n = stack1 [sp]; ! s = stack2 [sp]; ! ! /* Handle each of the four possible states separately. */ ! ! /* 1: We're here to traverse the left subtree (if any). */ ! if (s == s_left) ! { ! stack2 [sp] = s_here; ! if (n->left != NULL) ! { ! sp ++; ! stack1 [sp] = n->left; ! stack2 [sp] = s_left; ! } ! } ! ! /* 2: We're here to traverse this node. */ ! else if (s == s_here) ! { ! stack2 [sp] = s_right; ! val = (*fn) (n, data); ! if (val) break; ! } ! ! /* 3: We're here to traverse the right subtree (if any). */ ! else if (s == s_right) ! { ! stack2 [sp] = s_up; ! if (n->right != NULL) ! { ! sp ++; ! stack1 [sp] = n->right; ! stack2 [sp] = s_left; ! } ! } ! ! /* 4: We're here after both subtrees (if any) have been traversed. */ ! else if (s == s_up) ! { ! /* Pop the stack. */ ! if (sp == 0) break; /* Popping off the root note: we're finished! */ ! sp --; ! } ! ! else ! abort (); ! } ! ! splay_tree_free (stack1); ! splay_tree_free (stack2); ! return val; } Index: splay-tree.h =================================================================== RCS file: /cvs/gcc/gcc/libmudflap/splay-tree.h,v retrieving revision 1.1 diff -c -p -s -w -r1.1 splay-tree.h *** splay-tree.h 29 Jun 2004 22:30:53 -0000 1.1 --- splay-tree.h 8 Jul 2004 18:58:31 -0000 *************** *** 1,7 **** /* A splay-tree datatype. Copyright 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. Contributed by Mark Mitchell (mark@markmitchell.com). ! Adapted for libmudflap from libiberty. This file is part of GCC. --- 1,7 ---- /* A splay-tree datatype. Copyright 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. Contributed by Mark Mitchell (mark@markmitchell.com). ! Adapted for libmudflap from libiberty by Frank Ch. Eigler . This file is part of GCC. *************** Boston, MA 02111-1307, USA. */ *** 26,48 **** Algorithms. Harper-Collins, Inc. 1991. The major feature of splay trees is that all basic tree operations ! are amortized O(log n) time for a tree with n nodes. */ #ifndef _SPLAY_TREE_H #define _SPLAY_TREE_H - #ifdef __cplusplus - extern "C" { - #endif /* __cplusplus */ - - #define PARAMS(X) X - #define PTR void * - #define ATTRIBUTE_UNUSED __attribute__((__unused__)) - - #ifndef GTY - #define GTY(X) - #endif - /* Use typedefs for the key and data types to facilitate changing these types, if necessary. These types should be sufficiently wide that any pointer or scalar can be cast to these types, and then --- 26,41 ---- Algorithms. Harper-Collins, Inc. 1991. The major feature of splay trees is that all basic tree operations ! are amortized O(log n) time for a tree with n nodes. ! ! This version has been further modified to periodically rebalance ! the entire tree, should degenerate access patterns result in a very ! lopsided tree. ! */ #ifndef _SPLAY_TREE_H #define _SPLAY_TREE_H /* Use typedefs for the key and data types to facilitate changing these types, if necessary. These types should be sufficiently wide that any pointer or scalar can be cast to these types, and then *************** typedef void *splay_tree_value; *** 54,136 **** typedef struct splay_tree_node_s *splay_tree_node; /* The type of a function used to iterate over the tree. */ ! typedef int (*splay_tree_foreach_fn) PARAMS((splay_tree_node, void*)); ! ! /* The type of a function used to allocate memory for tree root and ! node structures. The first argument is the number of bytes needed; ! the second is a data pointer the splay tree functions pass through ! to the allocator. This function must never return zero. */ ! typedef PTR (*splay_tree_allocate_fn) PARAMS((int, void *)); ! ! /* The type of a function used to free memory allocated using the ! corresponding splay_tree_allocate_fn. The first argument is the ! memory to be freed; the latter is a data pointer the splay tree ! functions pass through to the freer. */ ! typedef void (*splay_tree_deallocate_fn) PARAMS((void *, void *)); /* The nodes in the splay tree. */ ! struct splay_tree_node_s GTY(()) { ! /* The key. */ ! splay_tree_key GTY ((use_param1)) key; ! ! /* The value. */ ! splay_tree_value GTY ((use_param2)) value; ! ! /* The left and right children, respectively. */ ! splay_tree_node GTY ((use_params)) left; ! splay_tree_node GTY ((use_params)) right; }; /* The splay tree itself. */ ! struct splay_tree_s GTY(()) { /* The root of the tree. */ ! splay_tree_node GTY ((use_params)) root; ! ! /* Allocate/free functions, and a data pointer to pass to them. */ ! splay_tree_allocate_fn allocate; ! splay_tree_deallocate_fn deallocate; ! PTR GTY((skip)) allocate_data; /* The last key value for which the tree has been splayed, but not since modified. */ ! splay_tree_key GTY ((use_param1)) last_splayed_key; int last_splayed_key_p; }; typedef struct splay_tree_s *splay_tree; ! extern splay_tree splay_tree_new PARAMS((void)); ! extern void splay_tree_delete PARAMS((splay_tree)); ! extern splay_tree_node splay_tree_insert ! PARAMS((splay_tree, ! splay_tree_key, ! splay_tree_value)); ! extern void splay_tree_remove PARAMS((splay_tree, ! splay_tree_key)); ! extern splay_tree_node splay_tree_lookup ! PARAMS((splay_tree, ! splay_tree_key)); ! extern splay_tree_node splay_tree_predecessor ! PARAMS((splay_tree, ! splay_tree_key)); ! extern splay_tree_node splay_tree_successor ! PARAMS((splay_tree, ! splay_tree_key)); ! extern splay_tree_node splay_tree_max ! PARAMS((splay_tree)); ! extern splay_tree_node splay_tree_min ! PARAMS((splay_tree)); ! extern int splay_tree_foreach PARAMS((splay_tree, ! splay_tree_foreach_fn, ! void*)); ! extern int splay_tree_compare_ints PARAMS((splay_tree_key, ! splay_tree_key)); ! extern int splay_tree_compare_pointers PARAMS((splay_tree_key, ! splay_tree_key)); ! ! #ifdef __cplusplus ! } ! #endif /* __cplusplus */ #endif /* _SPLAY_TREE_H */ --- 47,96 ---- typedef struct splay_tree_node_s *splay_tree_node; /* The type of a function used to iterate over the tree. */ ! typedef int (*splay_tree_foreach_fn) (splay_tree_node, void *); /* The nodes in the splay tree. */ ! struct splay_tree_node_s { ! /* Data. */ ! splay_tree_key key; ! splay_tree_value value; ! /* Children. */ ! splay_tree_node left; ! splay_tree_node right; }; /* The splay tree itself. */ ! struct splay_tree_s { /* The root of the tree. */ ! splay_tree_node root; /* The last key value for which the tree has been splayed, but not since modified. */ ! splay_tree_key last_splayed_key; int last_splayed_key_p; + + /* Statistics. */ + unsigned num_keys; + + /* Traversal recursion control flags. */ + unsigned max_depth; + unsigned depth; + unsigned rebalance_p; }; typedef struct splay_tree_s *splay_tree; ! extern splay_tree splay_tree_new (void); ! extern splay_tree_node splay_tree_insert (splay_tree, splay_tree_key, splay_tree_value); ! extern void splay_tree_remove (splay_tree, splay_tree_key); ! extern splay_tree_node splay_tree_lookup (splay_tree, splay_tree_key); ! extern splay_tree_node splay_tree_predecessor (splay_tree, splay_tree_key); ! extern splay_tree_node splay_tree_successor (splay_tree, splay_tree_key); ! extern splay_tree_node splay_tree_max (splay_tree); ! extern splay_tree_node splay_tree_min (splay_tree); ! extern int splay_tree_foreach (splay_tree, splay_tree_foreach_fn, void *); ! extern void splay_tree_rebalance (splay_tree sp); ! #endif /* _SPLAY_TREE_H */ Index: testsuite/libmudflap.c/heap-scalestress.c =================================================================== RCS file: testsuite/libmudflap.c/heap-scalestress.c diff -N testsuite/libmudflap.c/heap-scalestress.c *** /dev/null 1 Jan 1970 00:00:00 -0000 --- testsuite/libmudflap.c/heap-scalestress.c 8 Jul 2004 18:58:31 -0000 *************** *** 0 **** --- 1,79 ---- + /* zz30 + * + * demonstrate a splay-tree depth problem + */ + + #include + #include + #include + + #ifndef SCALE + #define SCALE 100000 + #endif + + + struct list + { + struct list *next; + }; + + + int + main () + { + struct list *head = NULL; + struct list *tail = NULL; + struct list *p; + long n; + int direction; + + for (direction = 0; direction < 2; direction++) + { + fprintf (stdout, "allocating\n"); + fflush (stdout); + + for (n = 0; n < SCALE; ++n) + { + p = malloc (sizeof *p); + if (NULL == p) + { + fprintf (stdout, "malloc failed\n"); + break; + } + if (direction == 0) + { /* add at tail */ + p->next = NULL; + if (NULL != tail) + tail->next = p; + else + head = p; + tail = p; + } + else + { /* add at head */ + p->next = head; + if (NULL == tail) + tail = p; + head = p; + } + } + + fprintf (stdout, "freeing\n"); + fflush (stdout); + + while (NULL != head) + { + p = head; + head = head->next; + free (p); + } + + } + + fprintf (stdout, "done\n"); + fflush (stdout); + + return (0); + } + + /* { dg-output "allocating.*freeing.*allocating.*freeing.*done" } */