-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
samples: lib: os: hash_map: add Hashmap sample code
This sample shows how to use `sys_hashmap`. Signed-off-by: Chris Friedt <cfriedt@meta.com>
- Loading branch information
1 parent
e607684
commit 480b749
Showing
6 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright (c) 2022 Meta | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
|
||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(hash_map) | ||
|
||
target_sources(app PRIVATE src/main.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Copyright (c) 2022 Meta | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
config TEST_LIB_HASH_MAP_MAX_ENTRIES | ||
int "Maximum number of Hashmap entries" | ||
default 40 | ||
help | ||
When benchmarking the performance of the Hashmap, it helps to be able | ||
to vary the number of entries to insert or remove from the hash table | ||
in a convenient way. This option translates to MANY in the test sources. | ||
|
||
CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES | ||
|
||
Of course, using realloc(), we are limited by the amount of available | ||
heap memory. For test scenarios using the Minimal C library, the heap | ||
size is controlled via | ||
|
||
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE | ||
|
||
For native_posix_64, the number of entries can be configured | ||
independently of the arena size since the native libc is used. | ||
|
||
config TEST_LIB_HASH_MAP_DURATION_S | ||
int "Duration of test (in seconds)" | ||
default 3 | ||
|
||
source "Kconfig.zephyr" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
.. _system_hashmap: | ||
|
||
System Hashmap | ||
############## | ||
|
||
Overview | ||
******** | ||
|
||
This is a simple example that repeatedly | ||
|
||
* inserts up to ``CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES`` | ||
* replaces up to the same number that were previously inserted | ||
* removes all previously inserted keys | ||
|
||
Building | ||
******** | ||
|
||
This application can be built on native_posix as follows: | ||
|
||
.. zephyr-app-commands:: | ||
:zephyr-app: samples/basic/hash_map | ||
:host-os: unix | ||
:board: native_posix | ||
:goals: build | ||
:compact: | ||
|
||
To build for another board, change "native_posix" above to that board's name. | ||
|
||
Additionally, it is possible to use one of the other Hashmap implementations by specifying | ||
|
||
* ``CONFIG_SYS_HASH_MAP_CHOICE_SC=y`` (Separate Chaining) | ||
* ``CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y`` (Open Addressing / Linear Probe) | ||
* ``CONFIG_SYS_HASH_MAP_CHOICE_CXX=y`` (C Wrapper around the C++ ``std::unordered_map``) | ||
|
||
To stress the Hashmap implementation, adjust ``CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES``. | ||
|
||
Running | ||
******* | ||
|
||
Run ``build/zephyr/zephyr.exe`` | ||
|
||
Sample Output | ||
************* | ||
|
||
.. code-block:: console | ||
System Hashmap sample | ||
[00:00:11.000,000] <inf> hashmap_sample: n_insert: 118200 n_remove: 295500 n_replace: 329061 n_miss: 0 n_error: 0 max_size: 118200 | ||
[00:00:11.010,000] <inf> hashmap_sample: success |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Copyright (c) 2022 Meta | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
CONFIG_BOOT_BANNER=n | ||
CONFIG_LOG=y | ||
|
||
CONFIG_TEST_RANDOM_GENERATOR=y | ||
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=8192 | ||
CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192 | ||
CONFIG_PICOLIBC_HEAP_SIZE=8192 | ||
|
||
CONFIG_SYS_HASH_FUNC32=y | ||
CONFIG_SYS_HASH_MAP=y | ||
|
||
CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES=40 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Copyright (c) 2022 Meta | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
sample: | ||
description: System Hashmap sample | ||
name: System Hashmap sample | ||
|
||
common: | ||
min_ram: 24 | ||
integration_platforms: | ||
- qemu_x86_64 | ||
- mps2_an385 | ||
harness: console | ||
harness_config: | ||
type: one_line | ||
regex: | ||
- .*success | ||
|
||
tests: | ||
# Minimal Libc | ||
libraries.hash_map.minimal.separate_chaining.djb2: | ||
extra_configs: | ||
- CONFIG_MINIMAL_LIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_SC=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y | ||
libraries.hash_map.minimal.open_addressing.djb2: | ||
extra_configs: | ||
- CONFIG_MINIMAL_LIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y | ||
# Newlib | ||
libraries.hash_map.newlib.separate_chaining.djb2: | ||
extra_configs: | ||
- CONFIG_NEWLIB_LIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_SC=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y | ||
libraries.hash_map.newlib.open_addressing.djb2: | ||
extra_configs: | ||
- CONFIG_NEWLIB_LIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y | ||
libraries.hash_map.newlib.cxx_unordered_map.djb2: | ||
extra_configs: | ||
- CONFIG_NEWLIB_LIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_CXX=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y | ||
# PicoLibc | ||
libraries.hash_map.picolibc.separate_chaining.djb2: | ||
extra_configs: | ||
- CONFIG_PICOLIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_SC=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y | ||
libraries.hash_map.picolibc.open_addressing.djb2: | ||
extra_configs: | ||
- CONFIG_PICOLIBC=y | ||
- CONFIG_SYS_HASH_MAP_CHOICE_OA_LP=y | ||
- CONFIG_SYS_HASH_FUNC32_CHOICE_DJB2=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Copyright (c) 2022 Meta | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <zephyr/logging/log.h> | ||
#include <zephyr/sys/hash_map.h> | ||
#include <zephyr/random/rand32.h> | ||
|
||
LOG_MODULE_REGISTER(hashmap_sample); | ||
|
||
SYS_HASHMAP_DEFINE_STATIC(map); | ||
|
||
void print_sys_memory_stats(void); | ||
|
||
struct _stats { | ||
uint64_t n_insert; | ||
uint64_t n_remove; | ||
uint64_t n_replace; | ||
uint64_t n_error; | ||
uint64_t n_miss; | ||
size_t max_size; | ||
}; | ||
|
||
static void print_stats(const struct _stats *stats); | ||
|
||
void main(void) | ||
{ | ||
size_t i; | ||
int ires; | ||
bool bres; | ||
struct _stats stats = {0}; | ||
|
||
printk("CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES: %u\n", CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES); | ||
|
||
do { | ||
for (i = 0; i < CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES; ++i) { | ||
|
||
ires = sys_hashmap_insert(&map, i, i, NULL); | ||
if (ires < 0) { | ||
break; | ||
} | ||
|
||
__ASSERT(ires == 1, "Expected to insert %zu", i); | ||
++stats.n_insert; | ||
++stats.max_size; | ||
|
||
LOG_DBG("Inserted %zu", i); | ||
|
||
if (k_uptime_get() / MSEC_PER_SEC > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { | ||
goto out; | ||
} | ||
} | ||
|
||
for (i = 0; i < stats.max_size; ++i) { | ||
|
||
ires = sys_hashmap_insert(&map, i, stats.max_size - i, NULL); | ||
__ASSERT(ires == 0, "Failed to replace %zu", i); | ||
++stats.n_replace; | ||
|
||
LOG_DBG("Replaced %zu", i); | ||
|
||
if (k_uptime_get() / MSEC_PER_SEC > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { | ||
goto out; | ||
} | ||
} | ||
|
||
for (i = stats.max_size; i > 0; --i) { | ||
bres = sys_hashmap_remove(&map, i - 1, NULL); | ||
__ASSERT(bres, "Failed to remove %zu", i - 1); | ||
++stats.n_remove; | ||
|
||
LOG_DBG("Removed %zu", i - 1); | ||
|
||
if (k_uptime_get() / MSEC_PER_SEC > CONFIG_TEST_LIB_HASH_MAP_DURATION_S) { | ||
goto out; | ||
} | ||
} | ||
/* These architectures / boards seem to have trouble with basic timekeeping atm */ | ||
} while (!IS_ENABLED(CONFIG_ARCH_POSIX) && !IS_ENABLED(CONFIG_BOARD_QEMU_NIOS2)); | ||
|
||
out: | ||
|
||
print_stats(&stats); | ||
|
||
sys_hashmap_clear(&map, NULL, NULL); | ||
|
||
LOG_INF("success"); | ||
|
||
if (IS_ENABLED(CONFIG_ARCH_POSIX)) { | ||
exit(0); | ||
} | ||
} | ||
|
||
static void print_stats(const struct _stats *stats) | ||
{ | ||
LOG_INF("n_insert: %" PRIu64 " n_remove: %" PRIu64 " n_replace: %" PRIu64 | ||
" n_miss: %" PRIu64 " n_error: %" PRIu64 " max_size: %zu", | ||
stats->n_insert, stats->n_remove, stats->n_replace, stats->n_miss, stats->n_error, | ||
stats->max_size); | ||
} |