1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define TLOG_TAG "hwcrypto_bench"
18
19 #include <inttypes.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <interface/hwkey/hwkey.h>
26 #include <lib/hwkey/hwkey.h>
27 #include <lib/rng/trusty_rng.h>
28 #include <trusty/time.h>
29 #include <trusty_benchmark.h>
30 #include <uapi/err.h>
31
32 #define BUF_SIZE 4096
33
34 typedef struct {
35 uint8_t rng_buf[BUF_SIZE];
36 } crypto_state_t;
37
38 static crypto_state_t* crypto_state;
39
40 struct query_param {
41 size_t sz;
42 int (*rng_call)(uint8_t*, size_t);
43 };
44
45 /* Parameters Array for the parametric benchmark */
46 static const struct query_param fixed_total_size_chunked[] = {
47 {2, trusty_rng_hw_rand}, {4, trusty_rng_hw_rand},
48 {8, trusty_rng_hw_rand}, {16, trusty_rng_hw_rand},
49 {32, trusty_rng_hw_rand}, {64, trusty_rng_hw_rand},
50 {128, trusty_rng_hw_rand}, {256, trusty_rng_hw_rand},
51 {512, trusty_rng_hw_rand}, {1024, trusty_rng_hw_rand},
52 {2048, trusty_rng_hw_rand}, {4096, trusty_rng_hw_rand},
53 {2, trusty_rng_secure_rand}, {4, trusty_rng_secure_rand},
54 {8, trusty_rng_secure_rand}, {16, trusty_rng_secure_rand},
55 {32, trusty_rng_secure_rand}, {64, trusty_rng_secure_rand},
56 {128, trusty_rng_secure_rand}, {256, trusty_rng_secure_rand},
57 {512, trusty_rng_secure_rand}, {1024, trusty_rng_secure_rand},
58 {2048, trusty_rng_secure_rand}, {4096, trusty_rng_secure_rand},
59 };
60
61 static const struct query_param* variable_sizes = fixed_total_size_chunked;
62
63 /*
64 * Construct the Column Header for each param. Can have any name, but must be
65 * assigned to trusty_bench_get_param_name_cb global in BENCH_SETUP
66 */
get_param_name_cb(char * buf,size_t buf_size,size_t param_idx)67 static void get_param_name_cb(char* buf, size_t buf_size, size_t param_idx) {
68 snprintf(buf, buf_size, "%zu Bytes - %s",
69 fixed_total_size_chunked[param_idx].sz,
70 fixed_total_size_chunked[param_idx].rng_call == trusty_rng_hw_rand
71 ? "hw_rand"
72 : "secure_rand");
73 }
74
75 /*
76 * Construct the Column Header for each param. Can have any name, but must be
77 * assigned to trusty_bench_get_param_name_cb global in BENCH_SETUP
78 */
get_param_name_cb_fixed(char * buf,size_t buf_size,size_t param_idx)79 static void get_param_name_cb_fixed(char* buf,
80 size_t buf_size,
81 size_t param_idx) {
82 snprintf(buf, buf_size, "%d Total - %zu Bytes Chunks - %s", BUF_SIZE,
83 fixed_total_size_chunked[param_idx].sz,
84 fixed_total_size_chunked[param_idx].rng_call == trusty_rng_hw_rand
85 ? "hw_rand"
86 : "secure_rand");
87 }
88 /*
89 * Construct the Formatted Aggregate Values. Can have any name, but must be
90 * assigned to trusty_bench_get_formatted_value_cb global in BENCH_SETUP
91 */
get_formatted_value_cb(char * buf,size_t buf_size,int64_t value,const char * metric_name)92 static void get_formatted_value_cb(char* buf,
93 size_t buf_size,
94 int64_t value,
95 const char* metric_name) {
96 if (strcmp("time_micro_seconds", metric_name) == 0 ||
97 strcmp("micro_sec_per_byte", metric_name) == 0) {
98 int64_t mic_sec = value / 1000;
99 int64_t n_sec = value % 1000;
100 snprintf(buf, buf_size, "%" PRId64 ".%03" PRId64 "", mic_sec, n_sec);
101 } else {
102 snprintf(buf, buf_size, "%" PRId64, value);
103 }
104 }
105
106 /*
107 * Executed before each atomic execution of a BENCH(crypto, ...) Macro.
108 */
BENCH_SETUP(crypto)109 BENCH_SETUP(crypto) {
110 /*
111 * Let Framework know how to print param column header. Default is the
112 * current param index. Will be reset to NULL after BENCH_TEARDOWN(crypto,
113 * hwrng, ...)
114 */
115 trusty_bench_get_param_name_cb = &get_param_name_cb;
116
117 /*
118 * Let Framework know how to print formatted aggregate values. Default is
119 * printing the int64_t value as such. Will be reset to NULL after
120 * BENCH_TEARDOWN(crypto, hwrng, ...)
121 */
122 trusty_bench_get_formatted_value_cb = &get_formatted_value_cb;
123 /*
124 * Let Framework know how to print results. Defaults to vertical. This line
125 * is here for demonstration purpose only. Feel free to uncomment.
126 */
127
128 /* trusty_bench_print_cb = &trusty_bench_print_horizontal_metric_list; */
129
130 crypto_state = calloc(1, sizeof(crypto_state_t));
131 if (crypto_state == NULL) {
132 TLOGE("Failed to Allocate memory for crypto_state!");
133 return ERR_NO_MEMORY;
134 }
135
136 return NO_ERROR;
137 }
138
139 /*
140 * Executed after each atomic execution of a BENCH(crypto, ...) Macro.
141 */
BENCH_TEARDOWN(crypto)142 BENCH_TEARDOWN(crypto) {
143 free(crypto_state);
144 crypto_state = NULL;
145 }
146
147 /*
148 * BENCH with 3 parameters (suite_name, test_name, nb_of_runs).
149 * The inner content is run 100 times.
150 * BENCH_SETUP/BENCH_TEARDOWN are executed before/after each individual run
151 * respectively.
152 */
153 BENCH(crypto, hwrng_hw_rand, 20) {
154 int rc;
155 rc = trusty_rng_hw_rand(crypto_state->rng_buf, BUF_SIZE);
156 ASSERT_EQ(NO_ERROR, rc);
157
158 test_abort:
159 return rc;
160 }
161
162 /* the returned time is in nanoseconds, the formatter will make it micro but the
163 * name here is the one used in printing */
BENCH_RESULT(crypto,hwrng_hw_rand,time_micro_seconds)164 BENCH_RESULT(crypto, hwrng_hw_rand, time_micro_seconds) {
165 /*
166 * bench_get_duration_ns() is the ns time from trusty_get_time with clock ID
167 * 0 for the last execution of 'BENCH'.
168 */
169 return bench_get_duration_ns();
170 }
171
BENCH_RESULT(crypto,hwrng_hw_rand,micro_sec_per_byte)172 BENCH_RESULT(crypto, hwrng_hw_rand, micro_sec_per_byte) {
173 return bench_get_duration_ns() / BUF_SIZE;
174 }
175
176 /*
177 * BENCH with 4 parameters (suite_name, test_name, nb_of_runs, params).
178 * For each parameter in query_params, the inner content is run 5 times.
179 * BENCH_SETUP/BENCH_TEARDOWN are executed before/after each individual run
180 * respectively.
181 */
182 BENCH(crypto, hwrng_fixed_total, 20, fixed_total_size_chunked) {
183 int rc;
184 size_t i;
185
186 trusty_bench_get_param_name_cb = &get_param_name_cb_fixed;
187
188 size_t nq_query =
189 BUF_SIZE / fixed_total_size_chunked[bench_get_param_idx()].sz;
190 for (i = 0; i < nq_query; i++) {
191 rc = fixed_total_size_chunked[bench_get_param_idx()].rng_call(
192 crypto_state->rng_buf,
193 fixed_total_size_chunked[bench_get_param_idx()].sz);
194 ASSERT_EQ(NO_ERROR, rc);
195 }
196
197 test_abort:
198 return rc;
199 }
200
201 /* the returned time is in nanoseconds, the formatter will make it micro but the
202 * name here is the one used in printing */
BENCH_RESULT(crypto,hwrng_fixed_total,time_micro_seconds)203 BENCH_RESULT(crypto, hwrng_fixed_total, time_micro_seconds) {
204 return bench_get_duration_ns();
205 }
206
BENCH_RESULT(crypto,hwrng_fixed_total,micro_sec_per_byte)207 BENCH_RESULT(crypto, hwrng_fixed_total, micro_sec_per_byte) {
208 return bench_get_duration_ns() / BUF_SIZE;
209 }
210
211 /*
212 * BENCH with 5 parameters (suite_name, test_name, nb_of_runs, params).
213 * For each parameter in query_params, the inner content is run 100 times.
214 * BENCH_SETUP/BENCH_TEARDOWN are executed before/after each individual run
215 * respectively. For convenience, one can reuse (suite_name, test_name) from a 3
216 * or 4 param BENCH macro. This allows sharing
217 * BENCH_SETUP/BENCH_TEARDOWN/BENCH_SETUP/BENCH_RESULT macros. you need a
218 * different parameter name, hence the aliasing here.
219 */
220 BENCH(crypto,
221 hwrng_var_size,
222 20,
223 variable_sizes,
224 countof(fixed_total_size_chunked)) {
225 int rc;
226
227 rc = variable_sizes[bench_get_param_idx()].rng_call(
228 crypto_state->rng_buf, variable_sizes[bench_get_param_idx()].sz);
229 ASSERT_EQ(NO_ERROR, rc);
230
231 test_abort:
232 return rc;
233 }
234
235 /* the returned time is in nanoseconds, the formatter will make it micro but the
236 * name here is the one used in printing */
BENCH_RESULT(crypto,hwrng_var_size,time_micro_seconds)237 BENCH_RESULT(crypto, hwrng_var_size, time_micro_seconds) {
238 return bench_get_duration_ns();
239 }
BENCH_RESULT(crypto,hwrng_var_size,micro_sec_per_byte)240 BENCH_RESULT(crypto, hwrng_var_size, micro_sec_per_byte) {
241 return bench_get_duration_ns() / variable_sizes[bench_get_param_idx()].sz;
242 }
243
244 PORT_TEST(hwcrypto, "com.android.trusty.hwrng.bench")
245