1 /*
2  * Copyright (C) 2024 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 #define TLOG_TAG "storage"
17 
18 #include <lib/rng/trusty_rng.h>
19 #include <lib/storage/storage.h>
20 #include <string.h>
21 #include <trusty_benchmark.h>
22 #include <uapi/err.h>
23 
24 /* Storage types to test */
25 static const char* storage_types[] = {
26 #if HAS_FS_NSP
27         STORAGE_CLIENT_NSP_PORT,
28 #endif
29         STORAGE_CLIENT_TD_PORT,
30 #if HAS_FS_TDP
31         STORAGE_CLIENT_TDP_PORT,
32 #endif
33         STORAGE_CLIENT_TDEA_PORT, STORAGE_CLIENT_TP_PORT};
34 
35 /* How many different storage backends are available */
36 #define NUM_STORAGE_TYPE countof(storage_types)
37 
38 static struct {
39     storage_session_t ss;
40     const char* port;
41     uint8_t* data;
42 } storage_state;
43 
44 static size_t size_params[] = {32,   64,   128,  256,  512,
45                                1024, 2048, 4096, 8192, 16384};
46 
get_formatted_value_cb(char * buf,size_t buf_size,int64_t value,const char * metric_name)47 static void get_formatted_value_cb(char* buf,
48                                    size_t buf_size,
49                                    int64_t value,
50                                    const char* metric_name) {
51     if (strcmp("time_ms", metric_name) == 0) {
52         int64_t milli_sec = value / 1000000;
53         int64_t us_sec = (value % 1000000) / 1000;
54         snprintf(buf, buf_size, "%" PRId64 ".%03" PRId64 "", milli_sec, us_sec);
55     } else {
56         snprintf(buf, buf_size, "%" PRId64, value);
57     }
58 }
59 
get_param_name_cb(char * buf,size_t buf_size,size_t param_idx)60 static void get_param_name_cb(char* buf, size_t buf_size, size_t param_idx) {
61     char* s = strrchr(storage_types[bench_get_param_idx() % NUM_STORAGE_TYPE],
62                       '.');
63     if (s) {
64         ++s;
65         snprintf(buf, buf_size, "%zu - %s",
66                  size_params[param_idx / NUM_STORAGE_TYPE], s);
67     }
68 }
69 
BENCH_SETUP(storage)70 BENCH_SETUP(storage) {
71     int rc = NO_ERROR;
72 
73     storage_state.ss = STORAGE_INVALID_SESSION;
74     storage_state.port =
75             storage_types[bench_get_param_idx() % NUM_STORAGE_TYPE];
76 
77     rc = storage_open_session(&storage_state.ss, storage_state.port);
78     if (rc < 0) {
79         TLOGE("failed (%d) to open %s session\n", rc, storage_state.port);
80         return ERR_GENERIC;
81     }
82 
83     size_t sz = size_params[bench_get_param_idx() / NUM_STORAGE_TYPE];
84     storage_state.data = malloc(sz * sizeof(uint8_t));
85     trusty_rng_secure_rand(storage_state.data, sz);
86 test_abort:
87     return rc;
88 }
89 
BENCH_TEARDOWN(storage)90 BENCH_TEARDOWN(storage) {
91     if (storage_state.ss != STORAGE_INVALID_SESSION) {
92         storage_close_session(storage_state.ss);
93     }
94     storage_state.port = NULL;
95 
96     free(storage_state.data);
97     storage_state.data = NULL;
98 }
99 
100 BENCH(storage, latency, 100, _, NUM_STORAGE_TYPE* countof(size_params)) {
101     int rc;
102     file_handle_t handle;
103     const char* fname = "test_transact_commit_writes";
104 
105     // open create truncate file (with commit)
106     rc = storage_open_file(
107             storage_state.ss, &handle, fname,
108             STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
109             STORAGE_OP_COMPLETE);
110     EXPECT_EQ(0, rc);
111 
112     storage_write(handle, 0, storage_state.data,
113                   size_params[bench_get_param_idx() / NUM_STORAGE_TYPE],
114                   STORAGE_OP_COMPLETE);
115 
116     rc = storage_end_transaction(storage_state.ss, true);
117     EXPECT_EQ(0, rc);
118 
119     // cleanup
120     storage_close_file(handle);
121     storage_delete_file(storage_state.ss, fname, STORAGE_OP_COMPLETE);
122     return NO_ERROR;
123 }
124 
BENCH_RESULT(storage,latency,time_ms,get_formatted_value_cb,get_param_name_cb)125 BENCH_RESULT(storage,
126              latency,
127              time_ms,
128              get_formatted_value_cb,
129              get_param_name_cb) {
130     return bench_get_duration_ns();  // Formatted to ms by callback
131 }
132 
133 PORT_TEST(storage, "com.android.trusty.storage.bench");
134