blob: 458f1a9d90f1fab8001fe36c9350118783730ea4 [file] [log] [blame]
Igor Opaniukab88c952017-02-14 13:22:54 +02001/*
2 * Copyright (c) 2016, Linaro Limited
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <errno.h>
29#include <fcntl.h>
30#include <inttypes.h>
31#include <limits.h>
32#include <libgen.h>
33#include <pthread.h>
34#include <string.h>
35#include <stdio.h>
36#include <stdbool.h>
37#include <stdlib.h>
38#include <sys/types.h>
39#include <sys/mman.h>
40#include <sys/stat.h>
41#include <sys/wait.h>
42#include <unistd.h>
43
44#include "benchmark_aux.h"
45
46#define STAT_AMOUNT 5
47#define TSFILE_NAME_SUFFIX ".ts"
48
49#define RING_SUCCESS 0
50#define RING_BADPARM -1
51#define RING_NODATA -2
52
53static const TEEC_UUID pta_benchmark_uuid = PTA_BENCHMARK_UUID;
54struct tee_ts_global *bench_ts_global;
55static bool is_running;
56
57static TEEC_SharedMemory ts_buf_shm = {
58 .flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT
59};
60
61static TEEC_Context ctx;
62static TEEC_Session sess;
63
64static void open_bench_pta(void)
65{
66 TEEC_Result res;
67 uint32_t err_origin;
68
69 res = TEEC_InitializeContext(NULL, &ctx);
70 tee_check_res(res, "TEEC_InitializeContext");
71
72 res = TEEC_OpenSession(&ctx, &sess, &pta_benchmark_uuid,
73 TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
74 tee_check_res(res, "TEEC_OpenSession");
75}
76
77static void close_bench_pta(void)
78{
79 /* release benchmark timestamp shm */
80 TEEC_ReleaseSharedMemory(&ts_buf_shm);
81 TEEC_CloseSession(&sess);
82 TEEC_FinalizeContext(&ctx);
83}
84
85static void init_ts_global(void *ts_global, uint32_t cores)
86{
Yves Leflochb31789d2017-08-01 14:51:18 +020087 unsigned int i;
Igor Opaniukab88c952017-02-14 13:22:54 +020088 struct tee_ts_cpu_buf *cpu_buf;
89
90 /* init global timestamp buffer */
91 bench_ts_global = (struct tee_ts_global *)ts_global;
92 bench_ts_global->cores = cores;
93
94 /* init per-cpu timestamp buffers */
Yves Leflochb31789d2017-08-01 14:51:18 +020095 for (i = 0; i < cores; i++) {
Igor Opaniukab88c952017-02-14 13:22:54 +020096 cpu_buf = &bench_ts_global->cpu_buf[i];
97 memset(cpu_buf, 0, sizeof(struct tee_ts_cpu_buf));
98 }
99}
100
101static void register_bench_buf(uint32_t cores)
102{
103 TEEC_Result res;
104 TEEC_Operation op = { 0 };
105 uint32_t ret_orig;
106
107 ts_buf_shm.size = sizeof(struct tee_ts_global) +
108 sizeof(struct tee_ts_cpu_buf) * cores;
109
110 /* allocate global timestamp buffer */
111 res = TEEC_AllocateSharedMemory(&ctx, &ts_buf_shm);
112 tee_check_res(res, "TEEC_AllocateSharedMemory");
113
114 init_ts_global(ts_buf_shm.buffer, cores);
115
116 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INOUT,
117 TEEC_NONE, TEEC_NONE, TEEC_NONE);
118 op.params[0].memref.parent = &ts_buf_shm;
119
120 TEEC_InvokeCommand(&sess, BENCHMARK_CMD_REGISTER_MEMREF,
121 &op, &ret_orig);
122 tee_check_res(res, "TEEC_InvokeCommand");
123}
124
125static void unregister_bench(void)
126{
127 TEEC_Result res;
128 TEEC_Operation op = { 0 };
129 uint32_t ret_orig;
130
131 op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE,
132 TEEC_NONE, TEEC_NONE, TEEC_NONE);
133
134 res = TEEC_InvokeCommand(&sess, BENCHMARK_CMD_UNREGISTER,
135 &op, &ret_orig);
136 tee_check_res(res, "TEEC_InvokeCommand");
137}
138
139static void usage(char *progname)
140{
141 fprintf(stderr, "Call latency benchmark tool for OP-TEE\n\n");
142 fprintf(stderr, "Usage:\n");
143 fprintf(stderr, " %s -h\n", progname);
144 fprintf(stderr, " %s host_app [host_app_args]\n", progname);
145 fprintf(stderr, "Options:\n");
146 fprintf(stderr, " -h Print this help and exit\n");
147 fprintf(stderr, " host_app Path to host app to benchmark\n");
148 fprintf(stderr, " host_app_args Original host app args\n");
149}
150
151static int timestamp_pop(struct tee_ts_cpu_buf *cpu_buf,
152 struct tee_time_st *ts)
153{
154 uint64_t ts_tail;
155
156 if (!cpu_buf && !ts)
157 return RING_BADPARM;
158
159 if (cpu_buf->tail >= cpu_buf->head)
160 return RING_NODATA;
161
162 ts_tail = cpu_buf->tail++;
163 *ts = cpu_buf->stamps[ts_tail & TEE_BENCH_MAX_MASK];
164
165 return 0;
166}
167
168static void *ts_consumer(void *arg)
169{
Yves Leflochb31789d2017-08-01 14:51:18 +0200170 unsigned int i;
171 int ret;
Igor Opaniukab88c952017-02-14 13:22:54 +0200172 bool ts_received = false;
173 uint32_t cores;
174 struct tee_time_st ts_data;
175 FILE *ts_file;
176 char *tsfile_path;
177
178 tsfile_path = arg;
179 if (!tsfile_path)
180 goto exit;
181
182 cores = get_cores();
183 if (!cores)
184 goto exit;
185
186 ts_file = fopen(tsfile_path, "w");
187 if (!ts_file)
188 goto exit;
189
190 while (is_running) {
191 ts_received = false;
192 for (i = 0; i < cores; i++) {
193 ret = timestamp_pop(&bench_ts_global->cpu_buf[i],
194 &ts_data);
195 if (!ret) {
196 ts_received = true;
Yves Leflochb31789d2017-08-01 14:51:18 +0200197 fprintf(ts_file, "%u\t%lld\t0x%"
Igor Opaniukab88c952017-02-14 13:22:54 +0200198 PRIx64 "\t%s\n",
199 i, ts_data.cnt, ts_data.addr,
200 bench_str_src(ts_data.src));
201 }
202 }
203
Yves Leflochb31789d2017-08-01 14:51:18 +0200204 if (!ts_received) {
Igor Opaniukab88c952017-02-14 13:22:54 +0200205 if (is_running)
206 sched_yield();
207 else
208 goto file_close;
Yves Leflochb31789d2017-08-01 14:51:18 +0200209 }
Igor Opaniukab88c952017-02-14 13:22:54 +0200210 }
211
212file_close:
213 fclose(ts_file);
214exit:
215 return NULL;
216}
217
218int main(int argc, char *argv[])
219{
220 int i;
221 int status;
222 pid_t pid;
223 char testapp_path[PATH_MAX];
224 char **testapp_argv;
225 char *res;
226 char *tsfile_path;
227 uint32_t cores;
228 pthread_t consumer_thread;
229
230 if (argc == 1) {
231 usage(argv[0]);
232 return 0;
233 }
234
235 /* Parse command line */
236 for (i = 1; i < argc; i++) {
237 if (!strcmp(argv[i], "-h")) {
238 usage(argv[0]);
239 return 0;
240 }
241 }
242
243 printf("1. Opening Benchmark Static TA...\n");
244 open_bench_pta();
245
246 cores = get_cores();
247 if (!cores)
248 tee_errx("Receiving amount of active cores failed",
249 EXIT_FAILURE);
250
251 printf("2. Allocating per-core buffers, cores detected = %d\n",
252 cores);
253 register_bench_buf(cores);
254
255 res = realpath(argv[1], testapp_path);
256 if (!res)
257 tee_errx("Failed to get realpath", EXIT_FAILURE);
258
259 alloc_argv(argc, argv, &testapp_argv);
260
261 printf("3. Starting origin host app %s ...\n", testapp_path);
262
263 /* fork/exec here */
264 pid = fork();
265
266 if (pid == -1) {
267 tee_errx("fork() failed", EXIT_FAILURE);
268 } else if (pid > 0) {
269 is_running = 1;
270
271 tsfile_path = malloc(strlen(testapp_path) +
272 strlen(TSFILE_NAME_SUFFIX) + 1);
273 if (!tsfile_path)
274 return 1;
275
276 tsfile_path[0] = '\0';
277 strcat(tsfile_path, testapp_path);
278 strcat(tsfile_path, TSFILE_NAME_SUFFIX);
279
280 printf("Dumping timestamps to %s ...\n", tsfile_path);
281 print_line();
282
283 if (pthread_create(&consumer_thread, NULL,
284 ts_consumer, tsfile_path)) {
285 fprintf(stderr, "Error creating ts consumer thread\n");
286 return 1;
287 }
288 /* wait for child app exits */
289 waitpid(pid, &status, 0);
290 is_running = 0;
291
292 /* wait for our consumer thread terminate */
293 if (pthread_join(consumer_thread, NULL)) {
294 fprintf(stderr, "Error joining thread\n");
295 return 2;
296 }
297 }
298 else {
299 execvp(testapp_path, testapp_argv);
300 tee_errx("execve() failed", EXIT_FAILURE);
301 }
302
303 printf("4. Done benchmark\n");
304
305 dealloc_argv(argc-1, testapp_argv);
306 unregister_bench();
307 close_bench_pta();
308 return 0;
309}