Skip to content
Permalink
Browse files

Correct the memory usage claims to take into account allocator overhe…

…ad (#132)

The default memory allocator used (libc_allocator_with_realloc)
necessarily has some overhead, as the size of the block is not passed to
free(). The memory usage claims are updated to take into account an
overhead of up to 16 bytes per malloc'ed block.
  • Loading branch information...
greg7mdp authored and donovanhide committed Jul 26, 2016
1 parent b15087b commit 4cb924025b8c622d1a1e11f4c1e9db15410c75fb
Showing with 69 additions and 5 deletions.
  1. +9 −5 README
  2. +60 −0 doc/implementation.html
14 README
@@ -106,20 +106,24 @@ SPARSETABLE
In addition to the hash-map and hash-set classes, this package also
provides sparsetable.h, an array implementation that uses space
proportional to the number of elements in the array, rather than the
maximum element index. It uses very little space overhead: 1 bit per
entry. See doc/sparsetable.html for the API.
maximum element index. It uses very little space overhead: 2 to 5
bits per entry. See doc/sparsetable.html for the API.

RESOURCE USAGE
--------------
* sparse_hash_map has memory overhead of about 2 bits per hash-map
entry.
* sparse_hash_map has memory overhead of about 4 to 10 bits per
hash-map entry, assuming a typical average occupancy of 50%.
* dense_hash_map has a factor of 2-3 memory overhead: if your
hashtable data takes X bytes, dense_hash_map will use 3X-4X memory
total.

Hashtables tend to double in size when resizing, creating an
additional 50% space overhead. dense_hash_map does in fact have a
significant "high water mark" memory use requirement.
significant "high water mark" memory use requirement, which is 6 times
the size of hash entries in the table when resizing (when reaching
50% occupancy, the table resizes to double the previous size, and the
old table (2x) is copied to the new table (4x)).

sparse_hash_map, however, is written to need very little space
overhead when resizing: only a few bits per hashtable entry.

@@ -131,6 +131,66 @@ <h3>Resource use</h3>
entry -- but take longer for inserts, deletes, and lookups. A smaller
M would use more overhead but make operations somewhat faster.</p>

The numbers above assume that the allocator used doesn't require extra
memory. The default allocator (using malloc/free) typically has some overhead
for each allocation. If we assume 16 byte overhead per allocation, the
overhead becomes 4.6 bit per array entry (32 bit pointers) or 5.3 bit per
array entry (64 bit pointers)

<p>Each sparsegroup has:</p>

<table>
<thead>
<tr>
<th>member</th>
<th>32 bit</th>
<th>64 bit</th>
</tr>
</thead>
<tbody>
<tr>
<td>pointer</td>
<td>4 bytes</td>
<td>8 bytes</td>
</tr>
<tr>
<td>num_buckets</td>
<td>2 bytes</td>
<td>2 bytes</td>
</tr>
<tr>
<td>bitmap</td>
<td>6 bytes</td>
<td>6 bytes</td>
</tr>
<tr>
<td>total</td>
<td>12 bytes = 96 bits</td>
<td>16 bytes = 128 bits</td>
</tr>
<tr>
<td>because this is the overhead for each sparsegroup (48 entries), we divide by 48</td>
<td></td>
<td></td>
</tr>
<tr>
<td>overhead / entry</td>
<td>96 / 48 = 2 bits</td>
<td>128 / 48 = 2.67 bits</td>
</tr>
<tr>
<td rowspan=3>additional overhead per allocation up to 16 bytes = 128 bits</td>
<td></td>
<td></td>
</tr>
<tr>
<td>max overhead / entry</td>
<td>(96 + 128) / 48 = 4.67 bits</td>
<td>(128 + 128) / 48 = 5.33 bits</td>
</tr>
</tbody>
</table>

<p>You can also look at some specific <A
HREF="performance.html">performance numbers</A>.</p>

0 comments on commit 4cb9240

Please sign in to comment.
You can’t perform that action at this time.