blob: 2c617213c407581a1c025a81677f2f8ae89a27e4 [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{
87 struct tee_ts_cpu_buf *cpu_buf;
88
89 /* init global timestamp buffer */
90 bench_ts_global = (struct tee_ts_global *)ts_global;
91 bench_ts_global->cores = cores;
92
93 /* init per-cpu timestamp buffers */
94 for (int i = 0; i < cores; i++) {
95 cpu_buf = &bench_ts_global->cpu_buf[i];
96 memset(cpu_buf, 0, sizeof(struct tee_ts_cpu_buf));
97 }
98}
99
100static void register_bench_buf(uint32_t cores)
101{
102 TEEC_Result res;
103 TEEC_Operation op = { 0 };
104 uint32_t ret_orig;
105
106 ts_buf_shm.size = sizeof(struct tee_ts_global) +
107 sizeof(struct tee_ts_cpu_buf) * cores;
108
109 /* allocate global timestamp buffer */
110 res = TEEC_AllocateSharedMemory(&ctx, &ts_buf_shm);
111 tee_check_res(res, "TEEC_AllocateSharedMemory");
112
113 init_ts_global(ts_buf_shm.buffer, cores);
114
115 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INOUT,
116 TEEC_NONE, TEEC_NONE, TEEC_NONE);
117 op.params[0].memref.parent = &ts_buf_shm;
118
119 TEEC_InvokeCommand(&sess, BENCHMARK_CMD_REGISTER_MEMREF,
120 &op, &ret_orig);
121 tee_check_res(res, "TEEC_InvokeCommand");
122}
123
124static void unregister_bench(void)
125{
126 TEEC_Result res;
127 TEEC_Operation op = { 0 };
128 uint32_t ret_orig;
129
130 op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE,
131 TEEC_NONE, TEEC_NONE, TEEC_NONE);
132
133 res = TEEC_InvokeCommand(&sess, BENCHMARK_CMD_UNREGISTER,
134 &op, &ret_orig);
135 tee_check_res(res, "TEEC_InvokeCommand");
136}
137
138static void usage(char *progname)
139{
140 fprintf(stderr, "Call latency benchmark tool for OP-TEE\n\n");
141 fprintf(stderr, "Usage:\n");
142 fprintf(stderr, " %s -h\n", progname);
143 fprintf(stderr, " %s host_app [host_app_args]\n", progname);
144 fprintf(stderr, "Options:\n");
145 fprintf(stderr, " -h Print this help and exit\n");
146 fprintf(stderr, " host_app Path to host app to benchmark\n");
147 fprintf(stderr, " host_app_args Original host app args\n");
148}
149
150static int timestamp_pop(struct tee_ts_cpu_buf *cpu_buf,
151 struct tee_time_st *ts)
152{
153 uint64_t ts_tail;
154
155 if (!cpu_buf && !ts)
156 return RING_BADPARM;
157
158 if (cpu_buf->tail >= cpu_buf->head)
159 return RING_NODATA;
160
161 ts_tail = cpu_buf->tail++;
162 *ts = cpu_buf->stamps[ts_tail & TEE_BENCH_MAX_MASK];
163
164 return 0;
165}
166
167static void *ts_consumer(void *arg)
168{
169 int i, ret;
170 bool ts_received = false;
171 uint32_t cores;
172 struct tee_time_st ts_data;
173 FILE *ts_file;
174 char *tsfile_path;
175
176 tsfile_path = arg;
177 if (!tsfile_path)
178 goto exit;
179
180 cores = get_cores();
181 if (!cores)
182 goto exit;
183
184 ts_file = fopen(tsfile_path, "w");
185 if (!ts_file)
186 goto exit;
187
188 while (is_running) {
189 ts_received = false;
190 for (i = 0; i < cores; i++) {
191 ret = timestamp_pop(&bench_ts_global->cpu_buf[i],
192 &ts_data);
193 if (!ret) {
194 ts_received = true;
195 fprintf(ts_file, "%ld\t%lld\t0x%"
196 PRIx64 "\t%s\n",
197 i, ts_data.cnt, ts_data.addr,
198 bench_str_src(ts_data.src));
199 }
200 }
201
202 if (!ts_received)
203 if (is_running)
204 sched_yield();
205 else
206 goto file_close;
207 }
208
209file_close:
210 fclose(ts_file);
211exit:
212 return NULL;
213}
214
215int main(int argc, char *argv[])
216{
217 int i;
218 int status;
219 pid_t pid;
220 char testapp_path[PATH_MAX];
221 char **testapp_argv;
222 char *res;
223 char *tsfile_path;
224 uint32_t cores;
225 pthread_t consumer_thread;
226
227 if (argc == 1) {
228 usage(argv[0]);
229 return 0;
230 }
231
232 /* Parse command line */
233 for (i = 1; i < argc; i++) {
234 if (!strcmp(argv[i], "-h")) {
235 usage(argv[0]);
236 return 0;
237 }
238 }
239
240 printf("1. Opening Benchmark Static TA...\n");
241 open_bench_pta();
242
243 cores = get_cores();
244 if (!cores)
245 tee_errx("Receiving amount of active cores failed",
246 EXIT_FAILURE);
247
248 printf("2. Allocating per-core buffers, cores detected = %d\n",
249 cores);
250 register_bench_buf(cores);
251
252 res = realpath(argv[1], testapp_path);
253 if (!res)
254 tee_errx("Failed to get realpath", EXIT_FAILURE);
255
256 alloc_argv(argc, argv, &testapp_argv);
257
258 printf("3. Starting origin host app %s ...\n", testapp_path);
259
260 /* fork/exec here */
261 pid = fork();
262
263 if (pid == -1) {
264 tee_errx("fork() failed", EXIT_FAILURE);
265 } else if (pid > 0) {
266 is_running = 1;
267
268 tsfile_path = malloc(strlen(testapp_path) +
269 strlen(TSFILE_NAME_SUFFIX) + 1);
270 if (!tsfile_path)
271 return 1;
272
273 tsfile_path[0] = '\0';
274 strcat(tsfile_path, testapp_path);
275 strcat(tsfile_path, TSFILE_NAME_SUFFIX);
276
277 printf("Dumping timestamps to %s ...\n", tsfile_path);
278 print_line();
279
280 if (pthread_create(&consumer_thread, NULL,
281 ts_consumer, tsfile_path)) {
282 fprintf(stderr, "Error creating ts consumer thread\n");
283 return 1;
284 }
285 /* wait for child app exits */
286 waitpid(pid, &status, 0);
287 is_running = 0;
288
289 /* wait for our consumer thread terminate */
290 if (pthread_join(consumer_thread, NULL)) {
291 fprintf(stderr, "Error joining thread\n");
292 return 2;
293 }
294 }
295 else {
296 execvp(testapp_path, testapp_argv);
297 tee_errx("execve() failed", EXIT_FAILURE);
298 }
299
300 printf("4. Done benchmark\n");
301
302 dealloc_argv(argc-1, testapp_argv);
303 unregister_bench();
304 close_bench_pta();
305 return 0;
306}