|  | /*****************************************************************************\ | 
|  | *  core_array.c - Handle functions dealing with core_arrays. | 
|  | ***************************************************************************** | 
|  | *  Copyright (C) SchedMD LLC. | 
|  | * | 
|  | *  This file is part of Slurm, a resource management program. | 
|  | *  For details, see <https://slurm.schedmd.com/>. | 
|  | *  Please also read the included file: DISCLAIMER. | 
|  | * | 
|  | *  Slurm is free software; you can redistribute it and/or modify it under | 
|  | *  the terms of the GNU General Public License as published by the Free | 
|  | *  Software Foundation; either version 2 of the License, or (at your option) | 
|  | *  any later version. | 
|  | * | 
|  | *  In addition, as a special exception, the copyright holders give permission | 
|  | *  to link the code of portions of this program with the OpenSSL library under | 
|  | *  certain conditions as described in each individual source file, and | 
|  | *  distribute linked combinations including the two. You must obey the GNU | 
|  | *  General Public License in all respects for all of the code used other than | 
|  | *  OpenSSL. If you modify file(s) with this exception, you may extend this | 
|  | *  exception to your version of the file(s), but you are not obligated to do | 
|  | *  so. If you do not wish to do so, delete this exception statement from your | 
|  | *  version.  If you delete this exception statement from all source files in | 
|  | *  the program, then also delete it here. | 
|  | * | 
|  | *  Slurm 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 General Public License for more | 
|  | *  details. | 
|  | * | 
|  | *  You should have received a copy of the GNU General Public License along | 
|  | *  with Slurm; if not, write to the Free Software Foundation, Inc., | 
|  | *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA. | 
|  | \*****************************************************************************/ | 
|  |  | 
|  | #include "src/common/core_array.h" | 
|  |  | 
|  | #include "src/common/node_conf.h" | 
|  | #include "src/common/xmalloc.h" | 
|  | #include "src/common/xstring.h" | 
|  |  | 
|  | /* | 
|  | * Build an empty array of bitmaps, one per node | 
|  | * Use free_core_array() to release returned memory | 
|  | */ | 
|  | extern bitstr_t **build_core_array(void) | 
|  | { | 
|  | xassert(node_record_count); | 
|  |  | 
|  | return xcalloc(node_record_count, sizeof(bitstr_t *)); | 
|  | } | 
|  |  | 
|  | /* Clear all elements of an array of bitmaps, one per node */ | 
|  | extern void clear_core_array(bitstr_t **core_array) | 
|  | { | 
|  | int n; | 
|  |  | 
|  | if (!core_array) | 
|  | return; | 
|  | for (n = 0; n < node_record_count; n++) { | 
|  | if (core_array[n]) | 
|  | bit_clear_all(core_array[n]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Copy an array of bitmaps, one per node | 
|  | * Use free_core_array() to release returned memory | 
|  | */ | 
|  | extern bitstr_t **copy_core_array(bitstr_t **core_array) | 
|  | { | 
|  | bitstr_t **core_array2 = NULL; | 
|  | int n; | 
|  |  | 
|  | if (core_array) { | 
|  | core_array2 = xmalloc(sizeof(bitstr_t *) * node_record_count); | 
|  | for (n = 0; n < node_record_count; n++) { | 
|  | if (core_array[n]) | 
|  | core_array2[n] = bit_copy(core_array[n]); | 
|  | } | 
|  | } | 
|  | return core_array2; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Return count of set bits in array of bitmaps, one per node | 
|  | */ | 
|  | extern int count_core_array_set(bitstr_t **core_array) | 
|  | { | 
|  | int count = 0, n; | 
|  |  | 
|  | if (!core_array) | 
|  | return count; | 
|  | for (n = 0; n < node_record_count; n++) { | 
|  | if (core_array[n]) | 
|  | count += bit_set_count(core_array[n]); | 
|  | } | 
|  | return count; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set core_array to ~core_array | 
|  | */ | 
|  | extern void core_array_not(bitstr_t **core_array) | 
|  | { | 
|  | if (!core_array) | 
|  | return; | 
|  | for (int n = 0; n < node_record_count; n++) { | 
|  | if (core_array[n]) | 
|  | bit_not(core_array[n]); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set row_bitmap1 to core_array1 & core_array2 | 
|  | */ | 
|  | extern void core_array_and(bitstr_t **core_array1, bitstr_t **core_array2) | 
|  | { | 
|  | int n, s1, s2; | 
|  | for (n = 0; n < node_record_count; n++) { | 
|  | if (core_array1[n] && core_array2[n]) { | 
|  | s1 = bit_size(core_array1[n]); | 
|  | s2 = bit_size(core_array2[n]); | 
|  | if (s1 > s2) | 
|  | bit_realloc(core_array2[n], s1); | 
|  | else if (s1 < s2) | 
|  | bit_realloc(core_array1[n], s2); | 
|  | bit_and(core_array1[n], core_array2[n]); | 
|  | } else | 
|  | FREE_NULL_BITMAP(core_array1[n]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set row_bitmap1 to row_bitmap1 & !row_bitmap2 | 
|  | * In other words, any bit set in row_bitmap2 is cleared from row_bitmap1 | 
|  | */ | 
|  | extern void core_array_and_not(bitstr_t **core_array1, bitstr_t **core_array2) | 
|  | { | 
|  | int n, s1, s2; | 
|  | for (n = 0; n < node_record_count; n++) { | 
|  | if (core_array1[n] && core_array2[n]) { | 
|  | s1 = bit_size(core_array1[n]); | 
|  | s2 = bit_size(core_array2[n]); | 
|  | if (s1 > s2) | 
|  | bit_realloc(core_array2[n], s1); | 
|  | else if (s1 < s2) | 
|  | bit_realloc(core_array1[n], s2); | 
|  | bit_and_not(core_array1[n], core_array2[n]); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set row_bitmap1 to core_array1 | core_array2 | 
|  | */ | 
|  | extern void core_array_or(bitstr_t **core_array1, bitstr_t **core_array2) | 
|  | { | 
|  | int n, s1, s2; | 
|  | for (n = 0; n < node_record_count; n++) { | 
|  | if (core_array1[n] && core_array2[n]) { | 
|  | s1 = bit_size(core_array1[n]); | 
|  | s2 = bit_size(core_array2[n]); | 
|  | if (s1 > s2) | 
|  | bit_realloc(core_array2[n], s1); | 
|  | else if (s1 < s2) | 
|  | bit_realloc(core_array1[n], s2); | 
|  | bit_or(core_array1[n], core_array2[n]); | 
|  | } else if (core_array2[n]) | 
|  | core_array1[n] = bit_copy(core_array2[n]); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Free an array of bitmaps, one per node */ | 
|  | extern void free_core_array(bitstr_t ***core_array) | 
|  | { | 
|  | bitstr_t **core_array2 = *core_array; | 
|  | int n; | 
|  |  | 
|  | if (core_array2) { | 
|  | for (n = 0; n < node_record_count; n++) | 
|  | FREE_NULL_BITMAP(core_array2[n]); | 
|  | xfree(core_array2); | 
|  | *core_array = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Enable detailed logging of cr_dist() node and per-node core bitmaps */ | 
|  | extern void core_array_log(char *loc, bitstr_t *node_map, bitstr_t **core_map) | 
|  | { | 
|  | char tmp[100]; | 
|  |  | 
|  | if (!(slurm_conf.debug_flags & DEBUG_FLAG_SELECT_TYPE)) | 
|  | return; | 
|  |  | 
|  | verbose("%s", loc); | 
|  |  | 
|  | if (node_map) { | 
|  | char *node_list = bitmap2node_name(node_map); | 
|  | verbose("node_list:%s", node_list); | 
|  | xfree(node_list); | 
|  | } | 
|  |  | 
|  | if (core_map) { | 
|  | char *core_list = NULL; | 
|  | char *sep = ""; | 
|  |  | 
|  | for (int i = 0; i < node_record_count; i++) { | 
|  | if (!core_map[i] || (bit_ffs(core_map[i]) == -1)) | 
|  | continue; | 
|  | bit_fmt(tmp, sizeof(tmp), core_map[i]); | 
|  | xstrfmtcat(core_list, "%snode[%d]:%s", sep, i, tmp); | 
|  | sep = ","; | 
|  | } | 
|  | verbose("core_list:%s", core_list); | 
|  | xfree(core_list); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Translate per-node core bitmap array to system-wide core bitmap */ | 
|  | extern bitstr_t *core_array_to_bitmap(bitstr_t **core_array) | 
|  | { | 
|  | bitstr_t *core_bitmap = NULL; | 
|  | int i; | 
|  | int c, core_offset; | 
|  | #if _DEBUG | 
|  | char tmp[128]; | 
|  | #endif | 
|  |  | 
|  | if (!core_array) | 
|  | return core_bitmap; | 
|  |  | 
|  | #if _DEBUG | 
|  | for (i = 0; i < node_record_count; i++) { | 
|  | if (!core_array[i]) | 
|  | continue; | 
|  | bit_fmt(tmp, sizeof(tmp), core_array[i]); | 
|  | error("OUT core bitmap[%d] %s", | 
|  | i, tmp); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | core_bitmap = bit_alloc(cr_get_coremap_offset(node_record_count)); | 
|  | for (i = 0; i < node_record_count; i++) { | 
|  | if (!core_array[i]) | 
|  | continue; | 
|  | core_offset = cr_get_coremap_offset(i); | 
|  | for (c = 0; c < node_record_table_ptr[i]->tot_cores; c++) { | 
|  | if (bit_test(core_array[i], c)) | 
|  | bit_set(core_bitmap, core_offset + c); | 
|  | } | 
|  | } | 
|  |  | 
|  | #if _DEBUG | 
|  | bit_fmt(tmp, sizeof(tmp), core_bitmap); | 
|  | error("IN core bitmap %s", tmp); | 
|  | #endif | 
|  |  | 
|  | return core_bitmap; | 
|  | } | 
|  |  | 
|  | /* Translate system-wide core bitmap to per-node core bitmap array */ | 
|  | extern bitstr_t **core_bitmap_to_array(bitstr_t *core_bitmap) | 
|  | { | 
|  | bitstr_t **core_array = NULL; | 
|  | int i, i_first, i_last, j, c; | 
|  | int node_inx = 0, core_offset; | 
|  | char tmp[128]; | 
|  |  | 
|  | if (!core_bitmap) | 
|  | return core_array; | 
|  |  | 
|  | #if _DEBUG | 
|  | bit_fmt(tmp, sizeof(tmp), core_bitmap); | 
|  | error("IN core bitmap %s", tmp); | 
|  | #endif | 
|  |  | 
|  | i_first = bit_ffs(core_bitmap); | 
|  | if (i_first == -1) | 
|  | return core_array; | 
|  |  | 
|  | core_array = build_core_array(); | 
|  |  | 
|  | i_last = bit_fls(core_bitmap); | 
|  |  | 
|  | for (i = i_first; i <= i_last; i++) { | 
|  | if (!bit_test(core_bitmap, i)) | 
|  | continue; | 
|  | /* | 
|  | * next_node will jump over any hole in the node list created by | 
|  | * dynamic node removal | 
|  | */ | 
|  | for (j = node_inx; next_node(&j); j++) { | 
|  | if (i < cr_get_coremap_offset(j+1)) { | 
|  | node_inx = j; | 
|  | i = cr_get_coremap_offset(j+1) - 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (j >= node_record_count) { | 
|  | bit_fmt(tmp, sizeof(tmp), core_bitmap); | 
|  | error("error translating core bitmap %s", | 
|  | tmp); | 
|  | break; | 
|  | } | 
|  | /* | 
|  | * If node_inx is pointing to a hole this means that | 
|  | * node_inx == last_node_index + 1, and the rest of | 
|  | * the list up to node_record_count (MaxNodeCount) is empty. | 
|  | * | 
|  | * next_node() would have returned NULL when | 
|  | * node_inx > last_node_index and we will end up here. | 
|  | */ | 
|  | if (!node_record_table_ptr[node_inx]) | 
|  | break; | 
|  |  | 
|  | /* Copy all core bitmaps for this node here */ | 
|  | core_array[node_inx] = | 
|  | bit_alloc(node_record_table_ptr[node_inx]->tot_cores); | 
|  | core_offset = cr_get_coremap_offset(node_inx); | 
|  | for (c = 0; c < node_record_table_ptr[node_inx]->tot_cores; | 
|  | c++) { | 
|  | if (bit_test(core_bitmap, core_offset + c)) | 
|  | bit_set(core_array[node_inx], c); | 
|  | } | 
|  | node_inx++; | 
|  | } | 
|  |  | 
|  | #if _DEBUG | 
|  | for (i = 0; i < node_record_count; i++) { | 
|  | if (!core_array[i]) | 
|  | continue; | 
|  | bit_fmt(tmp, sizeof(tmp), core_array[i]); | 
|  | error("OUT core bitmap[%d] %s", | 
|  | i, tmp); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return core_array; | 
|  | } |