diff options
author | Peter Schiffer <pschiffe@redhat.com> | 2013-04-04 19:02:29 +0200 |
---|---|---|
committer | Peter Schiffer <pschiffe@redhat.com> | 2013-04-04 19:02:29 +0200 |
commit | 381f0c0a5cd98a48dc6d5a5e0b98443707d8ea81 (patch) | |
tree | bdad2e739aac00eb02e71dfe7d4074268c6f69a4 /src/hardware/sysfs.c | |
parent | c47c5c19c5857439db30e40d4a691f5b700adf5f (diff) | |
download | openlmi-providers-381f0c0a5cd98a48dc6d5a5e0b98443707d8ea81.tar.gz openlmi-providers-381f0c0a5cd98a48dc6d5a5e0b98443707d8ea81.tar.xz openlmi-providers-381f0c0a5cd98a48dc6d5a5e0b98443707d8ea81.zip |
Hardware: Added Processor Cache Memory Provider
New Providers:
* LMI_ProcessorCacheMemoryProvider
* LMI_AssociatedProcessorCacheMemoryProvider
Other Changes:
* Optimized usage of string constats
* Fixed wrong usage of pointers in dmidecode.c
* Filled unknown mandatory fields in providers with "Unknown" value
* Replaced hard coded numbers with LMI constants
* Minor optimization - don't gather data which won't be used
Diffstat (limited to 'src/hardware/sysfs.c')
-rw-r--r-- | src/hardware/sysfs.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/src/hardware/sysfs.c b/src/hardware/sysfs.c new file mode 100644 index 0000000..c2cc1af --- /dev/null +++ b/src/hardware/sysfs.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Peter Schiffer <pschiffe@redhat.com> + */ + +#include "sysfs.h" + + +/* + * Read unsigned value from file. + * @param path of file + * @paratm result + * @return 0 if success, negative value otherwise + */ +short path_get_unsigned(const char *path, unsigned *result) +{ + short ret = -1; + unsigned buffer_size = 0; + char **buffer = NULL; + + if (read_file(path, &buffer, &buffer_size) != 0 || buffer_size < 1) { + ret = -2; + goto done; + } + if (sscanf(buffer[0], "%u", result) != 1) { + warn("Failed to parse file: \"%s\"; Error: %s", + path, strerror(errno)); + ret = -3; + goto done; + } + + ret = 0; + +done: + free_2d_buffer(&buffer, &buffer_size); + + if (ret != 0) { + *result = 0; + } + + return ret; +} + +/* + * Read string value from file. + * @param path of file + * @paratm result + * @return 0 if success, negative value otherwise + */ +short path_get_string(const char *path, char **result) +{ + short ret = -1; + unsigned buffer_size = 0; + char **buffer = NULL; + + if (read_file(path, &buffer, &buffer_size) != 0 || buffer_size < 1) { + ret = -2; + goto done; + } + *result = trim(buffer[0], NULL); + if (!(*result)) { + warn("Failed to parse file: \"%s\"", path); + ret = -3; + goto done; + } + + ret = 0; + +done: + free_2d_buffer(&buffer, &buffer_size); + + if (ret != 0) { + *result = NULL; + } + + return ret; +} + +/* + * Initialize SysfsCpuCache attributes. + * @param cache + */ +void init_sysfs_cpu_cache_struct(SysfsCpuCache *cache) +{ + cache->id = NULL; + cache->size = 0; + cache->name = NULL; + cache->level = 0; + cache->type = NULL; + cache->ways_of_assoc = 0; + cache->line_size = 0; +} + +/* + * Check attributes of cache structure and fill in defaults if needed. + * @param cache + * @return 0 if success, negative value otherwise + */ +short check_sysfs_cpu_cache_attributes(SysfsCpuCache *cache) +{ + short ret = -1; + + if (!cache->id) { + if (!(cache->id = strdup(""))) { + ret = -2; + goto done; + } + } + if (!cache->name) { + if (!(cache->name = strdup(""))) { + ret = -3; + goto done; + } + } + if (!cache->type) { + if (!(cache->type = strdup("Unknown"))) { + ret = -4; + goto done; + } + } + + ret = 0; + +done: + if (ret != 0) { + warn("Failed to allocate memory."); + } + + return ret; +} + +short sysfs_get_cpu_caches(SysfsCpuCache **caches, unsigned *caches_nb) +{ + short ret = -1; + unsigned i, level; + char *buf, *format_str, path[PATH_MAX]; + DIR *dir; + + *caches_nb = 0; + + /* count caches */ + char *cache_dir = SYSFS_CPU_PATH "/cpu0/cache"; + dir = opendir(cache_dir); + if (!dir) { + warn("Failed to read directory: \"%s\"; Error: %s", + cache_dir, strerror(errno)); + ret = -2; + goto done; + } + while (readdir(dir)) { + (*caches_nb)++; + } + closedir(dir); + + /* do not count . and .. */ + *caches_nb -= 2; + + /* if no cache was found */ + if (*caches_nb < 1) { + warn("No processor cache was found in sysfs."); + ret = -3; + goto done; + } + + /* allocate memory for caches */ + *caches = (SysfsCpuCache *)calloc(*caches_nb, sizeof(SysfsCpuCache)); + if (!(*caches)) { + warn("Failed to allocate memory."); + ret = -4; + goto done; + } + + for (i = 0; i < *caches_nb; i++) { + init_sysfs_cpu_cache_struct(&(*caches)[i]); + + /* cache ID and name */ + /* cache level */ + snprintf(path, PATH_MAX, SYSFS_CPU_PATH "/cpu0/cache/index%u/level", i); + if (path_get_unsigned(path, &level) != 0) { + ret = -5; + goto done; + } + (*caches)[i].level = level; + /* cache type */ + snprintf(path, PATH_MAX, SYSFS_CPU_PATH "/cpu0/cache/index%u/type", i); + if (path_get_string(path, &buf) != 0) { + ret = -6; + goto done; + } + if (strncmp(buf, "Data", 4) == 0) { + format_str = "L%ud-%u"; + } else if (strncmp(buf, "Instruction", 11) == 0) { + format_str = "L%ui-%u"; + } else { + format_str = "L%u-%u"; + } + if (asprintf(&(*caches)[i].id, format_str, level, i) < 0) { + (*caches)[i].id = NULL; + warn("Failed to allocate memory."); + ret = -7; + goto done; + } + if (asprintf(&(*caches)[i].name, "Level %u %s cache", + level, buf) < 0) { + (*caches)[i].name = NULL; + warn("Failed to allocate memory."); + ret = -8; + goto done; + } + (*caches)[i].type = buf; + buf = NULL; + + /* cache size */ + snprintf(path, PATH_MAX, SYSFS_CPU_PATH "/cpu0/cache/index%u/size", i); + if (path_get_unsigned(path, &(*caches)[i].size) != 0) { + (*caches)[i].size = 0; + } + (*caches)[i].size *= 1024; /* It's in kB, we want B */ + + /* ways of associativity */ + snprintf(path, PATH_MAX, + SYSFS_CPU_PATH "/cpu0/cache/index%u/ways_of_associativity", i); + if (path_get_unsigned(path, &(*caches)[i].ways_of_assoc) != 0) { + (*caches)[i].ways_of_assoc = 0; + } + + /* line size */ + snprintf(path, PATH_MAX, + SYSFS_CPU_PATH "/cpu0/cache/index%u/coherency_line_size", i); + if (path_get_unsigned(path, &(*caches)[i].line_size) != 0) { + (*caches)[i].line_size = 0; + } + + /* fill in default attributes if needed */ + if (check_sysfs_cpu_cache_attributes(&(*caches)[i]) != 0) { + ret = -9; + goto done; + } + } + + ret = 0; + +done: + if (buf) { + free(buf); + } + buf = NULL; + + if (ret != 0) { + sysfs_free_cpu_caches(caches, caches_nb); + } + + return ret; +} + +void sysfs_free_cpu_caches(SysfsCpuCache **caches, unsigned *caches_nb) +{ + unsigned i; + + if (*caches_nb > 0) { + for (i = 0; i < *caches_nb; i++) { + if ((*caches)[i].id) { + free((*caches)[i].id); + } + (*caches)[i].id = NULL; + if ((*caches)[i].name) { + free((*caches)[i].name); + } + (*caches)[i].name = NULL; + if ((*caches)[i].type) { + free((*caches)[i].type); + } + (*caches)[i].type = NULL; + } + free (*caches); + } + + *caches_nb = 0; + *caches = NULL; +} |