1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <benchmark/benchmark.h>
17#include "benchmark_fwk.h"
18#include "init_param.h"
19#include "param_init.h"
20#include "parameter.h"
21#include "sys_param.h"
22
23using namespace std;
24using namespace init_benchmark_test;
25namespace {
26static int g_maxCount = 512;
27}
28
29static inline int TestRandom(void)
30{
31    return random();
32}
33
34namespace init_benchmark_param {
35struct LocalParameterTestState {
36    explicit LocalParameterTestState(int nprops) noexcept : nprops(nprops), valid(false)
37    {
38        static const char paramNameChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
39        if (g_maxCount < nprops) {
40            fprintf(stderr, "Invalid nprops %d\n", nprops);
41            return;
42        }
43        names = new char *[nprops];
44        nameLens = new int[nprops];
45        values = new char *[nprops];
46        valueLens = new int[nprops];
47
48        srandom(nprops);
49        int count = 0;
50        for (int i = 0; i < nprops; i++) {
51            // Make sure the name has at least 10 characters to make
52            // it very unlikely to generate the same TestRandom name.
53            nameLens[i] = (TestRandom() % (PARAM_NAME_LEN_MAX - 10)) + 10; // 10 name len
54            names[i] = new char[PARAM_NAME_LEN_MAX + 1];
55            size_t paramNameLen = sizeof(paramNameChars) - 1;
56            for (int j = 0; j < nameLens[i]; j++) {
57                if (j == 0 || names[i][j - 1] == '.' || j == nameLens[i] - 1) {
58                    // Certain values are not allowed:
59                    // - Don't start name with '.'
60                    // - Don't allow '.' to appear twice in a row
61                    // - Don't allow the name to end with '.'
62                    // This assumes that '.' is the last character in the
63                    // array so that decrementing the length by one removes
64                    // the value from the possible values.
65                    paramNameLen--;
66                }
67                names[i][j] = paramNameChars[TestRandom() % paramNameLen];
68            }
69            names[i][nameLens[i]] = 0;
70
71            // Make sure the value contains at least 1 character.
72            valueLens[i] = (TestRandom() % (PARAM_VALUE_LEN_MAX - 1)) + 1;
73            values[i] = new char[PARAM_VALUE_LEN_MAX];
74            for (int j = 0; j < valueLens[i]; j++) {
75                values[i][j] = paramNameChars[TestRandom() % (sizeof(paramNameChars) - 1)];
76            }
77
78            if (SystemSetParameter(names[i], values[i]) != 0) {
79                count++;
80            }
81        }
82        if (count > 0) {
83            fprintf(stderr, "Failed to add a property, count %d\n", count);
84        }
85        valid = true;
86    }
87
88    LocalParameterTestState(const LocalParameterTestState&) = delete;
89    LocalParameterTestState & operator=(const LocalParameterTestState&) = delete;
90
91    ~LocalParameterTestState() noexcept
92    {
93        for (int i = 0; i < nprops; i++) {
94            delete names[i];
95            delete values[i];
96        }
97        delete[] names;
98        delete[] nameLens;
99        delete[] values;
100        delete[] valueLens;
101    }
102
103public:
104    const int nprops;
105    char **names;
106    int *nameLens;
107    char **values;
108    int *valueLens;
109    bool valid;
110};
111}
112
113static init_benchmark_param::LocalParameterTestState *g_localParamTester = nullptr;
114
115void CreateLocalParameterTest(int max)
116{
117    g_maxCount = max > 0 ? max : g_maxCount;
118    g_localParamTester = new init_benchmark_param::LocalParameterTestState(g_maxCount);
119    if (g_localParamTester == nullptr) {
120        exit(0);
121    }
122}
123
124/**
125 * @brief for parameter get
126 *
127 * @param state
128 */
129static void BMCachedParameterGet(benchmark::State &state)
130{
131    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
132        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
133        return;
134    }
135
136    CachedHandle handle = CachedParameterCreate(g_localParamTester->names[TestRandom() % g_maxCount], "4444444");
137    for (auto _ : state) {
138        benchmark::DoNotOptimize(CachedParameterGet(handle));
139    }
140    state.SetItemsProcessed(state.iterations());
141}
142
143/**
144 * @brief for parameter get, static handle
145 *
146 * @param state
147 */
148static void BMCachedParameterGetChangedStatic(benchmark::State &state)
149{
150    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
151        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
152        return;
153    }
154
155    for (auto _ : state) {
156        static CachedHandle handle = CachedParameterCreate(
157            g_localParamTester->names[TestRandom() % g_maxCount], "xxxxxx");
158        int changed = 0;
159        benchmark::DoNotOptimize(CachedParameterGetChanged(handle, &changed));
160    }
161    state.SetItemsProcessed(state.iterations());
162}
163
164/**
165 * @brief for parameter get, global handle
166 *
167 * @param state
168 */
169static void BMCachedParameterGetChangedGlobal(benchmark::State &state)
170{
171    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
172        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
173        return;
174    }
175
176    CachedHandle handle = CachedParameterCreate(g_localParamTester->names[TestRandom() % g_maxCount], "xxxxxxxxx");
177    for (auto _ : state) {
178        int changed = 0;
179        benchmark::DoNotOptimize(CachedParameterGetChanged(handle, &changed));
180    }
181    state.SetItemsProcessed(state.iterations());
182}
183
184/**
185 * @brief for parameter get, global handle
186 *
187 * @param state
188 */
189static void BMCachedParameterGetChangedGlobal2(benchmark::State &state)
190{
191    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
192        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
193        return;
194    }
195
196    CachedHandle handle = nullptr;
197    for (auto _ : state) {
198        if (handle == nullptr) {
199            handle = CachedParameterCreate(g_localParamTester->names[TestRandom() % g_maxCount], "xxxxxxxxx");
200        }
201        int changed = 0;
202        benchmark::DoNotOptimize(CachedParameterGetChanged(handle, &changed));
203    }
204    state.SetItemsProcessed(state.iterations());
205}
206
207/**
208 * @brief for get
209 * data exist
210 *
211 * @param state
212 */
213static void BMSystemReadParam(benchmark::State &state)
214{
215    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
216        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
217        return;
218    }
219    {
220        char value[PARAM_VALUE_LEN_MAX] = {0};
221        uint32_t len = PARAM_VALUE_LEN_MAX;
222        SystemReadParam(g_localParamTester->names[TestRandom() % g_maxCount], value, &len);
223    }
224    for (auto _ : state) {
225        char value[PARAM_VALUE_LEN_MAX] = {0};
226        uint32_t len = PARAM_VALUE_LEN_MAX;
227        SystemReadParam(g_localParamTester->names[TestRandom() % g_maxCount], value, &len);
228    }
229    state.SetItemsProcessed(state.iterations());
230}
231
232/**
233 * @brief for get
234 * data not exist
235 *
236 * @param state
237 */
238static void BMSystemReadParam_none(benchmark::State &state)
239{
240    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
241        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
242        return;
243    }
244    {
245        char value[PARAM_VALUE_LEN_MAX] = {0};
246        uint32_t len = PARAM_VALUE_LEN_MAX;
247        SystemReadParam("test.aaa.aaa.aaa", value, &len);
248    }
249    for (auto _ : state) {
250        char value[PARAM_VALUE_LEN_MAX] = {0};
251        uint32_t len = PARAM_VALUE_LEN_MAX;
252        SystemReadParam("test.aaa.aaa.aaa", value, &len);
253    }
254    state.SetItemsProcessed(state.iterations());
255}
256
257/**
258 * @brief for find
259 *
260 * @param state
261 */
262static void BMSystemFindParameter(benchmark::State &state)
263{
264    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
265        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
266        return;
267    }
268
269    for (auto _ : state) {
270        ParamHandle handle = 0;
271        SystemFindParameter(g_localParamTester->names[TestRandom() % g_maxCount], &handle);
272    }
273    state.SetItemsProcessed(state.iterations());
274}
275
276/**
277 * @brief for find, and read value
278 *
279 * @param state
280 */
281static void BMSystemGetParameterValue(benchmark::State &state)
282{
283    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
284        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
285        return;
286    }
287
288    ParamHandle *handle = new ParamHandle[g_maxCount];
289    for (int i = 0; i < g_maxCount; ++i) {
290        SystemFindParameter(g_localParamTester->names[TestRandom() % g_maxCount], &handle[i]);
291    }
292
293    int i = 0;
294    char value[PARAM_VALUE_LEN_MAX];
295    for (auto _ : state) {
296        uint32_t len = PARAM_VALUE_LEN_MAX;
297        SystemGetParameterValue(handle[i], value, &len);
298        i = (i + 1) % g_maxCount;
299    }
300    state.SetItemsProcessed(state.iterations());
301    delete[] handle;
302}
303
304/**
305 * @brief for find, and read commit id
306 *
307 * @param state
308 */
309static void BMSystemGetParameterCommitId(benchmark::State &state)
310{
311    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
312        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
313        return;
314    }
315
316    ParamHandle *handle = new ParamHandle[g_maxCount];
317    for (int i = 0; i < g_maxCount; ++i) {
318        SystemFindParameter(g_localParamTester->names[TestRandom() % g_maxCount], &handle[i]);
319    }
320
321    int i = 0;
322    for (auto _ : state) {
323        uint32_t commitId = 0;
324        SystemGetParameterCommitId(handle[i], &commitId);
325        i = (i + 1) % g_maxCount;
326    }
327    state.SetItemsProcessed(state.iterations());
328    delete[] handle;
329}
330
331static void BMTestRandom(benchmark::State &state)
332{
333    if (g_localParamTester == nullptr || !g_localParamTester->valid) {
334        fprintf(stderr, "Invalid nprops %d \n", g_maxCount);
335        return;
336    }
337
338    for (auto _ : state) {
339        benchmark::DoNotOptimize(TestRandom());
340    }
341    state.SetItemsProcessed(state.iterations());
342}
343
344INIT_BENCHMARK(BMCachedParameterGet);
345INIT_BENCHMARK(BMCachedParameterGetChangedStatic);
346INIT_BENCHMARK(BMCachedParameterGetChangedGlobal);
347INIT_BENCHMARK(BMCachedParameterGetChangedGlobal2);
348
349INIT_BENCHMARK(BMSystemReadParam);
350INIT_BENCHMARK(BMSystemReadParam_none);
351INIT_BENCHMARK(BMSystemFindParameter);
352INIT_BENCHMARK(BMSystemGetParameterValue);
353INIT_BENCHMARK(BMSystemGetParameterCommitId);
354INIT_BENCHMARK(BMTestRandom);
355