Skip to content

Commit

Permalink
i#4014 dr$sim phys: Export open-address hashtable from DR (#5519)
Browse files Browse the repository at this point in the history
For virtual-to-physical translation, we cannot use a 3rd-party library
such as STL due to static linking constraints.  Yet the drcontainers
hashtable performs poorly; we need an open-address hashtable.  Since
DR has one we export it here in a new interface.

Adds a simple test and documentation.

Issue: #4014
  • Loading branch information
derekbruening authored Jun 7, 2022
1 parent d96d930 commit a3544c2
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 3 deletions.
4 changes: 4 additions & 0 deletions api/docs/release.dox
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ Further non-compatibility-affecting changes include:
- Added -use_physical support to drcachesim offline traces using two new
marker types: #TRACE_MARKER_TYPE_PHYSICAL_ADDRESS and
#TRACE_MARKER_TYPE_PHYSICAL_ADDRESS_NOT_AVAILABLE.
- Added an open-address hashtable implementation for cases where third-party
libraries must be avoided and open addressing is best: dr_hashtable_create(),
dr_hashtable_destroy(), dr_hashtable_clear(), dr_hashtable_lookup(),
dr_hashtable_add(), dr_hashtable_remove().

The changes between version 9.0.1 and 9.0.0 include the following compatibility
changes:
Expand Down
87 changes: 86 additions & 1 deletion core/lib/dr_tools.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2010-2021 Google, Inc. All rights reserved.
* Copyright (c) 2010-2022, Inc. All rights reserved.
* Copyright (c) 2002-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -2620,4 +2620,89 @@ DR_API
bool
dr_trace_exists_at(void *drcontext, void *tag);

/**************************************************
* OPEN-ADDRESS HASHTABLE
*/

DR_API
/**
* Allocates and initializes an open-address library-independent hashtable:
*
* @param[drcontext] This context controls whether thread-private or global
* heap is used for the table.
* @param[bits] The base-2 log of the initial capacity of the table.
* @param[load_factor_percent] The threshold of the table's occupancy at which
* it will be resized (so smaller values keep the table sparser
* and generally more performant but at the cost of more memory).
* This is a percentage and so must be between 0 and 100.
* Values are typically in the 20-80 range and for performance
* critical tables would usually be below 50.
* @param[synch] Whether to use a lock around all operations.
* @param[free_payload_func] An optional function to call when removing an entry.
*
* @return a pointer to the heap-allocated table.
*/
void *
dr_hashtable_create(void *drcontext, uint bits, uint load_factor_percent, bool synch,
void (*free_payload_func)(void * /*drcontext*/, void *));

DR_API
/**
* Destroys a hashtable created by dr_hashtable_create().
*
* @param[drcontext] Must be the same context passed to dr_hashtable_create().
* @param[htable] A pointer to the table itself, returned by dr_hashtable_create().
*/
void
dr_hashtable_destroy(void *drcontext, void *htable);

DR_API
/**
* Removes all entries in a hashtable created by dr_hashtable_create().
*
* @param[drcontext] Must be the same context passed to dr_hashtable_create().
* @param[htable] A pointer to the table itself, returned by dr_hashtable_create().
*/
void
dr_hashtable_clear(void *drcontext, void *htable);

DR_API
/**
* Queries whether an entry for the given key exists.
*
* @param[drcontext] Must be the same context passed to dr_hashtable_create().
* @param[htable] A pointer to the table itself, returned by dr_hashtable_create().
* @param[key] The key to query.
*
* @return the payload value for the key that was passed to dr_hashtable_add(),
* or NULL if no such key is found.
*/
void *
dr_hashtable_lookup(void *drcontext, void *htable, ptr_uint_t key);

DR_API
/**
* Adds a new entry to the hashtable.
*
* @param[drcontext] Must be the same context passed to dr_hashtable_create().
* @param[htable] A pointer to the table itself, returned by dr_hashtable_create().
* @param[key] The key to add.
* @param[payload] The payload to add.
*/
void
dr_hashtable_add(void *drcontext, void *htable, ptr_uint_t key, void *payload);

DR_API
/**
* Removes an entry for the given key.
*
* @param[drcontext] Must be the same context passed to dr_hashtable_create().
* @param[htable] A pointer to the table itself, returned by dr_hashtable_create().
* @param[key] The key to remove.
*
* @return whether the key was found.
*/
bool
dr_hashtable_remove(void *drcontext, void *htable, ptr_uint_t key);

#endif /* _DR_TOOLS_H_ */
60 changes: 59 additions & 1 deletion core/lib/instrument.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* ******************************************************************************
* Copyright (c) 2010-2021 Google, Inc. All rights reserved.
* Copyright (c) 2010-2022 Google, Inc. All rights reserved.
* Copyright (c) 2010-2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2002-2010 VMware, Inc. All rights reserved.
* ******************************************************************************/
Expand Down Expand Up @@ -7811,3 +7811,61 @@ dr_is_detaching(void)
{
return doing_detach;
}

/**************************************************
* OPEN-ADDRESS HASHTABLE
*
* Some uses cases need an open-address hashtable that does not use 3rd-party
* libraries. Rather than add something to drcontainers, we simply export the
* hashtablex.h-based table directly from DR.
*/

DR_API
void *
dr_hashtable_create(void *drcontext, uint bits, uint load_factor_percent, bool synch,
void (*free_payload_func)(void * /*drcontext*/, void *))
{
uint flags = HASHTABLE_PERSISTENT;
if (synch)
flags |= HASHTABLE_SHARED | HASHTABLE_ENTRY_SHARED;
else
flags |= HASHTABLE_LOCKLESS_ACCESS;
return generic_hash_create(
(dcontext_t *)drcontext, bits, load_factor_percent, flags,
(void (*)(dcontext_t *, void *))free_payload_func _IF_DEBUG("client"));
}

DR_API
void
dr_hashtable_destroy(void *drcontext, void *htable)
{
generic_hash_destroy((dcontext_t *)drcontext, (generic_table_t *)htable);
}

DR_API
void
dr_hashtable_clear(void *drcontext, void *htable)
{
generic_hash_clear((dcontext_t *)drcontext, (generic_table_t *)htable);
}

DR_API
void *
dr_hashtable_lookup(void *drcontext, void *htable, ptr_uint_t key)
{
return generic_hash_lookup((dcontext_t *)drcontext, (generic_table_t *)htable, key);
}

DR_API
void
dr_hashtable_add(void *drcontext, void *htable, ptr_uint_t key, void *payload)
{
generic_hash_add((dcontext_t *)drcontext, (generic_table_t *)htable, key, payload);
}

DR_API
bool
dr_hashtable_remove(void *drcontext, void *htable, ptr_uint_t key)
{
return generic_hash_remove((dcontext_t *)drcontext, (generic_table_t *)htable, key);
}
5 changes: 4 additions & 1 deletion ext/drcontainers/hashtable.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2020 Google, Inc. All rights reserved.
* Copyright (c) 2011-2022 Google, Inc. All rights reserved.
* Copyright (c) 2007-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -153,6 +153,9 @@ hashtable_init(hashtable_t *table, uint num_bits, hash_type_t hashtype, bool str
* @param[in] cmp_key_func A callback for comparing two keys.
* Leave it NULL if no callback is needed and the default is to be used.
* For HASH_CUSTOM, a callback must be provided.
*
* This hashtable uses closed addressing.
* For an open-address hashtable, consider dr_hashtable_create().
*/
void
hashtable_init_ex(hashtable_t *table, uint num_bits, hash_type_t hashtype, bool str_dup,
Expand Down
30 changes: 30 additions & 0 deletions suite/tests/client-interface/drcontainers-test.dll.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,42 @@ test_hashtable_apply_all_user_data(void)
hashtable_delete(&hash_table);
}

#define KEY 42
#define PAYLOAD ((void *)12)
static bool free_func_called;

static void
free_payload_func(void *drcontext, void *payload)
{
CHECK(drcontext == dr_get_current_drcontext(), "context should be mine");
CHECK(payload == PAYLOAD, "free payload arg incorrect");
free_func_called = true;
}

static void
test_dr_hashtable(void)
{
void *dcxt = dr_get_current_drcontext();
void *table = dr_hashtable_create(dcxt, 8, 50, /*synch=*/false, free_payload_func);
CHECK(dr_hashtable_lookup(dcxt, table, KEY) == NULL, "table should be empty");
dr_hashtable_add(dcxt, table, KEY, PAYLOAD);
CHECK(dr_hashtable_lookup(dcxt, table, KEY) == PAYLOAD, "should find if just-added");
CHECK(dr_hashtable_remove(dcxt, table, KEY), "should find if just-added");
CHECK(free_func_called, "free_payload_func sanity check");
CHECK(dr_hashtable_lookup(dcxt, table, KEY) == NULL, "just removed");
dr_hashtable_add(dcxt, table, KEY, PAYLOAD);
dr_hashtable_clear(dcxt, table);
CHECK(dr_hashtable_lookup(dcxt, table, KEY) == NULL, "table should be empty");
dr_hashtable_destroy(dcxt, table);
}

DR_EXPORT void
dr_init(client_id_t id)
{
test_vector();
test_hashtable_apply_all();
test_hashtable_apply_all_user_data();
test_dr_hashtable();

/* XXX: test other data structures */
}

0 comments on commit a3544c2

Please sign in to comment.