diff options
author | Eugene V. Lyubimkin <jackyf.devel@gmail.com> | 2008-11-16 20:36:18 +0200 |
---|---|---|
committer | Daniel Lange <DLange@git.local> | 2016-04-11 13:00:23 +0200 |
commit | bcb965d78ae0b4599fe77a2d641b3ff035658fc9 (patch) | |
tree | 59066e7fa5473b02eefaea37ac015cfaea7cd7c6 /plpa-1.1/src/plpa_map.c | |
parent | 2eabf3432b05b93ce4de9af283ae549d0f7c18c8 (diff) | |
parent | c74c38760df69bb87e93dff18cf91464e5d02f37 (diff) | |
download | debian_htop-bcb965d78ae0b4599fe77a2d641b3ff035658fc9.tar.gz debian_htop-bcb965d78ae0b4599fe77a2d641b3ff035658fc9.tar.bz2 debian_htop-bcb965d78ae0b4599fe77a2d641b3ff035658fc9.zip |
Imported Debian patch 0.8.1-1debian/0.8.1-1
Diffstat (limited to 'plpa-1.1/src/plpa_map.c')
-rw-r--r-- | plpa-1.1/src/plpa_map.c | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/plpa-1.1/src/plpa_map.c b/plpa-1.1/src/plpa_map.c new file mode 100644 index 0000000..84b1d0e --- /dev/null +++ b/plpa-1.1/src/plpa_map.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * Portions of this file originally contributed by Advanced Micro + * Devices, Inc. See notice below. + */ +/* ============================================================ + License Agreement + + Copyright (c) 2006, 2007 Advanced Micro Devices, Inc. + All rights reserved. + + Redistribution and use in any form of this material and any product + thereof including software in source or binary forms, along with any + related documentation, with or without modification ("this material"), + is permitted provided that the following conditions are met: + + + Redistributions of source code of any software must retain the above + copyright notice and all terms of this license as part of the code. + + + Redistributions in binary form of any software must reproduce the + above copyright notice and all terms of this license in any related + documentation and/or other materials. + + + Neither the names nor trademarks of Advanced Micro Devices, Inc. or + any copyright holders or contributors may be used to endorse or + promote products derived from this material without specific prior + written permission. + + + Notice about U.S. Government restricted rights: This material is + provided with "RESTRICTED RIGHTS." Use, duplication or disclosure by + the U.S. Government is subject to the full extent of restrictions set + forth in FAR52.227 and DFARS252.227 et seq., or any successor or + applicable regulations. Use of this material by the U.S. Government + constitutes acknowledgment of the proprietary rights of Advanced Micro + Devices, Inc. + and any copyright holders and contributors. + + + In no event shall anyone redistributing or accessing or using this + material commence or participate in any arbitration or legal action + relating to this material against Advanced Micro Devices, Inc. or any + copyright holders or contributors. The foregoing shall survive any + expiration or termination of this license or any agreement or access + or use related to this material. + + + ANY BREACH OF ANY TERM OF THIS LICENSE SHALL RESULT IN THE IMMEDIATE + REVOCATION OF ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL. + + THIS MATERIAL IS PROVIDED BY ADVANCED MICRO DEVICES, INC. AND ANY + COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" IN ITS CURRENT CONDITION + AND WITHOUT ANY REPRESENTATIONS, GUARANTEE, OR WARRANTY OF ANY KIND OR + IN ANY WAY RELATED TO SUPPORT, INDEMNITY, ERROR FREE OR UNINTERRUPTED + OPERATION, OR THAT IT IS FREE FROM DEFECTS OR VIRUSES. ALL + OBLIGATIONS ARE HEREBY DISCLAIMED - WHETHER EXPRESS, IMPLIED, OR + STATUTORY - INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF + TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, + COMPLETENESS, OPERABILITY, QUALITY OF SERVICE, OR NON-INFRINGEMENT. IN + NO EVENT SHALL ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, PUNITIVE, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, REVENUE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED OR BASED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED + TO THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + THE ENTIRE AND AGGREGATE LIABILITY OF ADVANCED MICRO DEVICES, INC. AND + ANY COPYRIGHT HOLDERS AND CONTRIBUTORS SHALL NOT EXCEED TEN DOLLARS + (US $10.00). ANYONE REDISTRIBUTING OR ACCESSING OR USING THIS MATERIAL + ACCEPTS THIS ALLOCATION OF RISK AND AGREES TO RELEASE ADVANCED MICRO + DEVICES, INC. AND ANY COPYRIGHT HOLDERS AND CONTRIBUTORS FROM ANY AND + ALL LIABILITIES, OBLIGATIONS, CLAIMS, OR DEMANDS IN EXCESS OF TEN + DOLLARS (US $10.00). THE FOREGOING ARE ESSENTIAL TERMS OF THIS LICENSE + AND, IF ANY OF THESE TERMS ARE CONSTRUED AS UNENFORCEABLE, FAIL IN + ESSENTIAL PURPOSE, OR BECOME VOID OR DETRIMENTAL TO ADVANCED MICRO + DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR CONTRIBUTORS FOR ANY REASON, + THEN ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL SHALL + TERMINATE IMMEDIATELY. MOREOVER, THE FOREGOING SHALL SURVIVE ANY + EXPIRATION OR TERMINATION OF THIS LICENSE OR ANY AGREEMENT OR ACCESS + OR USE RELATED TO THIS MATERIAL. + + NOTICE IS HEREBY PROVIDED, AND BY REDISTRIBUTING OR ACCESSING OR USING + THIS MATERIAL SUCH NOTICE IS ACKNOWLEDGED, THAT THIS MATERIAL MAY BE + SUBJECT TO RESTRICTIONS UNDER THE LAWS AND REGULATIONS OF THE UNITED + STATES OR OTHER COUNTRIES, WHICH INCLUDE BUT ARE NOT LIMITED TO, U.S. + EXPORT CONTROL LAWS SUCH AS THE EXPORT ADMINISTRATION REGULATIONS AND + NATIONAL SECURITY CONTROLS AS DEFINED THEREUNDER, AS WELL AS STATE + DEPARTMENT CONTROLS UNDER THE U.S. MUNITIONS LIST. THIS MATERIAL MAY + NOT BE USED, RELEASED, TRANSFERRED, IMPORTED, EXPORTED AND/OR RE- + EXPORTED IN ANY MANNER PROHIBITED UNDER ANY APPLICABLE LAWS, INCLUDING + U.S. EXPORT CONTROL LAWS REGARDING SPECIFICALLY DESIGNATED PERSONS, + COUNTRIES AND NATIONALS OF COUNTRIES SUBJECT TO NATIONAL SECURITY + CONTROLS. + MOREOVER, + THE FOREGOING SHALL SURVIVE ANY EXPIRATION OR TERMINATION OF ANY + LICENSE OR AGREEMENT OR ACCESS OR USE RELATED TO THIS MATERIAL. + + This license forms the entire agreement regarding the subject matter + hereof and supersedes all proposals and prior discussions and writings + between the parties with respect thereto. This license does not affect + any ownership, rights, title, or interest in, or relating to, this + material. No terms of this license can be modified or waived, and no + breach of this license can be excused, unless done so in a writing + signed by all affected parties. Each term of this license is + separately enforceable. If any term of this license is determined to + be or becomes unenforceable or illegal, such term shall be reformed to + the minimum extent necessary in order for this license to remain in + effect in accordance with its terms as modified by such reformation. + This license shall be governed by and construed in accordance with the + laws of the State of Texas without regard to rules on conflicts of law + of any state or jurisdiction or the United Nations Convention on the + International Sale of Goods. All disputes arising out of this license + shall be subject to the jurisdiction of the federal and state courts + in Austin, Texas, and all defenses are hereby waived concerning + personal jurisdiction and venue of these courts. + ============================================================ */ + +#include "plpa_config.h" +#include "plpa.h" +#include "plpa_internal.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <limits.h> +#include <errno.h> +#include <stdlib.h> + +typedef struct tuple_t_ { + int processor_id, socket, core; +} tuple_t; + +static int supported = 0; +static int num_processors = -1; +static int max_processor_num = -1; +static int num_sockets = -1; +static int max_socket_id = -1; +static int *max_core_id = NULL; +static int *num_cores = NULL; +static int max_core_id_overall = -1; +static tuple_t *map_processor_id_to_tuple = NULL; +static tuple_t ***map_tuple_to_processor_id = NULL; + +static void clear_cache(void) +{ + if (NULL != max_core_id) { + free(max_core_id); + max_core_id = NULL; + } + if (NULL != num_cores) { + free(num_cores); + num_cores = NULL; + } + if (NULL != map_processor_id_to_tuple) { + free(map_processor_id_to_tuple); + map_processor_id_to_tuple = NULL; + } + if (NULL != map_tuple_to_processor_id) { + if (NULL != map_tuple_to_processor_id[0]) { + free(map_tuple_to_processor_id[0]); + map_tuple_to_processor_id = NULL; + } + free(map_tuple_to_processor_id); + map_tuple_to_processor_id = NULL; + } + + num_processors = max_processor_num = -1; + num_sockets = max_socket_id = -1; + max_core_id_overall = -1; +} + +static void load_cache(const char *sysfs_mount) +{ + int i, j, k, invalid_entry, fd; + char path[PATH_MAX], buf[8]; + PLPA_NAME(cpu_set_t) *cores_on_sockets; + int found; + + /* Check for the parent directory */ + sprintf(path, "%s/devices/system/cpu", sysfs_mount); + if (access(path, R_OK|X_OK)) { + return; + } + + /* Go through and find the max processor ID */ + for (num_processors = max_processor_num = i = 0; + i < PLPA_BITMASK_CPU_MAX; ++i) { + sprintf(path, "%s/devices/system/cpu/cpu%d", sysfs_mount, i); + if (0 != access(path, (R_OK | X_OK))) { + max_processor_num = i - 1; + break; + } + ++num_processors; + } + + /* If we found no processors, then we have no topology info */ + if (0 == num_processors) { + clear_cache(); + return; + } + + /* Malloc space for the first map (processor ID -> tuple). + Include enough space for one invalid entry. */ + map_processor_id_to_tuple = malloc(sizeof(tuple_t) * + (max_processor_num + 2)); + if (NULL == map_processor_id_to_tuple) { + return; + } + for (i = 0; i <= max_processor_num; ++i) { + map_processor_id_to_tuple[i].processor_id = i; + map_processor_id_to_tuple[i].socket = -1; + map_processor_id_to_tuple[i].core = -1; + } + /* Set the invalid entry */ + invalid_entry = i; + map_processor_id_to_tuple[invalid_entry].processor_id = -1; + map_processor_id_to_tuple[invalid_entry].socket = -1; + map_processor_id_to_tuple[invalid_entry].core = -1; + + /* Build a cached map of (socket,core) tuples */ + for (found = 0, i = 0; i <= max_processor_num; ++i) { + sprintf(path, "%s/devices/system/cpu/cpu%d/topology/core_id", + sysfs_mount, i); + fd = open(path, O_RDONLY); + if ( fd < 0 ) { + continue; + } + if ( read(fd, buf, 7) <= 0 ) { + continue; + } + sscanf(buf, "%d", &(map_processor_id_to_tuple[i].core)); + close(fd); + + sprintf(path, + "%s/devices/system/cpu/cpu%d/topology/physical_package_id", + sysfs_mount, i); + fd = open(path, O_RDONLY); + if ( fd < 0 ) { + continue; + } + if ( read(fd, buf, 7) <= 0 ) { + continue; + } + sscanf(buf, "%d", &(map_processor_id_to_tuple[i].socket)); + close(fd); + found = 1; + + /* Keep a running tab on the max socket number */ + if (map_processor_id_to_tuple[i].socket > max_socket_id) { + max_socket_id = map_processor_id_to_tuple[i].socket; + } + } + + /* Now that we know the max number of sockets, allocate some + arrays */ + max_core_id = malloc(sizeof(int) * (max_socket_id + 1)); + if (NULL == max_core_id) { + clear_cache(); + return; + } + num_cores = malloc(sizeof(int) * (max_socket_id + 1)); + if (NULL == num_cores) { + clear_cache(); + return; + } + for (i = 0; i <= max_socket_id; ++i) { + num_cores[i] = -1; + max_core_id[i] = -1; + } + + /* Find the max core number on each socket */ + for (i = 0; i <= max_processor_num; ++i) { + if (map_processor_id_to_tuple[i].core > + max_core_id[map_processor_id_to_tuple[i].socket]) { + max_core_id[map_processor_id_to_tuple[i].socket] = + map_processor_id_to_tuple[i].core; + } + if (max_core_id[map_processor_id_to_tuple[i].socket] > + max_core_id_overall) { + max_core_id_overall = + max_core_id[map_processor_id_to_tuple[i].socket]; + } + } + + /* If we didn't find any core_id/physical_package_id's, then we + don't have the topology info */ + if (!found) { + clear_cache(); + return; + } + + /* Go through and count the number of unique sockets found. It + may not be the same as max_socket_id because there may be + "holes" -- e.g., sockets 0 and 3 are used, but sockets 1 and 2 + are empty. */ + for (j = i = 0; i <= max_socket_id; ++i) { + if (max_core_id[i] >= 0) { + ++j; + } + } + if (j > 0) { + num_sockets = j; + } + + /* Count how many cores are available on each socket. This may + not be the same as max_core_id[socket_num] if there are + "holes". I don't know if holes can happen (i.e., if specific + cores can be taken offline), but what the heck... */ + cores_on_sockets = malloc(sizeof(PLPA_NAME(cpu_set_t)) * + (max_socket_id + 1)); + if (NULL == cores_on_sockets) { + clear_cache(); + return; + } + for (i = 0; i <= max_socket_id; ++i) { + PLPA_CPU_ZERO(&(cores_on_sockets[i])); + } + for (i = 0; i <= max_processor_num; ++i) { + if (map_processor_id_to_tuple[i].socket >= 0) { + PLPA_CPU_SET(map_processor_id_to_tuple[i].core, + &(cores_on_sockets[map_processor_id_to_tuple[i].socket])); + } + } + for (i = 0; i <= max_socket_id; ++i) { + int count = 0; + for (j = 0; j < PLPA_BITMASK_CPU_MAX; ++j) { + if (PLPA_CPU_ISSET(j, &(cores_on_sockets[i]))) { + ++count; + } + } + if (count > 0) { + num_cores[i] = count; + } + } + + /* Now go through and build the map in the other direction: + (socket,core) => processor_id. This map simply points to + entries in the other map (i.e., it's by reference instead of by + value). */ + map_tuple_to_processor_id = malloc(sizeof(tuple_t **) * + (max_socket_id + 1)); + if (NULL == map_tuple_to_processor_id) { + clear_cache(); + return; + } + map_tuple_to_processor_id[0] = malloc(sizeof(tuple_t *) * + ((max_socket_id + 1) * + (max_core_id_overall + 1))); + if (NULL == map_tuple_to_processor_id[0]) { + clear_cache(); + return; + } + /* Set pointers for 2nd dimension */ + for (i = 1; i <= max_socket_id; ++i) { + map_tuple_to_processor_id[i] = + map_tuple_to_processor_id[i - 1] + max_core_id_overall + 1; + } + /* Compute map */ + for (i = 0; i <= max_socket_id; ++i) { + for (j = 0; j <= max_core_id_overall; ++j) { + /* Default to the invalid entry in the other map, meaning + that this (socket,core) combination doesn't exist + (e.g., the core number does not exist in this socket, + although it does exist in other sockets). */ + map_tuple_to_processor_id[i][j] = + &map_processor_id_to_tuple[invalid_entry]; + + /* See if this (socket,core) tuple exists in the other + map. If so, set this entry to point to it (overriding + the invalid entry default). */ + for (k = 0; k <= max_processor_num; ++k) { + if (map_processor_id_to_tuple[k].socket == i && + map_processor_id_to_tuple[k].core == j) { + map_tuple_to_processor_id[i][j] = + &map_processor_id_to_tuple[k]; +#if defined(PLPA_DEBUG) && PLPA_DEBUG + printf("Creating map: (socket %d, core %d) -> ID %d\n", + i, j, k); +#endif + break; + } + } + } + } + + supported = 1; +} + +/* Internal function to setup the mapping data. Guaranteed to be + calling during PLPA_NAME(init), so we don't have to worry about + thread safety here. */ +int PLPA_NAME(map_init)(void) +{ + const char *sysfs_mount = "/sys"; + char *temp; + + temp = getenv("PLPA_SYSFS_MOUNT"); + if (temp) { + sysfs_mount = temp; + } + + load_cache(sysfs_mount); + return 0; +} + +/* Internal function to cleanup allocated memory. Only called by one + thread (during PLPA_NAME(finalize), so don't need to worry about + thread safety here. */ +void PLPA_NAME(map_finalize)(void) +{ + clear_cache(); +} + +/* Return whether this kernel supports topology information or not */ +int PLPA_NAME(have_topology_information)(int *supported_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == supported_arg) { + return EINVAL; + } + + *supported_arg = supported; + return 0; +} + +int PLPA_NAME(map_to_processor_id)(int socket, int core, int *processor_id) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == processor_id) { + return EINVAL; + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for some invalid entries */ + if (socket < 0 || socket > max_socket_id || + core < 0 || core > max_core_id_overall) { + return ENOENT; + } + /* If the mapping returns -1, then this is a non-existent + socket/core combo (even though they fall within the max socket + / max core overall values) */ + ret = map_tuple_to_processor_id[socket][core]->processor_id; + if (-1 == ret) { + return ENOENT; + } + + /* Ok, all should be good -- return the mapping */ + *processor_id = ret; + return 0; +} + +int PLPA_NAME(map_to_socket_core)(int processor_id, int *socket, int *core) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == socket || NULL == core) { + return EINVAL; + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for some invalid entries */ + if (processor_id < 0 || processor_id > max_processor_num) { + return ENOENT; + } + ret = map_processor_id_to_tuple[processor_id].socket; + if (-1 == ret) { + return ENOENT; + } + + /* Ok, all should be good -- return the mapping */ + *socket = ret; + *core = map_processor_id_to_tuple[processor_id].core; + return 0; +} + +int PLPA_NAME(get_processor_info)(int *num_processors_arg, + int *max_processor_num_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == max_processor_num_arg || NULL == num_processors_arg) { + return EINVAL; + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* All done */ + *num_processors_arg = num_processors; + *max_processor_num_arg = max_processor_num; + return 0; +} + +/* Return the max socket number */ +int PLPA_NAME(get_socket_info)(int *num_sockets_arg, int *max_socket_id_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == max_socket_id_arg || NULL == num_sockets_arg) { + return EINVAL; + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* All done */ + *num_sockets_arg = num_sockets; + *max_socket_id_arg = max_socket_id; + return 0; +} + +/* Return the number of cores in a socket and the max core ID number */ +int PLPA_NAME(get_core_info)(int socket, int *num_cores_arg, + int *max_core_id_arg) +{ + int ret; + + /* Initialize if not already done so */ + if (!PLPA_NAME(initialized)) { + if (0 != (ret = PLPA_NAME(init)())) { + return ret; + } + } + + /* Check for bozo arguments */ + if (NULL == max_core_id_arg || NULL == num_cores_arg) { + return EINVAL; + } + + /* If this system doesn't support mapping, sorry Charlie */ + if (!supported) { + return ENOSYS; + } + + /* Check for some invalid entries */ + if (socket < 0 || socket > max_socket_id || -1 == max_core_id[socket]) { + return ENOENT; + } + ret = num_cores[socket]; + if (-1 == ret) { + return ENOENT; + } + + /* All done */ + *num_cores_arg = ret; + *max_core_id_arg = max_core_id[socket]; + return 0; +} |