19f51cf32Spaul luse /*- 29f51cf32Spaul luse * BSD LICENSE 39f51cf32Spaul luse * 49f51cf32Spaul luse * Copyright (c) Intel Corporation. 59f51cf32Spaul luse * All rights reserved. 69f51cf32Spaul luse * 79f51cf32Spaul luse * Redistribution and use in source and binary forms, with or without 89f51cf32Spaul luse * modification, are permitted provided that the following conditions 99f51cf32Spaul luse * are met: 109f51cf32Spaul luse * 119f51cf32Spaul luse * * Redistributions of source code must retain the above copyright 129f51cf32Spaul luse * notice, this list of conditions and the following disclaimer. 139f51cf32Spaul luse * * Redistributions in binary form must reproduce the above copyright 149f51cf32Spaul luse * notice, this list of conditions and the following disclaimer in 159f51cf32Spaul luse * the documentation and/or other materials provided with the 169f51cf32Spaul luse * distribution. 179f51cf32Spaul luse * * Neither the name of Intel Corporation nor the names of its 189f51cf32Spaul luse * contributors may be used to endorse or promote products derived 199f51cf32Spaul luse * from this software without specific prior written permission. 209f51cf32Spaul luse * 219f51cf32Spaul luse * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 229f51cf32Spaul luse * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 239f51cf32Spaul luse * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 249f51cf32Spaul luse * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 259f51cf32Spaul luse * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 269f51cf32Spaul luse * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 279f51cf32Spaul luse * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 289f51cf32Spaul luse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 299f51cf32Spaul luse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 309f51cf32Spaul luse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 319f51cf32Spaul luse * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 329f51cf32Spaul luse */ 339f51cf32Spaul luse 349f51cf32Spaul luse #include "spdk/stdinc.h" 359f51cf32Spaul luse #include "spdk/thread.h" 369f51cf32Spaul luse #include "spdk/env.h" 379f51cf32Spaul luse #include "spdk/event.h" 389f51cf32Spaul luse #include "spdk/log.h" 399f51cf32Spaul luse #include "spdk/string.h" 409f51cf32Spaul luse #include "spdk/accel_engine.h" 41*e69375bfSpaul luse #include "spdk/crc32.h" 429f51cf32Spaul luse 439f51cf32Spaul luse static uint64_t g_tsc_rate; 449f51cf32Spaul luse static uint64_t g_tsc_us_rate; 459f51cf32Spaul luse static uint64_t g_tsc_end; 469f51cf32Spaul luse static int g_xfer_size_bytes = 4096; 479f51cf32Spaul luse static int g_queue_depth = 32; 489f51cf32Spaul luse static int g_time_in_sec = 5; 49*e69375bfSpaul luse static uint32_t g_crc32c_seed = 0; 509f51cf32Spaul luse static bool g_verify = false; 512a0c66d0Spaul luse static const char *g_workload_type = NULL; 52514be889Spaul luse static enum accel_capability g_workload_selection; 539f51cf32Spaul luse static struct worker_thread *g_workers = NULL; 549f51cf32Spaul luse static int g_num_workers = 0; 559f51cf32Spaul luse static pthread_mutex_t g_workers_lock = PTHREAD_MUTEX_INITIALIZER; 569f51cf32Spaul luse 579f51cf32Spaul luse struct worker_thread { 589f51cf32Spaul luse struct spdk_io_channel *ch; 599f51cf32Spaul luse uint64_t xfer_completed; 609f51cf32Spaul luse uint64_t xfer_failed; 619f51cf32Spaul luse uint64_t current_queue_depth; 629f51cf32Spaul luse struct spdk_mempool *data_pool; 639f51cf32Spaul luse struct spdk_mempool *task_pool; 649f51cf32Spaul luse struct worker_thread *next; 659f51cf32Spaul luse unsigned core; 669f51cf32Spaul luse struct spdk_thread *thread; 679f51cf32Spaul luse bool is_draining; 689f51cf32Spaul luse struct spdk_poller *is_draining_poller; 699f51cf32Spaul luse struct spdk_poller *stop_poller; 709f51cf32Spaul luse }; 719f51cf32Spaul luse 729f51cf32Spaul luse struct ap_task { 739f51cf32Spaul luse void *src; 749f51cf32Spaul luse void *dst; 759f51cf32Spaul luse struct worker_thread *worker; 769f51cf32Spaul luse }; 779f51cf32Spaul luse 789f51cf32Spaul luse inline static struct ap_task * 799f51cf32Spaul luse __ap_task_from_accel_task(struct spdk_accel_task *at) 809f51cf32Spaul luse { 819f51cf32Spaul luse return (struct ap_task *)((uintptr_t)at - sizeof(struct ap_task)); 829f51cf32Spaul luse } 839f51cf32Spaul luse 849f51cf32Spaul luse inline static struct spdk_accel_task * 859f51cf32Spaul luse __accel_task_from_ap_task(struct ap_task *ap) 869f51cf32Spaul luse { 879f51cf32Spaul luse return (struct spdk_accel_task *)((uintptr_t)ap + sizeof(struct ap_task)); 889f51cf32Spaul luse } 899f51cf32Spaul luse 909f51cf32Spaul luse static void 919f51cf32Spaul luse dump_user_config(struct spdk_app_opts *opts) 929f51cf32Spaul luse { 939f51cf32Spaul luse printf("SPDK Configuration:\n"); 949f51cf32Spaul luse printf("Core mask: %s\n\n", opts->reactor_mask); 959f51cf32Spaul luse printf("Accel Perf Configuration:\n"); 962a0c66d0Spaul luse printf("Workload Type: %s\n", g_workload_type); 97*e69375bfSpaul luse if (!strcmp(g_workload_type, "crc32c")) { 98*e69375bfSpaul luse printf("CRC-32C seed: %u", g_crc32c_seed); 99*e69375bfSpaul luse } 1009f51cf32Spaul luse printf("Transfer size: %u bytes\n", g_xfer_size_bytes); 1019f51cf32Spaul luse printf("Queue depth: %u\n", g_queue_depth); 1029f51cf32Spaul luse printf("Run time: %u seconds\n", g_time_in_sec); 1039f51cf32Spaul luse printf("Verify: %s\n\n", g_verify ? "Yes" : "No"); 1049f51cf32Spaul luse } 1059f51cf32Spaul luse 1069f51cf32Spaul luse static void 1079f51cf32Spaul luse usage(void) 1089f51cf32Spaul luse { 1099f51cf32Spaul luse printf("accel_perf options:\n"); 1109f51cf32Spaul luse printf("\t[-h help message]\n"); 1119f51cf32Spaul luse printf("\t[-q queue depth]\n"); 1129f51cf32Spaul luse printf("\t[-n number of channels]\n"); 1139f51cf32Spaul luse printf("\t[-o transfer size in bytes]\n"); 1149f51cf32Spaul luse printf("\t[-t time in seconds]\n"); 115*e69375bfSpaul luse printf("\t[-w workload type must be one of these: copy, fill, crc32c\n"); 116*e69375bfSpaul luse printf("\t[-s for crc32c workload, use this seed value (default 0)\n"); 1172a0c66d0Spaul luse printf("\t[-y verify result if this switch is on]\n"); 1189f51cf32Spaul luse } 1199f51cf32Spaul luse 1209f51cf32Spaul luse static int 1219f51cf32Spaul luse parse_args(int argc, char *argv) 1229f51cf32Spaul luse { 1239f51cf32Spaul luse switch (argc) { 1249f51cf32Spaul luse case 'o': 1259f51cf32Spaul luse g_xfer_size_bytes = spdk_strtol(optarg, 10); 1269f51cf32Spaul luse break; 1279f51cf32Spaul luse case 'q': 1289f51cf32Spaul luse g_queue_depth = spdk_strtol(optarg, 10); 1299f51cf32Spaul luse break; 130*e69375bfSpaul luse case 's': 131*e69375bfSpaul luse g_crc32c_seed = spdk_strtol(optarg, 10); 132*e69375bfSpaul luse break; 1339f51cf32Spaul luse case 't': 1349f51cf32Spaul luse g_time_in_sec = spdk_strtol(optarg, 10); 1359f51cf32Spaul luse break; 1369f51cf32Spaul luse case 'y': 1379f51cf32Spaul luse g_verify = true; 1389f51cf32Spaul luse break; 1392a0c66d0Spaul luse case 'w': 1402a0c66d0Spaul luse g_workload_type = optarg; 141514be889Spaul luse if (!strcmp(g_workload_type, "copy")) { 142514be889Spaul luse g_workload_selection = ACCEL_COPY; 143514be889Spaul luse } else if (!strcmp(g_workload_type, "fill")) { 144514be889Spaul luse g_workload_selection = ACCEL_FILL; 145*e69375bfSpaul luse } else if (!strcmp(g_workload_type, "crc32c")) { 146*e69375bfSpaul luse g_workload_selection = ACCEL_CRC32C; 147514be889Spaul luse } 1482a0c66d0Spaul luse break; 1499f51cf32Spaul luse default: 1509f51cf32Spaul luse usage(); 1519f51cf32Spaul luse return 1; 1529f51cf32Spaul luse } 1539f51cf32Spaul luse return 0; 1549f51cf32Spaul luse } 1559f51cf32Spaul luse 1569f51cf32Spaul luse static void 1579f51cf32Spaul luse unregister_worker(void *arg1) 1589f51cf32Spaul luse { 1599f51cf32Spaul luse struct worker_thread *worker = arg1; 1609f51cf32Spaul luse 1619f51cf32Spaul luse spdk_mempool_free(worker->data_pool); 1629f51cf32Spaul luse spdk_mempool_free(worker->task_pool); 1639f51cf32Spaul luse spdk_put_io_channel(worker->ch); 1649f51cf32Spaul luse pthread_mutex_lock(&g_workers_lock); 1659f51cf32Spaul luse assert(g_num_workers >= 1); 1669f51cf32Spaul luse if (--g_num_workers == 0) { 1679f51cf32Spaul luse pthread_mutex_unlock(&g_workers_lock); 1689f51cf32Spaul luse spdk_app_stop(0); 1699f51cf32Spaul luse } 1709f51cf32Spaul luse pthread_mutex_unlock(&g_workers_lock); 1719f51cf32Spaul luse } 1729f51cf32Spaul luse 1739f51cf32Spaul luse static void accel_done(void *ref, int status); 1749f51cf32Spaul luse 1759f51cf32Spaul luse static void 1769f51cf32Spaul luse _submit_single(void *arg1, void *arg2) 1779f51cf32Spaul luse { 1789f51cf32Spaul luse struct worker_thread *worker = arg1; 1799f51cf32Spaul luse struct ap_task *task = arg2; 1809f51cf32Spaul luse 1819f51cf32Spaul luse assert(worker); 1829f51cf32Spaul luse 1839f51cf32Spaul luse if (g_verify) { 1849f51cf32Spaul luse memset(task->src, 0x5a, g_xfer_size_bytes); 1852a0c66d0Spaul luse memset(task->dst, 0xa5, g_xfer_size_bytes); 1869f51cf32Spaul luse } 1879f51cf32Spaul luse task->worker = worker; 1889f51cf32Spaul luse task->worker->current_queue_depth++; 189*e69375bfSpaul luse switch (g_workload_selection) { 190*e69375bfSpaul luse case ACCEL_COPY: 1919f51cf32Spaul luse spdk_accel_submit_copy(__accel_task_from_ap_task(task), 1929f51cf32Spaul luse worker->ch, task->dst, 1939f51cf32Spaul luse task->src, g_xfer_size_bytes, accel_done); 194*e69375bfSpaul luse break; 195*e69375bfSpaul luse case ACCEL_FILL: 1962a0c66d0Spaul luse /* For fill use the first byte of the task->dst buffer */ 1972a0c66d0Spaul luse spdk_accel_submit_fill(__accel_task_from_ap_task(task), 1982a0c66d0Spaul luse worker->ch, task->dst, *(uint8_t *)task->src, 1992a0c66d0Spaul luse g_xfer_size_bytes, accel_done); 200*e69375bfSpaul luse break; 201*e69375bfSpaul luse case ACCEL_CRC32C: 202*e69375bfSpaul luse spdk_accel_submit_crc32c(__accel_task_from_ap_task(task), 203*e69375bfSpaul luse worker->ch, (uint32_t *)task->dst, task->src, g_crc32c_seed, 204*e69375bfSpaul luse g_xfer_size_bytes, accel_done); 205*e69375bfSpaul luse break; 206*e69375bfSpaul luse default: 2072a0c66d0Spaul luse assert(false); 208*e69375bfSpaul luse break; 209*e69375bfSpaul luse 2102a0c66d0Spaul luse } 2119f51cf32Spaul luse } 2129f51cf32Spaul luse 2139f51cf32Spaul luse static void 2149f51cf32Spaul luse _accel_done(void *arg1) 2159f51cf32Spaul luse { 2169f51cf32Spaul luse struct ap_task *task = arg1; 2179f51cf32Spaul luse struct worker_thread *worker = task->worker; 218*e69375bfSpaul luse uint32_t sw_crc32c; 2199f51cf32Spaul luse 2209f51cf32Spaul luse assert(worker); 2219f51cf32Spaul luse assert(worker->current_queue_depth > 0); 2229f51cf32Spaul luse 2239f51cf32Spaul luse if (g_verify) { 224*e69375bfSpaul luse if (!strcmp(g_workload_type, "crc32c")) { 225*e69375bfSpaul luse /* calculate sw CRC-32C and compare to sw aceel result. */ 226*e69375bfSpaul luse sw_crc32c = spdk_crc32c_update(task->src, g_xfer_size_bytes, ~g_crc32c_seed); 227*e69375bfSpaul luse if (*(uint32_t *)task->dst != sw_crc32c) { 228*e69375bfSpaul luse SPDK_NOTICELOG("CRC-32C miscompare\n"); 229*e69375bfSpaul luse worker->xfer_failed++; 230*e69375bfSpaul luse /* TODO: cleanup */ 231*e69375bfSpaul luse exit(-1); 232*e69375bfSpaul luse } 233*e69375bfSpaul luse } else if (memcmp(task->src, task->dst, g_xfer_size_bytes)) { 2349f51cf32Spaul luse SPDK_NOTICELOG("Data miscompare\n"); 2359f51cf32Spaul luse worker->xfer_failed++; 2369f51cf32Spaul luse /* TODO: cleanup */ 2379f51cf32Spaul luse exit(-1); 2389f51cf32Spaul luse } 2399f51cf32Spaul luse } 2409f51cf32Spaul luse worker->xfer_completed++; 2419f51cf32Spaul luse worker->current_queue_depth--; 2429f51cf32Spaul luse 2439f51cf32Spaul luse if (!worker->is_draining) { 2449f51cf32Spaul luse _submit_single(worker, task); 2459f51cf32Spaul luse } else { 2469f51cf32Spaul luse spdk_mempool_put(worker->data_pool, task->src); 2479f51cf32Spaul luse spdk_mempool_put(worker->data_pool, task->dst); 2489f51cf32Spaul luse spdk_mempool_put(worker->task_pool, task); 2499f51cf32Spaul luse } 2509f51cf32Spaul luse } 2519f51cf32Spaul luse 2529f51cf32Spaul luse static int 2539f51cf32Spaul luse dump_result(void) 2549f51cf32Spaul luse { 2559f51cf32Spaul luse uint64_t total_completed = 0; 2569f51cf32Spaul luse uint64_t total_failed = 0; 2579f51cf32Spaul luse uint64_t total_xfer_per_sec, total_bw_in_MiBps; 2589f51cf32Spaul luse struct worker_thread *worker = g_workers; 2599f51cf32Spaul luse 2609f51cf32Spaul luse printf("\nCore Transfers Bandwidth Failed\n"); 2619f51cf32Spaul luse printf("-------------------------------------------------\n"); 2629f51cf32Spaul luse while (worker != NULL) { 2639f51cf32Spaul luse 2649f51cf32Spaul luse uint64_t xfer_per_sec = worker->xfer_completed / g_time_in_sec; 2659f51cf32Spaul luse uint64_t bw_in_MiBps = (worker->xfer_completed * g_xfer_size_bytes) / 2669f51cf32Spaul luse (g_time_in_sec * 1024 * 1024); 2679f51cf32Spaul luse 2689f51cf32Spaul luse total_completed += worker->xfer_completed; 2699f51cf32Spaul luse total_failed += worker->xfer_failed; 2709f51cf32Spaul luse 2719f51cf32Spaul luse if (xfer_per_sec) { 2729f51cf32Spaul luse printf("%10d%12" PRIu64 "/s%8" PRIu64 " MiB/s%11" PRIu64 "\n", 2739f51cf32Spaul luse worker->core, xfer_per_sec, 2749f51cf32Spaul luse bw_in_MiBps, worker->xfer_failed); 2759f51cf32Spaul luse } 2769f51cf32Spaul luse 2779f51cf32Spaul luse worker = worker->next; 2789f51cf32Spaul luse } 2799f51cf32Spaul luse 2809f51cf32Spaul luse total_xfer_per_sec = total_completed / g_time_in_sec; 2819f51cf32Spaul luse total_bw_in_MiBps = (total_completed * g_xfer_size_bytes) / 2829f51cf32Spaul luse (g_time_in_sec * 1024 * 1024); 2839f51cf32Spaul luse 2849f51cf32Spaul luse printf("=================================================\n"); 2859f51cf32Spaul luse printf("Total:%16" PRIu64 "/s%8" PRIu64 " MiB/s%11" PRIu64 "\n\n", 2869f51cf32Spaul luse total_xfer_per_sec, total_bw_in_MiBps, total_failed); 2879f51cf32Spaul luse 2889f51cf32Spaul luse return total_failed ? 1 : 0; 2899f51cf32Spaul luse } 2909f51cf32Spaul luse 2919f51cf32Spaul luse static int 2929f51cf32Spaul luse _check_draining(void *arg) 2939f51cf32Spaul luse { 2949f51cf32Spaul luse struct worker_thread *worker = arg; 2959f51cf32Spaul luse 2969f51cf32Spaul luse assert(worker); 2979f51cf32Spaul luse 2989f51cf32Spaul luse if (worker->current_queue_depth == 0) { 2999f51cf32Spaul luse spdk_poller_unregister(&worker->is_draining_poller); 3009f51cf32Spaul luse unregister_worker(worker); 3019f51cf32Spaul luse } 3029f51cf32Spaul luse 3039f51cf32Spaul luse return -1; 3049f51cf32Spaul luse } 3059f51cf32Spaul luse 3069f51cf32Spaul luse static int 3079f51cf32Spaul luse _worker_stop(void *arg) 3089f51cf32Spaul luse { 3099f51cf32Spaul luse struct worker_thread *worker = arg; 3109f51cf32Spaul luse 3119f51cf32Spaul luse assert(worker); 3129f51cf32Spaul luse 3139f51cf32Spaul luse spdk_poller_unregister(&worker->stop_poller); 3149f51cf32Spaul luse 3159f51cf32Spaul luse /* now let the worker drain and check it's outstanding IO with a poller */ 3169f51cf32Spaul luse worker->is_draining = true; 317ab0bc5c2SShuhei Matsumoto worker->is_draining_poller = SPDK_POLLER_REGISTER(_check_draining, worker, 0); 3189f51cf32Spaul luse 3199f51cf32Spaul luse return 0; 3209f51cf32Spaul luse } 3219f51cf32Spaul luse 3229f51cf32Spaul luse static void 3239f51cf32Spaul luse _init_thread_done(void *ctx) 3249f51cf32Spaul luse { 3259f51cf32Spaul luse } 3269f51cf32Spaul luse 3279f51cf32Spaul luse static void 3289f51cf32Spaul luse _init_thread(void *arg1) 3299f51cf32Spaul luse { 3309f51cf32Spaul luse struct worker_thread *worker; 3319f51cf32Spaul luse char buf_pool_name[30], task_pool_name[30]; 3329f51cf32Spaul luse struct ap_task *task; 3339f51cf32Spaul luse int i; 3349f51cf32Spaul luse 3359f51cf32Spaul luse worker = calloc(1, sizeof(*worker)); 3369f51cf32Spaul luse if (worker == NULL) { 3379f51cf32Spaul luse fprintf(stderr, "Unable to allocate worker\n"); 3389f51cf32Spaul luse return; 3399f51cf32Spaul luse } 3409f51cf32Spaul luse 3419f51cf32Spaul luse worker->core = spdk_env_get_current_core(); 3429f51cf32Spaul luse worker->thread = spdk_get_thread(); 3439f51cf32Spaul luse worker->next = g_workers; 3449f51cf32Spaul luse worker->ch = spdk_accel_engine_get_io_channel(); 3459f51cf32Spaul luse snprintf(buf_pool_name, sizeof(buf_pool_name), "buf_pool_%d", g_num_workers); 3469f51cf32Spaul luse snprintf(task_pool_name, sizeof(task_pool_name), "task_pool_%d", g_num_workers); 3479f51cf32Spaul luse worker->data_pool = spdk_mempool_create(buf_pool_name, 3489f51cf32Spaul luse g_queue_depth * 2, /* src + dst */ 3499f51cf32Spaul luse g_xfer_size_bytes, 3509f51cf32Spaul luse SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 3519f51cf32Spaul luse SPDK_ENV_SOCKET_ID_ANY); 3529f51cf32Spaul luse worker->task_pool = spdk_mempool_create(task_pool_name, 3539f51cf32Spaul luse g_queue_depth, 3549f51cf32Spaul luse spdk_accel_task_size() + sizeof(struct ap_task), 3559f51cf32Spaul luse SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 3569f51cf32Spaul luse SPDK_ENV_SOCKET_ID_ANY); 3579f51cf32Spaul luse if (!worker->data_pool || !worker->task_pool) { 3589f51cf32Spaul luse fprintf(stderr, "Could not allocate buffer pool.\n"); 3599f51cf32Spaul luse spdk_mempool_free(worker->data_pool); 3609f51cf32Spaul luse spdk_mempool_free(worker->task_pool); 3619f51cf32Spaul luse free(worker); 3629f51cf32Spaul luse return; 3639f51cf32Spaul luse } 3649f51cf32Spaul luse 3659f51cf32Spaul luse /* Register a poller that will stop the worker at time elapsed */ 366ab0bc5c2SShuhei Matsumoto worker->stop_poller = SPDK_POLLER_REGISTER(_worker_stop, worker, 3679f51cf32Spaul luse g_time_in_sec * 1000000ULL); 3689f51cf32Spaul luse 3699f51cf32Spaul luse g_workers = worker; 3709f51cf32Spaul luse pthread_mutex_lock(&g_workers_lock); 3719f51cf32Spaul luse g_num_workers++; 3729f51cf32Spaul luse pthread_mutex_unlock(&g_workers_lock); 3739f51cf32Spaul luse 3749f51cf32Spaul luse for (i = 0; i < g_queue_depth; i++) { 3759f51cf32Spaul luse task = spdk_mempool_get(worker->task_pool); 3769f51cf32Spaul luse if (!task) { 3779f51cf32Spaul luse fprintf(stderr, "Unable to get accel_task\n"); 3789f51cf32Spaul luse return; 3799f51cf32Spaul luse } 3809f51cf32Spaul luse task->src = spdk_mempool_get(worker->data_pool); 3819f51cf32Spaul luse task->dst = spdk_mempool_get(worker->data_pool); 3829f51cf32Spaul luse _submit_single(worker, task); 3839f51cf32Spaul luse } 3849f51cf32Spaul luse } 3859f51cf32Spaul luse 3869f51cf32Spaul luse static void 3879f51cf32Spaul luse accel_done(void *ref, int status) 3889f51cf32Spaul luse { 3899f51cf32Spaul luse struct ap_task *task = __ap_task_from_accel_task(ref); 3909f51cf32Spaul luse struct worker_thread *worker = task->worker; 3919f51cf32Spaul luse 3929f51cf32Spaul luse assert(worker); 3939f51cf32Spaul luse 3949f51cf32Spaul luse spdk_thread_send_msg(worker->thread, _accel_done, task); 3959f51cf32Spaul luse } 3969f51cf32Spaul luse 3979f51cf32Spaul luse static void 3989f51cf32Spaul luse accel_perf_start(void *arg1) 3999f51cf32Spaul luse { 400514be889Spaul luse uint64_t capabilites; 401514be889Spaul luse struct spdk_io_channel *accel_ch; 402514be889Spaul luse 403514be889Spaul luse accel_ch = spdk_accel_engine_get_io_channel(); 404514be889Spaul luse capabilites = spdk_accel_get_capabilities(accel_ch); 405514be889Spaul luse spdk_put_io_channel(accel_ch); 406514be889Spaul luse 407514be889Spaul luse if ((capabilites & g_workload_selection) != g_workload_selection) { 408514be889Spaul luse SPDK_ERRLOG("Selected workload is not supported by the current engine\n"); 409514be889Spaul luse SPDK_NOTICELOG("Software engine is selected by default, enable a HW engine via RPC\n\n"); 410514be889Spaul luse spdk_app_stop(-1); 411514be889Spaul luse return; 412514be889Spaul luse } 413514be889Spaul luse 4149f51cf32Spaul luse g_tsc_rate = spdk_get_ticks_hz(); 4159f51cf32Spaul luse g_tsc_us_rate = g_tsc_rate / (1000 * 1000); 4169f51cf32Spaul luse g_tsc_end = spdk_get_ticks() + g_time_in_sec * g_tsc_rate; 4179f51cf32Spaul luse 4189f51cf32Spaul luse printf("Running for %d seconds...\n", g_time_in_sec); 4199f51cf32Spaul luse fflush(stdout); 4209f51cf32Spaul luse 4219f51cf32Spaul luse spdk_for_each_thread(_init_thread, NULL, _init_thread_done); 4229f51cf32Spaul luse } 4239f51cf32Spaul luse 4249f51cf32Spaul luse int 4259f51cf32Spaul luse main(int argc, char **argv) 4269f51cf32Spaul luse { 4279f51cf32Spaul luse struct spdk_app_opts opts = {}; 4289f51cf32Spaul luse struct worker_thread *worker, *tmp; 4299f51cf32Spaul luse int rc = 0; 4309f51cf32Spaul luse 4319f51cf32Spaul luse pthread_mutex_init(&g_workers_lock, NULL); 4329f51cf32Spaul luse spdk_app_opts_init(&opts); 4339f51cf32Spaul luse opts.reactor_mask = "0x1"; 4342a0c66d0Spaul luse if ((rc = spdk_app_parse_args(argc, argv, &opts, "o:q:t:yw:", NULL, parse_args, 4359f51cf32Spaul luse usage)) != SPDK_APP_PARSE_ARGS_SUCCESS) { 4369f51cf32Spaul luse rc = -1; 4379f51cf32Spaul luse goto cleanup; 4389f51cf32Spaul luse } 4399f51cf32Spaul luse 44036676037Spaul luse if (g_workload_type == NULL || 44136676037Spaul luse (strcmp(g_workload_type, "copy") && 442*e69375bfSpaul luse strcmp(g_workload_type, "fill") && 443*e69375bfSpaul luse strcmp(g_workload_type, "crc32c"))) { 4442a0c66d0Spaul luse usage(); 4452a0c66d0Spaul luse rc = -1; 4462a0c66d0Spaul luse goto cleanup; 4472a0c66d0Spaul luse } 4482a0c66d0Spaul luse 4499f51cf32Spaul luse dump_user_config(&opts); 4509f51cf32Spaul luse rc = spdk_app_start(&opts, accel_perf_start, NULL); 4519f51cf32Spaul luse if (rc) { 4529f51cf32Spaul luse SPDK_ERRLOG("ERROR starting application\n"); 4539f51cf32Spaul luse } else { 4549f51cf32Spaul luse dump_result(); 4559f51cf32Spaul luse } 4569f51cf32Spaul luse 4579f51cf32Spaul luse pthread_mutex_destroy(&g_workers_lock); 4589f51cf32Spaul luse 4599f51cf32Spaul luse worker = g_workers; 4609f51cf32Spaul luse while (worker) { 4619f51cf32Spaul luse tmp = worker->next; 4629f51cf32Spaul luse free(worker); 4639f51cf32Spaul luse worker = tmp; 4649f51cf32Spaul luse } 4659f51cf32Spaul luse cleanup: 4669f51cf32Spaul luse spdk_app_fini(); 4679f51cf32Spaul luse return rc; 4689f51cf32Spaul luse } 469