xref: /aosp_15_r20/trusty/kernel/app/memorylatencybench/main.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1 /*
2  * Copyright (C) 2023 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 "memlatency"
18 
19 #include <inttypes.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <arch/defines.h>
26 #include <trusty_benchmark.h>
27 #include <uapi/err.h>
28 
29 #define BLOCK_SIZE_BYTES (CACHE_LINE * 4)
30 #define STRUCT_NPAD (BLOCK_SIZE_BYTES) / sizeof(uintptr_t)
31 #define MAX_WORKING_SET_SZ 16777216
32 
33 static const uint64_t working_set_sizes[] = {
34         BLOCK_SIZE_BYTES,
35         512,
36         1024,
37         2048,
38         4096,
39         8192,
40         16384,
41         32768,
42         65536,
43         131072,
44         262144,
45         524288,
46         1048576,
47         2097152,
48         4194304,
49         8388608,
50         MAX_WORKING_SET_SZ,
51 };
52 
53 typedef union memlatency_state_t {
54     union memlatency_state_t* next;
55     uintptr_t pad[STRUCT_NPAD];
56 } memlatency_state_t;
57 
58 static memlatency_state_t* memlatency_state_start;
59 
60 static size_t nb_blocks = MAX_WORKING_SET_SZ / sizeof(memlatency_state_t);
61 
get_param_name_cb_fixed(char * buf,size_t buf_size,size_t param_idx)62 static void get_param_name_cb_fixed(char* buf,
63                                     size_t buf_size,
64                                     size_t param_idx) {
65     snprintf(buf, buf_size,
66              "%" PRIu64 " Bytes working size in blocks of %zu Bytes",
67              working_set_sizes[param_idx], sizeof(memlatency_state_t));
68 }
69 
get_formatted_value_cb(char * buf,size_t buf_size,int64_t value,const char * metric_name)70 static void get_formatted_value_cb(char* buf,
71                                    size_t buf_size,
72                                    int64_t value,
73                                    const char* metric_name) {
74     if (strcmp("time_micro_seconds", metric_name) == 0) {
75         int64_t mic_sec = value / 1000;
76         int64_t n_sec = value % 1000;
77 
78         snprintf(buf, buf_size, "%" PRId64 ".%03" PRId64 "", mic_sec, n_sec);
79     } else {
80         snprintf(buf, buf_size, "%" PRId64, value);
81     }
82 }
83 
84 static uint64_t mem_lat_pmu_evt_arr[] = {PMU_EV_CPU_CYCLES,
85                                          PMU_EV_INST_RETIRED};
86 
BENCH_SETUP(memlatency)87 BENCH_SETUP(memlatency) {
88     BENCH_INIT_PMU(mem_lat_pmu_evt_arr);
89     trusty_bench_get_param_name_cb = &get_param_name_cb_fixed;
90     trusty_bench_get_formatted_value_cb = &get_formatted_value_cb;
91     memlatency_state_start =
92             memalign(CACHE_LINE, nb_blocks * sizeof(memlatency_state_t));
93 
94     if (memlatency_state_start == NULL) {
95         TLOGE("Failed to Allocate memory for memlatency_state!");
96         return ERR_NO_MEMORY;
97     }
98 
99     memset((uint8_t*)memlatency_state_start, 0,
100            nb_blocks * sizeof(memlatency_state_t));
101 
102     for (size_t idx = 0; idx < nb_blocks - 1; ++idx) {
103         memlatency_state_start[idx].next = &memlatency_state_start[idx + 1];
104     }
105 
106     static_assert(sizeof(memlatency_state_t) == BLOCK_SIZE_BYTES);
107 
108     return NO_ERROR;
109 }
110 
BENCH_TEARDOWN(memlatency)111 BENCH_TEARDOWN(memlatency) {
112     free(memlatency_state_start);
113     memlatency_state_start = NULL;
114 }
115 
116 BENCH(memlatency, latency_read, 20, working_set_sizes) {
117     uint64_t sz = working_set_sizes[bench_get_param_idx()];
118     uint64_t nb_blocks = sz / BLOCK_SIZE_BYTES;
119     uint64_t loops = 10 * (MAX_WORKING_SET_SZ / sz);
120 
121     ASSERT_GT(nb_blocks, 0);
122 
123     while (loops > 0) {
124         --loops;
125         volatile union memlatency_state_t* block = memlatency_state_start;
126 
127         for (size_t idx = 0; idx < nb_blocks; idx++) {
128             /* To make sure we are not overwriting next block Address */
129             static_assert(sizeof(uintptr_t) == __SIZEOF_POINTER__);
130             block = block->next;
131         }
132     }
133 
134     return NO_ERROR;
135 test_abort:
136     return ERR_GENERIC;
137 }
138 
139 BENCH(memlatency, latency_write, 20, working_set_sizes) {
140     uint64_t sz = working_set_sizes[bench_get_param_idx()];
141     uint64_t nb_blocks = sz / BLOCK_SIZE_BYTES;
142     uint64_t loops = 10 * (MAX_WORKING_SET_SZ / sz);
143 
144     ASSERT_GT(nb_blocks, 0);
145 
146     while (loops > 0) {
147         --loops;
148         union memlatency_state_t* block = memlatency_state_start;
149 
150         for (size_t idx = 0; idx < nb_blocks; idx++) {
151             /* To make sure we are not overwriting next block Address */
152             static_assert(sizeof(uintptr_t) == __SIZEOF_POINTER__);
153             (block + idx)->pad[1] = idx + sz;
154         }
155     }
156 
157     return NO_ERROR;
158 test_abort:
159     return ERR_GENERIC;
160 }
161 
BENCH_RESULT(memlatency,latency_read,time_micro_seconds)162 BENCH_RESULT(memlatency, latency_read, time_micro_seconds) {
163     return bench_get_duration_ns();
164 }
165 
BENCH_RESULT(memlatency,latency_write,time_micro_seconds)166 BENCH_RESULT(memlatency, latency_write, time_micro_seconds) {
167     return bench_get_duration_ns();
168 }
169 
BENCH_RESULT(memlatency,latency_read,cycle_counter_0)170 BENCH_RESULT(memlatency, latency_read, cycle_counter_0) {
171     return bench_get_pmu_cnt(0);
172 }
173 
BENCH_RESULT(memlatency,latency_read,cycle_counter)174 BENCH_RESULT(memlatency, latency_read, cycle_counter) {
175     return bench_get_pmu_cnt(1);
176 }
177 
BENCH_RESULT(memlatency,latency_read,inst_retired)178 BENCH_RESULT(memlatency, latency_read, inst_retired) {
179     return bench_get_pmu_cnt(2);
180 }
181 
182 PORT_TEST(memlatency, "com.android.kernel.memorylatency.bench");
183