blob: f6c0dde1d30bda6f1fe40f4f3c197a98d2ba44f2 [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>
Igor Opaniukf1f3fd02017-09-14 15:34:56 +030043#include <yaml.h>
Igor Opaniukab88c952017-02-14 13:22:54 +020044
45#include "benchmark_aux.h"
Igor Opaniukf1f3fd02017-09-14 15:34:56 +030046#include "common.h"
Igor Opaniukab88c952017-02-14 13:22:54 +020047
Igor Opaniukf1f3fd02017-09-14 15:34:56 +030048#define MAX_SCALAR 20
49static struct tee_ts_global *bench_ts_global;
Igor Opaniukab88c952017-02-14 13:22:54 +020050
51static const TEEC_UUID pta_benchmark_uuid = PTA_BENCHMARK_UUID;
Igor Opaniukab88c952017-02-14 13:22:54 +020052static TEEC_SharedMemory ts_buf_shm = {
53 .flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT
54};
Igor Opaniukab88c952017-02-14 13:22:54 +020055static TEEC_Context ctx;
56static TEEC_Session sess;
57
Igor Opaniukf1f3fd02017-09-14 15:34:56 +030058static volatile sig_atomic_t is_running;
59static yaml_emitter_t emitter;
60
61
62void sigint_handler(int data)
63{
64 (void)data;
65
66 is_running = 0;
67}
68
Igor Opaniukab88c952017-02-14 13:22:54 +020069static void open_bench_pta(void)
70{
71 TEEC_Result res;
72 uint32_t err_origin;
73
74 res = TEEC_InitializeContext(NULL, &ctx);
75 tee_check_res(res, "TEEC_InitializeContext");
76
77 res = TEEC_OpenSession(&ctx, &sess, &pta_benchmark_uuid,
78 TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
79 tee_check_res(res, "TEEC_OpenSession");
80}
81
82static void close_bench_pta(void)
83{
84 /* release benchmark timestamp shm */
85 TEEC_ReleaseSharedMemory(&ts_buf_shm);
86 TEEC_CloseSession(&sess);
87 TEEC_FinalizeContext(&ctx);
88}
89
90static void init_ts_global(void *ts_global, uint32_t cores)
91{
Yves Leflochb31789d2017-08-01 14:51:18 +020092 unsigned int i;
Igor Opaniukab88c952017-02-14 13:22:54 +020093 struct tee_ts_cpu_buf *cpu_buf;
94
95 /* init global timestamp buffer */
96 bench_ts_global = (struct tee_ts_global *)ts_global;
97 bench_ts_global->cores = cores;
98
99 /* init per-cpu timestamp buffers */
Yves Leflochb31789d2017-08-01 14:51:18 +0200100 for (i = 0; i < cores; i++) {
Igor Opaniukab88c952017-02-14 13:22:54 +0200101 cpu_buf = &bench_ts_global->cpu_buf[i];
102 memset(cpu_buf, 0, sizeof(struct tee_ts_cpu_buf));
103 }
104}
105
106static void register_bench_buf(uint32_t cores)
107{
108 TEEC_Result res;
109 TEEC_Operation op = { 0 };
110 uint32_t ret_orig;
111
112 ts_buf_shm.size = sizeof(struct tee_ts_global) +
113 sizeof(struct tee_ts_cpu_buf) * cores;
114
115 /* allocate global timestamp buffer */
116 res = TEEC_AllocateSharedMemory(&ctx, &ts_buf_shm);
117 tee_check_res(res, "TEEC_AllocateSharedMemory");
118
119 init_ts_global(ts_buf_shm.buffer, cores);
120
121 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INOUT,
122 TEEC_NONE, TEEC_NONE, TEEC_NONE);
123 op.params[0].memref.parent = &ts_buf_shm;
124
125 TEEC_InvokeCommand(&sess, BENCHMARK_CMD_REGISTER_MEMREF,
126 &op, &ret_orig);
127 tee_check_res(res, "TEEC_InvokeCommand");
128}
129
130static void unregister_bench(void)
131{
132 TEEC_Result res;
133 TEEC_Operation op = { 0 };
134 uint32_t ret_orig;
135
136 op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE,
137 TEEC_NONE, TEEC_NONE, TEEC_NONE);
138
139 res = TEEC_InvokeCommand(&sess, BENCHMARK_CMD_UNREGISTER,
140 &op, &ret_orig);
141 tee_check_res(res, "TEEC_InvokeCommand");
142}
143
144static void usage(char *progname)
145{
146 fprintf(stderr, "Call latency benchmark tool for OP-TEE\n\n");
147 fprintf(stderr, "Usage:\n");
148 fprintf(stderr, " %s -h\n", progname);
149 fprintf(stderr, " %s host_app [host_app_args]\n", progname);
150 fprintf(stderr, "Options:\n");
151 fprintf(stderr, " -h Print this help and exit\n");
152 fprintf(stderr, " host_app Path to host app to benchmark\n");
153 fprintf(stderr, " host_app_args Original host app args\n");
154}
155
156static int timestamp_pop(struct tee_ts_cpu_buf *cpu_buf,
157 struct tee_time_st *ts)
158{
159 uint64_t ts_tail;
160
161 if (!cpu_buf && !ts)
162 return RING_BADPARM;
163
164 if (cpu_buf->tail >= cpu_buf->head)
165 return RING_NODATA;
166
167 ts_tail = cpu_buf->tail++;
168 *ts = cpu_buf->stamps[ts_tail & TEE_BENCH_MAX_MASK];
169
170 return 0;
171}
172
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300173static bool init_emitter(FILE *ts_file)
174{
175 yaml_event_t event;
176
177 if (!yaml_emitter_initialize(&emitter))
178 ERROR_RETURN_FALSE("Can't initialize YAML emitter");
179
180 yaml_emitter_set_canonical(&emitter, 0);
181 yaml_emitter_set_unicode(&emitter, 1);
182 yaml_emitter_set_output_file(&emitter, ts_file);
183
184 /* Stream start */
185 if (!yaml_stream_start_event_initialize(&event, YAML_UTF8_ENCODING))
186 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200187 "Failed to initialize YAML stream start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300188 if (!yaml_emitter_emit(&emitter, &event))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200189 ERROR_GOTO(emitter_delete,
190 "Failed to emit YAML stream start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300191
192 /* Document start */
193 if (!yaml_document_start_event_initialize(&event,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200194 NULL, NULL, NULL, YAML_IMPLICIT))
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300195 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200196 "Failed to initialize YAML document start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300197 if (!yaml_emitter_emit(&emitter, &event))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200198 ERROR_GOTO(emitter_delete,
199 "Failed to emit YAML doc start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300200
201 /* Mapping start */
202 if (!yaml_mapping_start_event_initialize(&event,
203 NULL, NULL , YAML_IMPLICIT,
204 YAML_ANY_SEQUENCE_STYLE))
205 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200206 "Failed to initialize YAML mapping start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300207 if (!yaml_emitter_emit(&emitter, &event))
208 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200209 "Failed to emit YAML sequence mapping event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300210 /* Key timestamps */
211 yaml_scalar_event_initialize(&event, NULL, NULL,
212 (yaml_char_t *)"timestamps", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE);
213 if (!yaml_emitter_emit(&emitter, &event))
214 ERROR_RETURN_FALSE("Failed to emit YAML scalar");
215
216 /* Sequence start */
217 if (!yaml_sequence_start_event_initialize(&event,
218 NULL, NULL , YAML_IMPLICIT,
219 YAML_ANY_SEQUENCE_STYLE))
220 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200221 "Failed to initialize YAML sequence start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300222 if (!yaml_emitter_emit(&emitter, &event))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200223 ERROR_GOTO(emitter_delete,
224 "Failed to emit YAML sequence start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300225
226 return true;
227emitter_delete:
228 yaml_emitter_delete(&emitter);
229 return false;
230}
231
232static void deinit_emitter()
233{
234 yaml_event_t event;
235
236 /* Sequence cmd */
237 if (!yaml_sequence_end_event_initialize(&event))
238 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200239 "Failed to initialize YAML sequence end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300240 if (!yaml_emitter_emit(&emitter, &event))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200241 ERROR_GOTO(emitter_delete,
242 "Failed to emit YAML sequence end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300243
244 /* Mapping end */
245 if (!yaml_mapping_end_event_initialize(&event))
246 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200247 "Failed to initialize YAML mapping end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300248 if (!yaml_emitter_emit(&emitter, &event))
249 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200250 "Failed to emit YAML mapping end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300251
252 /* Document end */
253 if (!yaml_document_end_event_initialize(&event, 0))
254 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200255 "Failed to initialize YAML document end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300256 if (!yaml_emitter_emit(&emitter, &event))
257 ERROR_GOTO(emitter_delete, "Failed to emit YAML doc end event");
258
259 /* Stream end */
260 if (!yaml_stream_end_event_initialize(&event))
261 ERROR_GOTO(emitter_delete,
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200262 "Failed to initialise YAML stream end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300263 if (!yaml_emitter_emit(&emitter, &event))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200264 ERROR_GOTO(emitter_delete,
265 "Failed to emit YAML stream end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300266
267emitter_delete:
268 yaml_emitter_delete(&emitter);
269}
270
271static bool fill_map(char *var, char *value)
272{
273 yaml_event_t event;
274
275 yaml_scalar_event_initialize(&event, NULL, NULL,
276 (yaml_char_t *)var, -1, 1, 1, YAML_PLAIN_SCALAR_STYLE);
277 if (!yaml_emitter_emit(&emitter, &event))
278 ERROR_RETURN_FALSE("Failed to emit YAML scalar");
279
280 yaml_scalar_event_initialize(&event, NULL, NULL,
281 (yaml_char_t *)value, -1, 1, 1, YAML_PLAIN_SCALAR_STYLE);
282 if (!yaml_emitter_emit(&emitter, &event))
283 ERROR_RETURN_FALSE("Failed to emit YAML scalar");
284
285 return true;
286}
287
288static bool fill_timestamp(uint32_t core, uint64_t count, uint64_t addr,
289 const char *subsystem)
290{
291 yaml_event_t event;
292 char data[MAX_SCALAR];
293
294 /* Mapping start */
295 if (!yaml_mapping_start_event_initialize(&event,
296 NULL, NULL , YAML_IMPLICIT,
297 YAML_ANY_SEQUENCE_STYLE))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200298 ERROR_RETURN_FALSE(
299 "Failed to initialize YAML mapping start event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300300 if (!yaml_emitter_emit(&emitter, &event))
301 ERROR_RETURN_FALSE("Failed to emit YAML mapping start event");
302
303 snprintf(data, MAX_SCALAR, "%" PRIu32, core);
304 fill_map("core", data);
305
306 snprintf(data, MAX_SCALAR, "%" PRIu64, count);
307 fill_map("counter", data);
308
309 snprintf(data, MAX_SCALAR, "0x%" PRIx64, addr);
310 fill_map("address", data);
311
312 snprintf(data, MAX_SCALAR, "%s", subsystem);
313 fill_map("component", data);
314
315 /* Mapping end */
316 if (!yaml_mapping_end_event_initialize(&event))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200317 ERROR_RETURN_FALSE(
318 "Failed to initialize YAML mapping end event");
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300319 if (!yaml_emitter_emit(&emitter, &event))
320 ERROR_RETURN_FALSE("Failed to emit YAML mapping end event");
321
322 return true;
323}
324
325/*
326 * Consume all timestamps from per-cpu ringbuffers and put everything into
327 * the yaml file.
328 */
Igor Opaniukab88c952017-02-14 13:22:54 +0200329static void *ts_consumer(void *arg)
330{
Yves Leflochb31789d2017-08-01 14:51:18 +0200331 unsigned int i;
332 int ret;
Igor Opaniukab88c952017-02-14 13:22:54 +0200333 bool ts_received = false;
334 uint32_t cores;
335 struct tee_time_st ts_data;
336 FILE *ts_file;
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300337 char *tsfile_path = arg;
Igor Opaniukab88c952017-02-14 13:22:54 +0200338
Igor Opaniukab88c952017-02-14 13:22:54 +0200339 if (!tsfile_path)
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300340 ERROR_GOTO(exit, "Wrong timestamp file path");
Igor Opaniukab88c952017-02-14 13:22:54 +0200341
342 cores = get_cores();
343 if (!cores)
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300344 ERROR_GOTO(exit, "Can't receive amount of avalable cores");
Igor Opaniukab88c952017-02-14 13:22:54 +0200345
346 ts_file = fopen(tsfile_path, "w");
347 if (!ts_file)
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300348 ERROR_GOTO(exit, "Can't open timestamp file");
349
350 if (!init_emitter(ts_file))
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200351 ERROR_GOTO(file_close,
352 "Error occurred in emitter initialization");
Igor Opaniukab88c952017-02-14 13:22:54 +0200353
354 while (is_running) {
355 ts_received = false;
356 for (i = 0; i < cores; i++) {
357 ret = timestamp_pop(&bench_ts_global->cpu_buf[i],
358 &ts_data);
359 if (!ret) {
360 ts_received = true;
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300361 DBG("Timestamp: core = %u; tick = %lld; pc = 0x%"
362 PRIx64 ";system = %s",
Igor Opaniukab88c952017-02-14 13:22:54 +0200363 i, ts_data.cnt, ts_data.addr,
364 bench_str_src(ts_data.src));
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300365 if (!fill_timestamp(i, ts_data.cnt,
366 ts_data.addr, bench_str_src(ts_data.src)))
367 ERROR_GOTO(deinit_yaml, "Adding timestamp failed");
368
Igor Opaniukab88c952017-02-14 13:22:54 +0200369 }
370 }
371
Yves Leflochb31789d2017-08-01 14:51:18 +0200372 if (!ts_received) {
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300373 if (is_running) {
374 DBG("yielding...");
Igor Opaniukab88c952017-02-14 13:22:54 +0200375 sched_yield();
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300376 } else {
377 ERROR_GOTO(deinit_yaml,
378 "No new data in the per-cpu ringbuffers, closing ts file");
379 }
Yves Leflochb31789d2017-08-01 14:51:18 +0200380 }
Igor Opaniukab88c952017-02-14 13:22:54 +0200381 }
382
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300383deinit_yaml:
384 deinit_emitter();
Igor Opaniukab88c952017-02-14 13:22:54 +0200385file_close:
386 fclose(ts_file);
387exit:
388 return NULL;
389}
390
391int main(int argc, char *argv[])
392{
393 int i;
394 int status;
395 pid_t pid;
396 char testapp_path[PATH_MAX];
397 char **testapp_argv;
398 char *res;
399 char *tsfile_path;
400 uint32_t cores;
401 pthread_t consumer_thread;
402
403 if (argc == 1) {
404 usage(argv[0]);
405 return 0;
406 }
407
408 /* Parse command line */
409 for (i = 1; i < argc; i++) {
410 if (!strcmp(argv[i], "-h")) {
411 usage(argv[0]);
412 return 0;
413 }
414 }
415
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300416 signal(SIGINT, sigint_handler);
417
418 INFO("1. Opening Benchmark Static TA...");
Igor Opaniukab88c952017-02-14 13:22:54 +0200419 open_bench_pta();
420
421 cores = get_cores();
422 if (!cores)
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300423 ERROR_EXIT("Receiving amount of active cores failed");
Igor Opaniukab88c952017-02-14 13:22:54 +0200424
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300425 INFO("2. Allocating per-core buffers, cores detected = %d",
Igor Opaniukab88c952017-02-14 13:22:54 +0200426 cores);
427 register_bench_buf(cores);
428
429 res = realpath(argv[1], testapp_path);
430 if (!res)
431 tee_errx("Failed to get realpath", EXIT_FAILURE);
432
433 alloc_argv(argc, argv, &testapp_argv);
434
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300435 INFO("3. Starting origin host app %s ...", testapp_path);
Igor Opaniukab88c952017-02-14 13:22:54 +0200436
437 /* fork/exec here */
438 pid = fork();
439
440 if (pid == -1) {
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300441 DBG("fork() failed");
442 ERROR_EXIT("Starting origin host application failed.");
Igor Opaniukab88c952017-02-14 13:22:54 +0200443 } else if (pid > 0) {
444 is_running = 1;
445
446 tsfile_path = malloc(strlen(testapp_path) +
447 strlen(TSFILE_NAME_SUFFIX) + 1);
448 if (!tsfile_path)
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200449 ERROR_EXIT("Memory allocation failed the file path.");
Igor Opaniukab88c952017-02-14 13:22:54 +0200450
451 tsfile_path[0] = '\0';
452 strcat(tsfile_path, testapp_path);
453 strcat(tsfile_path, TSFILE_NAME_SUFFIX);
454
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300455 INFO("Dumping timestamps to %s ...", tsfile_path);
Igor Opaniukab88c952017-02-14 13:22:54 +0200456 print_line();
457
458 if (pthread_create(&consumer_thread, NULL,
459 ts_consumer, tsfile_path)) {
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300460 DBG( "Error creating ts consumer thread");
461 ERROR_EXIT("Can't start process of reading timestamps");
Igor Opaniukab88c952017-02-14 13:22:54 +0200462 }
463 /* wait for child app exits */
464 waitpid(pid, &status, 0);
465 is_running = 0;
466
467 /* wait for our consumer thread terminate */
468 if (pthread_join(consumer_thread, NULL)) {
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300469 DBG("Error joining thread");
Igor Opaniuk66e23bf2018-02-06 19:18:59 +0200470 ERROR_EXIT("Couldn't start consuming timestamps");
Igor Opaniukab88c952017-02-14 13:22:54 +0200471 }
472 }
473 else {
474 execvp(testapp_path, testapp_argv);
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300475 DBG("execve() failed");
476 ERROR_EXIT("Starting origin host application failed");
Igor Opaniukab88c952017-02-14 13:22:54 +0200477 }
478
Igor Opaniukf1f3fd02017-09-14 15:34:56 +0300479 INFO("4. Done benchmark");
Igor Opaniukab88c952017-02-14 13:22:54 +0200480
481 dealloc_argv(argc-1, testapp_argv);
482 unregister_bench();
483 close_bench_pta();
484 return 0;
485}