blob: 6dff80db0fa1b6b54e516cb452dd518c01a0f174 [file] [edit]
/*****************************************************************************\
* drained_tres.h - track what is drained and why
*****************************************************************************
* Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* 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.
\*****************************************************************************/
#ifndef _DRAINED_TRES_H
#define _DRAINED_TRES_H
#include <stdbool.h>
#include "src/common/bitstring.h"
#include "src/common/list.h"
#include "src/common/pack.h"
/*
* Stand-in reported for a TRES drained without a reason of its own, which
* only state predating per-TRES reasons can hold. It is a display
* placeholder, not a reason: accounting treats one carrying it as carrying
* none, and falls back to the node's reason instead of naming an event after
* it.
*/
#define DRAINED_TRES_NO_REASON "no reason"
/*
* One set of indexed TRES drained for the same reason. Devices and CPUs
* keep a list of these. A device is named by bit and by UUID.
*
* A count-only pool (a GRES type, an untyped GRES, or memory) is a
* drain_count_t instead: it has a count and a reason, and no bitmap.
*/
typedef struct {
list_t *ids; /* string-named TRES, or NULL */
bitstr_t *index_bits; /* index-named TRES, or NULL */
char *reason; /* why these TRES were drained */
} drain_group_t;
/*
* How many of a count-only TRES are drained, and why. name is the GRES type,
* or NULL for an untyped GRES and for memory. count 0 means nothing is
* drained and reason is NULL.
*/
typedef struct {
uint64_t count;
char *name;
char *reason;
} drain_count_t;
/*
* list_create() destructor for one drain_group_t.
* IN x - drain_group_t to free
*/
extern void drained_tres_group_delete(void *x);
/*
* True when the group holds no TRES of any kind and can be discarded.
* IN group - group to test
* RET true when the group is empty
*/
extern bool drained_tres_group_empty(drain_group_t *group);
/*
* Order groups by their lowest indexed TRES, then by reason.
* IN x - first drain_group_t
* IN y - second drain_group_t
* RET list sort order, negative when x sorts before y
*/
extern int drained_tres_sort_groups(void *x, void *y);
/*
* drained_tres_group_get - the group in *groups holding reason, appending one
* if this is the first TRES drained for it. Creates the list as needed.
* IN/OUT groups - group list, created when NULL
* IN reason - reason the group is keyed by
* RET the group, owned by the list
*/
extern drain_group_t *drained_tres_group_get(list_t **groups,
const char *reason);
/*
* drained_tres_group_set - record that the TRES at index inx of an index space
* cnt TRES units wide was drained for reason, moving it out of whatever
* group previously held it. A TRES drained without a reason is left
* in no group, which is how every reader already reads "no reason".
* IN/OUT groups - group list, created when NULL
* IN inx - index of the TRES to move
* IN cnt - width of the index space
* IN reason - why it is drained, or NULL for no reason
*/
extern void drained_tres_group_set(list_t **groups, int inx, int cnt,
const char *reason);
/*
* As drained_tres_group_set(), for a caller that already resolved the group.
* IN/OUT groups - group list the TRES is removed from
* IN group - group that receives the TRES
* IN inx - index of the TRES to move
* IN cnt - width of the index space
*/
extern void drained_tres_group_set_in(list_t **groups, drain_group_t *group,
int inx, int cnt);
/*
* drained_tres_group_clear - drop the TRES at index inx from whichever group
* holds it, discarding a group that is left holding nothing.
* IN/OUT groups - group list
* IN inx - index of the TRES to drop
*/
extern void drained_tres_group_clear(list_t **groups, int inx);
/*
* drained_tres_group_reason - the reason the TRES at index inx was drained, or
* NULL when it is not drained or was drained without one. The string is
* owned by the group; the caller borrows it.
* IN groups - group list, may be NULL
* IN inx - index to look up
* RET borrowed reason, or NULL
*/
extern char *drained_tres_group_reason(list_t *groups, int inx);
/*
* drained_tres_groups_resize - resize every group's bitmap to cnt, discarding
* groups that are left holding nothing. A group still holding a
* string-named TRES survives a resize that empties its bitmap. Used when
* a TRES unit count and the restored drain state that covers it disagree.
* IN/OUT groups - group list
* IN cnt - new bitmap width
*/
extern void drained_tres_groups_resize(list_t **groups, int cnt);
/*
* drained_tres_group_by_id - the group holding string-named TRES id, or NULL.
* IN groups - group list, may be NULL
* IN id - string name to look up
* RET the group, or NULL. The caller borrows it.
*/
extern drain_group_t *drained_tres_group_by_id(list_t *groups, const char *id);
/*
* drained_tres_group_id_set - as drained_tres_group_set(), for a
* string-named TRES.
* IN/OUT groups - group list, created when NULL
* IN id - string name of the TRES
* IN reason - why it is drained
*/
extern void drained_tres_group_id_set(list_t **groups, const char *id,
const char *reason);
/*
* drained_tres_group_id_clear - drained_tres_group_clear() for a
* string-named TRES.
* IN/OUT groups - group list
* IN id - string name of the TRES to drop
*/
extern void drained_tres_group_id_clear(list_t **groups, const char *id);
/*
* drained_tres_groups_clear_ids - drop every string-named TRES from every
* group, discarding the groups left holding nothing. Indexed TRES stay.
* IN/OUT groups - group list
*/
extern void drained_tres_groups_clear_ids(list_t **groups);
/*
* drained_tres_groups_pack/unpack - the group list as a count followed by each
* group in struct order: string-named TRES, index-named TRES, reason.
* Unpack leaves *groups NULL when the list is empty.
* IN groups - group list to pack, may be NULL
* IN protocol_version - version to pack for
* IN buffer - buffer to pack into
*/
extern void drained_tres_groups_pack(list_t *groups, uint16_t protocol_version,
buf_t *buffer);
/*
* Unpack a group list packed by drained_tres_groups_pack().
* OUT groups - restored list, NULL when the list is empty
* IN protocol_version - version to unpack
* IN buffer - buffer to unpack from
* RET SLURM_SUCCESS or an error
*/
extern int drained_tres_groups_unpack(list_t **groups,
uint16_t protocol_version, buf_t *buffer);
/*
* Free the strings in an embedded drain_count_t and zero its count.
* IN/OUT cnt - pool to clear
*/
extern void drained_tres_count_clear(drain_count_t *cnt);
/*
* list_create() destructor for one heap drain_count_t.
* IN x - drain_count_t to free
*/
extern void drained_tres_count_delete(void *x);
/*
* drained_tres_count_set - set an embedded pool's count. A count of 0 clears
* it. A pool that was empty records reason. replace_reason replaces the
* reason of a pool that already holds a count.
* IN/OUT cnt - pool to set
* IN count - drained count, 0 to clear the pool
* IN reason - why it is drained
* IN replace_reason - replace the reason of a pool that already has a count
*/
extern void drained_tres_count_set(drain_count_t *cnt, uint64_t count,
const char *reason, bool replace_reason);
/*
* The pool named name, or NULL. The caller borrows it.
* IN counts - pool list, may be NULL
* IN name - pool name to find
* RET the pool, or NULL
*/
extern drain_count_t *drained_tres_count_find(list_t *counts, const char *name);
/*
* drained_tres_count_list_set - as drained_tres_count_set(), for the pool
* named name in *counts. A count of 0 deletes that pool.
* IN/OUT counts - pool list, created when NULL
* IN name - pool name
* IN count - drained count, 0 to delete the pool
* IN reason - why it is drained
* IN replace_reason - replace the reason of a pool that already has a count
*/
extern void drained_tres_count_list_set(list_t **counts, const char *name,
uint64_t count, const char *reason,
bool replace_reason);
/*
* Pack one embedded pool in struct order: count, name, reason.
* IN cnt - pool to pack
* IN protocol_version - version to pack for
* IN buffer - buffer to pack into
*/
extern void drained_tres_count_pack(drain_count_t *cnt,
uint16_t protocol_version, buf_t *buffer);
/*
* Unpack one embedded pool packed by drained_tres_count_pack().
* OUT cnt - pool to fill
* IN protocol_version - version to unpack
* IN buffer - buffer to unpack from
* RET SLURM_SUCCESS or an error
*/
extern int drained_tres_count_unpack(drain_count_t *cnt,
uint16_t protocol_version, buf_t *buffer);
/*
* Pack a list of drain_count_t.
* IN counts - pool list, may be NULL
* IN protocol_version - version to pack for
* IN buffer - buffer to pack into
*/
extern void drained_tres_counts_pack(list_t *counts, uint16_t protocol_version,
buf_t *buffer);
/*
* Unpack a list packed by drained_tres_counts_pack().
* OUT counts - restored list, NULL when the list is empty
* IN protocol_version - version to unpack
* IN buffer - buffer to unpack from
* RET SLURM_SUCCESS or an error
*/
extern int drained_tres_counts_unpack(list_t **counts,
uint16_t protocol_version, buf_t *buffer);
/*
* drained_tres_max_limit - parse a MaxDrainedTres specification and return the
* limit configured for one TRES.
* IN max_drained_tres - comma separated "<tres_name>:<count>" list, may be NULL
* IN tres_name - full TRES name to look up, e.g. "cpu", "mem", "gres/gpu" or
* "gres/gpu:a100"
* IN allow_suffix - accept a "K", "M", "G", "T" or "P" multiplier on the count,
* as documented for gres/ counts. cpu and mem counts must be plain
* integers, so their caller passes false.
* RET the configured limit, or INFINITE64 (no limit) when the TRES is unlisted
* or its count is malformed
*/
extern uint64_t drained_tres_max_limit(char *max_drained_tres, char *tres_name,
bool allow_suffix);
/*
* drained_tres_validate_max - log an error for every part of a MaxDrainedTres
* specification that drained_tres_max_limit() would silently read as
* "no limit", so a typo cannot disable the limit unnoticed.
* IN max_drained_tres - the configured specification, may be NULL
* IN nodenames - NodeName= expression the specification came from, for the log
* RET true when every listed TRES and count is usable
*/
extern bool drained_tres_validate_max(char *max_drained_tres, char *nodenames);
/*
* drained_tres_over_limit - if drained exceeds limit, append an explanation
* naming the TRES to *reason (comma separated when it already holds one).
* IN/OUT reason - reason string to append to, may be NULL
* IN tres_name - TRES the limit applies to
* IN drained - amount currently drained
* IN limit - configured MaxDrainedTres limit for that TRES
* RET true if drained exceeds limit
*/
extern bool drained_tres_over_limit(char **reason, const char *tres_name,
uint64_t drained, uint64_t limit);
/*
* drained_tres_recs_to_str - render the drained-TRES records carried on a
* node_info_t as the DrainedTRES string shown by "scontrol show node".
* Indexed TRES sharing a name and a reason are reported as one entry.
* IN recs - list of drained_tres_t, may be NULL
* RET the string, or NULL when nothing is drained. Caller must xfree.
*/
extern char *drained_tres_recs_to_str(list_t *recs);
/*
* Append one drained-TRES record to recs. Every string is copied, so the caller
* keeps ownership of what it passes in; NULL fields stay NULL.
* IN/OUT recs - list of drained_tres_t to append the record to
* IN tres_name - "gres/<name>[:<type>]", "cpu" or "mem"
* IN index - index range list of the drained TRES, or NULL
* IN uuid - UUID of the drained device, or NULL
* IN count - number of drained TRES, or NO_VAL64 when index or uuid
* identify them instead
* IN reason - why the TRES were drained, may be NULL
*/
extern void drained_tres_rec_add(list_t *recs, const char *tres_name,
const char *index, const char *uuid,
uint64_t count, const char *reason);
/*
* list_create() destructor for one drained_tres_t.
* IN x - drained_tres_t to free
*/
extern void drained_tres_delete(void *x);
/*
* Pack one drained_tres_t element. Used by slurm_pack_list().
* IN in - drained_tres_t to pack
* IN protocol_version - protocol version to pack for
* IN buffer - buffer to pack into
*/
extern void drained_tres_pack(void *in, uint16_t protocol_version,
buf_t *buffer);
/*
* Unpack one drained_tres_t element. Used by slurm_unpack_list().
* OUT out - restored drained_tres_t
* IN protocol_version - protocol version to unpack
* IN buffer - buffer to unpack from
* RET SLURM_SUCCESS or an error
*/
extern int drained_tres_unpack(void **out, uint16_t protocol_version,
buf_t *buffer);
/*
* drained_tres_index_add - set every index named by a "0,2-3" style list,
* growing index to fit. Used to merge the index lists of several
* drained_tres_t records into the one range list that reports them all.
* IN/OUT index - bitmap to set the indexes in, allocated when *index is NULL
* IN str - index range list, may be NULL
*/
extern void drained_tres_index_add(bitstr_t **index, const char *str);
#endif /* !_DRAINED_TRES_H */