1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 #include "ocf/ocf_def.h" 34 #include "ocf_env.h" 35 36 #include "spdk/crc32.h" 37 #include "spdk/env.h" 38 #include "spdk/log.h" 39 40 /* Number of buffers for mempool 41 * Need to be power of two - 1 for better memory utilization 42 * It depends on memory usage of OCF which 43 * in itself depends on the workload 44 * It is a big number because OCF uses allocators 45 * for every request it sends and receives 46 * 47 * The value of 16383 is tested to work on 24 caches 48 * running IO of io_size=512 and io_depth=512, which 49 * should be more than enough for any real life scenario. 50 * Increase this value if needed. It will result in 51 * more memory being used initially on SPDK app start, 52 * when compiled with OCF support. 53 */ 54 #define ENV_ALLOCATOR_NBUFS 16383 55 56 #define GET_ELEMENTS_COUNT(_limit) (_limit < 0 ? ENV_ALLOCATOR_NBUFS : _limit) 57 58 /* Use unique index for env allocators */ 59 static env_atomic g_env_allocator_index = 0; 60 61 void * 62 env_allocator_new(env_allocator *allocator) 63 { 64 void *mem = spdk_mempool_get(allocator->mempool); 65 66 if (spdk_unlikely(!mem)) { 67 return NULL; 68 } 69 70 if (allocator->zero) { 71 memset(mem, 0, allocator->element_size); 72 } 73 74 return mem; 75 } 76 77 env_allocator * 78 env_allocator_create(uint32_t size, const char *name, bool zero) 79 { 80 return env_allocator_create_extended(size, name, -1, zero); 81 } 82 83 env_allocator * 84 env_allocator_create_extended(uint32_t size, const char *name, int limit, bool zero) 85 { 86 env_allocator *allocator; 87 char qualified_name[OCF_ALLOCATOR_NAME_MAX] = {0}; 88 89 snprintf(qualified_name, OCF_ALLOCATOR_NAME_MAX, "ocf_env_%d:%s", 90 env_atomic_inc_return(&g_env_allocator_index), name); 91 92 allocator = calloc(1, sizeof(*allocator)); 93 if (!allocator) { 94 return NULL; 95 } 96 97 allocator->mempool = spdk_mempool_create(qualified_name, 98 GET_ELEMENTS_COUNT(limit), size, 99 SPDK_MEMPOOL_DEFAULT_CACHE_SIZE, 100 SPDK_ENV_SOCKET_ID_ANY); 101 102 if (!allocator->mempool) { 103 SPDK_ERRLOG("mempool creation failed\n"); 104 free(allocator); 105 return NULL; 106 } 107 108 allocator->element_size = size; 109 allocator->element_count = GET_ELEMENTS_COUNT(limit); 110 allocator->zero = zero; 111 112 return allocator; 113 } 114 115 void 116 env_allocator_del(env_allocator *allocator, void *item) 117 { 118 spdk_mempool_put(allocator->mempool, item); 119 } 120 121 void 122 env_allocator_destroy(env_allocator *allocator) 123 { 124 if (allocator) { 125 if (allocator->element_count - spdk_mempool_count(allocator->mempool)) { 126 SPDK_ERRLOG("Not all objects deallocated\n"); 127 assert(false); 128 } 129 130 spdk_mempool_free(allocator->mempool); 131 free(allocator); 132 } 133 } 134 /* *** CRC *** */ 135 136 uint32_t 137 env_crc32(uint32_t crc, uint8_t const *message, size_t len) 138 { 139 return spdk_crc32_ieee_update(message, len, crc); 140 } 141 142 /* EXECUTION CONTEXTS */ 143 pthread_mutex_t *exec_context_mutex; 144 145 static void __attribute__((constructor)) init_execution_context(void) 146 { 147 unsigned count = env_get_execution_context_count(); 148 unsigned i; 149 150 ENV_BUG_ON(count == 0); 151 exec_context_mutex = malloc(count * sizeof(exec_context_mutex[0])); 152 ENV_BUG_ON(exec_context_mutex == NULL); 153 for (i = 0; i < count; i++) { 154 ENV_BUG_ON(pthread_mutex_init(&exec_context_mutex[i], NULL)); 155 } 156 } 157 158 static void __attribute__((destructor)) deinit_execution_context(void) 159 { 160 unsigned count = env_get_execution_context_count(); 161 unsigned i; 162 163 ENV_BUG_ON(count == 0); 164 ENV_BUG_ON(exec_context_mutex == NULL); 165 166 for (i = 0; i < count; i++) { 167 ENV_BUG_ON(pthread_mutex_destroy(&exec_context_mutex[i])); 168 } 169 free(exec_context_mutex); 170 } 171 172 /* get_execution_context must assure that after the call finishes, the caller 173 * will not get preempted from current execution context. For userspace env 174 * we simulate this behavior by acquiring per execution context mutex. As a 175 * result the caller might actually get preempted, but no other thread will 176 * execute in this context by the time the caller puts current execution ctx. */ 177 unsigned env_get_execution_context(void) 178 { 179 unsigned cpu; 180 181 cpu = sched_getcpu(); 182 cpu = (cpu == -1) ? 0 : cpu; 183 184 ENV_BUG_ON(pthread_mutex_lock(&exec_context_mutex[cpu])); 185 186 return cpu; 187 } 188 189 void env_put_execution_context(unsigned ctx) 190 { 191 pthread_mutex_unlock(&exec_context_mutex[ctx]); 192 } 193 194 unsigned env_get_execution_context_count(void) 195 { 196 int num = sysconf(_SC_NPROCESSORS_ONLN); 197 198 return (num == -1) ? 0 : num; 199 } 200