/** * Copyright (C) Mellanox Technologies Ltd. 2019. ALL RIGHTS RESERVED. * * See file LICENSE for terms. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #define UCS_CPU_CACHE_FILE_FMT "/sys/devices/system/cpu/cpu%d/cache/index%d/%s" #define UCS_CPU_CACHE_LEVEL_FILE "level" #define UCS_CPU_CACHE_TYPE_FILE "type" #define UCS_CPU_CACHE_SIZE_FILE "size" /* cache size array. index - cache type (ucs_cpu_cache_type_t), value - cache value, * 0 means cache is not supported */ static size_t ucs_cpu_cache_size[UCS_CPU_CACHE_LAST] = {0}; static ucs_init_once_t ucs_cache_read_once = UCS_INIT_ONCE_INITIALIZER; /* cache datatypes */ struct { /* sysfs entries for system cache sizes */ int level; const char *type; } const ucs_cpu_cache_sysfs_name[] = { [UCS_CPU_CACHE_L1d] = {.level = 1, .type = "Data"}, [UCS_CPU_CACHE_L1i] = {.level = 1, .type = "Instruction"}, [UCS_CPU_CACHE_L2] = {.level = 2, .type = "Unified"}, [UCS_CPU_CACHE_L3] = {.level = 3, .type = "Unified"} }; const ucs_cpu_builtin_memcpy_t ucs_cpu_builtin_memcpy[UCS_CPU_VENDOR_LAST] = { [UCS_CPU_VENDOR_UNKNOWN] = { .min = UCS_MEMUNITS_INF, .max = UCS_MEMUNITS_INF }, [UCS_CPU_VENDOR_INTEL] = { .min = 1 * UCS_KBYTE, .max = 8 * UCS_MBYTE }, [UCS_CPU_VENDOR_AMD] = { .min = 1 * UCS_KBYTE, .max = 136 * UCS_KBYTE }, [UCS_CPU_VENDOR_GENERIC_ARM] = { .min = UCS_MEMUNITS_INF, .max = UCS_MEMUNITS_INF }, [UCS_CPU_VENDOR_GENERIC_PPC] = { .min = UCS_MEMUNITS_INF, .max = UCS_MEMUNITS_INF } }; const size_t ucs_cpu_est_bcopy_bw[UCS_CPU_VENDOR_LAST] = { [UCS_CPU_VENDOR_UNKNOWN] = 5800 * UCS_MBYTE, [UCS_CPU_VENDOR_INTEL] = 5800 * UCS_MBYTE, [UCS_CPU_VENDOR_AMD] = 5008 * UCS_MBYTE, [UCS_CPU_VENDOR_GENERIC_ARM] = 5800 * UCS_MBYTE, [UCS_CPU_VENDOR_GENERIC_PPC] = 5800 * UCS_MBYTE }; static void ucs_sysfs_get_cache_size() { char type_str[32]; /* Data/Instruction/Unified */ char size_str[32]; /* memunits */ int cache_index; int cpu; long level; ssize_t file_size; ucs_cpu_cache_type_t cache_type; ucs_status_t status; cpu = ucs_get_first_cpu(); for (cache_index = 0;; cache_index++) { file_size = ucs_read_file_str(type_str, sizeof(type_str), 1, UCS_CPU_CACHE_FILE_FMT, cpu, cache_index, UCS_CPU_CACHE_TYPE_FILE); if (file_size < 0) { return; /* no more files */ } ucs_strtrim(type_str); status = ucs_read_file_number(&level, 1, UCS_CPU_CACHE_FILE_FMT, cpu, cache_index, UCS_CPU_CACHE_LEVEL_FILE); if (status != UCS_OK) { return; /* no more files */ } /* ok, we found valid directory, let's try to read cache size */ file_size = ucs_read_file_str(size_str, sizeof(size_str), 1, UCS_CPU_CACHE_FILE_FMT, cpu, cache_index, UCS_CPU_CACHE_SIZE_FILE); if (file_size < 0) { return; /* no more files */ } /* now lookup for cache size entry */ for (cache_type = UCS_CPU_CACHE_L1d; cache_type < UCS_CPU_CACHE_LAST; cache_type++) { if ((ucs_cpu_cache_sysfs_name[cache_type].level == level) && !strcasecmp(ucs_cpu_cache_sysfs_name[cache_type].type, type_str)) { if (ucs_cpu_cache_size[cache_type] != 0) { break; } status = ucs_str_to_memunits(ucs_strtrim(size_str), &ucs_cpu_cache_size[cache_type]); if (status != UCS_OK) { ucs_cpu_cache_size[cache_type] = 0; /* reset cache value */ } } } } } size_t ucs_cpu_get_cache_size(ucs_cpu_cache_type_t type) { ucs_status_t status; if (type >= UCS_CPU_CACHE_LAST) { return 0; } UCS_INIT_ONCE(&ucs_cache_read_once) { UCS_STATIC_ASSERT(ucs_array_size(ucs_cpu_cache_size) == UCS_CPU_CACHE_LAST); /* try first CPU-specific algorithm */ status = ucs_arch_get_cache_size(ucs_cpu_cache_size); if (status != UCS_OK) { /* read rest of caches from sysfs */ ucs_sysfs_get_cache_size(); } } return ucs_cpu_cache_size[type]; } double ucs_cpu_get_memcpy_bw() { return ucs_cpu_est_bcopy_bw[ucs_arch_get_cpu_vendor()]; }