|
| 1 | +/* |
| 2 | + * Copyright (c) 2024 Nordic Semiconductor ASA |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | +#include <stdlib.h> |
| 7 | + |
| 8 | +#include "settings_priv.h" |
| 9 | +#include <zephyr/ztest.h> |
| 10 | +#include <zephyr/settings/settings.h> |
| 11 | +#include <zephyr/bluetooth/bluetooth.h> |
| 12 | + |
| 13 | +/* This is a test suite for performance testing of settings subsystem by writing |
| 14 | + * many small setting values repeatedly. Ideally, this should consume as small |
| 15 | + * amount of time as possible for best possible UX. |
| 16 | + */ |
| 17 | + |
| 18 | +static struct k_work_q settings_work_q; |
| 19 | +static K_THREAD_STACK_DEFINE(settings_work_stack, 2024); |
| 20 | +static struct k_work_delayable pending_store; |
| 21 | + |
| 22 | +#define TEST_SETTINGS_COUNT (128) |
| 23 | +#define TEST_STORE_ITR (5) |
| 24 | +#define TEST_TIMEOUT_SEC (60) |
| 25 | +#define TEST_SETTINGS_WORKQ_PRIO (1) |
| 26 | + |
| 27 | +static void bt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, |
| 28 | + struct net_buf_simple *buf) |
| 29 | +{ |
| 30 | + printk("len %u\n", buf->len); |
| 31 | +} |
| 32 | + |
| 33 | +struct test_setting { |
| 34 | + uint32_t val; |
| 35 | +} test_settings[TEST_SETTINGS_COUNT]; |
| 36 | + |
| 37 | +K_SEM_DEFINE(waitfor_work, 0, 1); |
| 38 | + |
| 39 | +static void store_pending(struct k_work *work) |
| 40 | +{ |
| 41 | + int err; |
| 42 | + char path[20]; |
| 43 | + struct test_stats { |
| 44 | + uint32_t total_calculated; |
| 45 | + uint32_t total_measured; |
| 46 | + uint32_t single_entry_max; |
| 47 | + uint32_t single_entry_min; |
| 48 | + } stats = {0, 0, 0, UINT32_MAX}; |
| 49 | + |
| 50 | + int64_t ts1 = k_uptime_get(); |
| 51 | + |
| 52 | + /* benchmark storage performance */ |
| 53 | + for (int j = 0; j < TEST_STORE_ITR; j++) { |
| 54 | + for (int i = 0; i < TEST_SETTINGS_COUNT; i++) { |
| 55 | + test_settings[i].val = TEST_SETTINGS_COUNT*j + i; |
| 56 | + |
| 57 | + int64_t ts2 = k_uptime_get(); |
| 58 | + |
| 59 | + snprintk(path, sizeof(path), "ab/cdef/ghi/%04x", i); |
| 60 | + err = settings_save_one(path, &test_settings[i], |
| 61 | + sizeof(struct test_setting)); |
| 62 | + zassert_equal(err, 0, "settings_save_one failed %d", err); |
| 63 | + |
| 64 | + int64_t delta2 = k_uptime_delta(&ts2); |
| 65 | + |
| 66 | + if (stats.single_entry_max < delta2) { |
| 67 | + stats.single_entry_max = delta2; |
| 68 | + } |
| 69 | + if (stats.single_entry_min > delta2) { |
| 70 | + stats.single_entry_min = delta2; |
| 71 | + } |
| 72 | + stats.total_calculated += delta2; |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + int64_t delta1 = k_uptime_delta(&ts1); |
| 77 | + |
| 78 | + stats.total_measured = delta1; |
| 79 | + |
| 80 | + printk("*** storing of %u entries completed ***\n", ARRAY_SIZE(test_settings)); |
| 81 | + printk("total calculated: %u, total measured: %u\n", stats.total_calculated, |
| 82 | + stats.total_measured); |
| 83 | + printk("entry max: %u, entry min: %u\n", stats.single_entry_max, |
| 84 | + stats.single_entry_min); |
| 85 | + |
| 86 | + k_sem_give(&waitfor_work); |
| 87 | +} |
| 88 | + |
| 89 | +ZTEST_SUITE(settings_perf, NULL, NULL, NULL, NULL, NULL); |
| 90 | + |
| 91 | +ZTEST(settings_perf, test_performance) |
| 92 | +{ |
| 93 | + int err; |
| 94 | + |
| 95 | + if (IS_ENABLED(CONFIG_NVS)) { |
| 96 | + printk("Testing with NVS\n"); |
| 97 | + } else if (IS_ENABLED(CONFIG_ZMS)) { |
| 98 | + printk("Testing with ZMS\n"); |
| 99 | + } |
| 100 | + |
| 101 | + k_work_queue_start(&settings_work_q, settings_work_stack, |
| 102 | + K_THREAD_STACK_SIZEOF(settings_work_stack), |
| 103 | + K_PRIO_COOP(TEST_SETTINGS_WORKQ_PRIO), NULL); |
| 104 | + k_thread_name_set(&settings_work_q.thread, "Settings workq"); |
| 105 | + k_work_init_delayable(&pending_store, store_pending); |
| 106 | + |
| 107 | + if (IS_ENABLED(CONFIG_BT)) { |
| 108 | + /* enable one of the major subsystems, and start scanning. */ |
| 109 | + err = bt_enable(NULL); |
| 110 | + zassert_equal(err, 0, "Bluetooth init failed (err %d)\n", err); |
| 111 | + |
| 112 | + err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, bt_scan_cb); |
| 113 | + zassert_equal(err, 0, "Scanning failed to start (err %d)\n", err); |
| 114 | + } |
| 115 | + |
| 116 | + err = settings_subsys_init(); |
| 117 | + zassert_equal(err, 0, "settings_backend_init failed %d", err); |
| 118 | + |
| 119 | + /* fill with values */ |
| 120 | + for (int i = 0; i < TEST_SETTINGS_COUNT; i++) { |
| 121 | + test_settings[i].val = i; |
| 122 | + } |
| 123 | + |
| 124 | + k_work_reschedule_for_queue(&settings_work_q, &pending_store, K_NO_WAIT); |
| 125 | + |
| 126 | + err = k_sem_take(&waitfor_work, K_SECONDS(TEST_TIMEOUT_SEC)); |
| 127 | + zassert_equal(err, 0, "k_sem_take failed %d", err); |
| 128 | + |
| 129 | + if (IS_ENABLED(CONFIG_BT)) { |
| 130 | + err = bt_le_scan_stop(); |
| 131 | + zassert_equal(err, 0, "Scanning failed to stop (err %d)\n", err); |
| 132 | + } |
| 133 | +} |
0 commit comments