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
bt_scan_cb(const bt_addr_le_t * addr,int8_t rssi,uint8_t adv_type,struct net_buf_simple * buf)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
store_pending(struct k_work * work)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
ZTEST(settings_perf,test_performance)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 }
134