Files
s390-tools/zconf/chp/chpstat/key.c
Peter Oberparleiter cb77faeae7 chpstat: add tool to display channel-path statistics
Add a new tool named chpstat that can be used to view channel-path
statistics such as utilization and I/O throughput, and to query and
control the status of the channel-path statistics function.

Note: Channel-path statistics are only available on systems running in
      an LPAR or DPM partition.

When run without further options, data for all channel-paths is
displayed repeatedly with a 5 second delay in table format.

Example output:

      CHANNEL-PATH       UTILIZATION(%)   READ(B/s)  WRITE(B/s)
  ID TYP CMG SHR SPEED  PART TOTAL  BUS  PART TOTAL  PART TOTAL
  1d  25   2   1     -  7.16  7.50 7.50  129M  129M  0.00  161K
  21  1b   2   1   32G  0.00  0.00 0.00  0.00  0.00  0.00  0.00
  34  1b   2   1   32G  0.00  0.00 0.00  0.00  0.00  0.00  0.00
  61  25   2   1     -  0.00  0.01 0.00  0.00 2.00K  0.00  307K
  63  25   2   1     -  0.00  0.01 0.00  0.00  0.00  0.00  381K
  bd  11   2   1   10G     -     -    - 529.8 532.1 616.3 616.3

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:27 +02:00

228 lines
4.6 KiB
C

/*
* Registry for supported data keys
*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "key.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "cmg.h"
#include "lib/util_libc.h"
#include "lib/zt_common.h"
static struct key_t *keys;
static unsigned int num_keys;
static struct key_t **selected_keys;
static unsigned int num_selected_keys;
#define GET_CMG_MASK(c) ((u32)(1 << (c)))
#define CMG_ALL_MASK ((u32)0xffffffff)
#define IS_CMG_MASK(c, n) ((c) & GET_CMG_MASK(n))
static char *mask_to_cmg_str(u32 mask)
{
char *str;
int i;
if (mask == CMG_ALL_MASK)
return util_strdup("all");
str = util_strdup("");
for (i = 1; i <= 32; i++) {
if (!IS_CMG_MASK(mask, i))
continue;
if (*str)
util_concatf(&str, ",");
util_concatf(&str, "%d", i);
}
return str;
}
const char *key_group_to_str(enum key_group_t group)
{
switch (group) {
case KEY_GRP_META:
return "meta";
case KEY_GRP_ITERATION:
return "iteration";
case KEY_GRP_CHP:
return "channel_path";
case KEY_GRP_CHARS:
return "characteristics";
case KEY_GRP_UTIL:
return "utilization";
case KEY_GRP_METRICS:
return "metrics";
default:
return "";
}
}
static void add_key(const char *name, enum key_group_t group, bool found,
u32 cmg_mask)
{
struct key_t *key;
key = key_get_by_name(name);
if (!key) {
util_expand_array(&keys, &num_keys);
key = &keys[num_keys - 1];
key->name = util_strdup(name);
key->group = group;
}
key->found |= found;
key->cmg_mask |= cmg_mask;
free(key->cmg_str);
key->cmg_str = mask_to_cmg_str(key->cmg_mask);
}
static void add_generic_keys(void)
{
add_key(KEY_META_API_LEVEL, KEY_GRP_META, true, CMG_ALL_MASK);
add_key(KEY_META_VERSION, KEY_GRP_META, true, CMG_ALL_MASK);
add_key(KEY_META_HOST, KEY_GRP_META, true, CMG_ALL_MASK);
add_key(KEY_META_TIME, KEY_GRP_META, true, CMG_ALL_MASK);
add_key(KEY_META_TIME_EPOCH, KEY_GRP_META, true, CMG_ALL_MASK);
add_key(KEY_ITERATION, KEY_GRP_ITERATION, true, CMG_ALL_MASK);
add_key(KEY_TIME, KEY_GRP_ITERATION, true, CMG_ALL_MASK);
add_key(KEY_TIME_EPOCH, KEY_GRP_ITERATION, true, CMG_ALL_MASK);
add_key(KEY_CHPID, KEY_GRP_CHP, true, CMG_ALL_MASK);
add_key(KEY_TYPE, KEY_GRP_CHP, true, CMG_ALL_MASK);
add_key(KEY_CMG, KEY_GRP_CHP, true, CMG_ALL_MASK);
add_key(KEY_SHARED, KEY_GRP_CHP, true, CMG_ALL_MASK);
add_key(KEY_SPEED, KEY_GRP_CHP, true, CMG_ALL_MASK);
}
static void add_cmg_keys(bool all)
{
enum key_group_t groups[] = { KEY_GRP_UTIL, KEY_GRP_CHARS,
KEY_GRP_METRICS };
unsigned int i, j;
struct cmg_t *cmg;
char **cmg_keys;
cmg_for_each(cmg) {
for (i = 0; i < ARRAY_SIZE(groups); i++) {
cmg_keys = cmg_get_keys(cmg, groups[i]);
for (j = 0; cmg_keys[j]; j++) {
add_key(cmg_keys[j], groups[i],
cmg->found || all,
GET_CMG_MASK(cmg->cmg));
}
cmg_free_keys(cmg_keys);
}
}
}
void key_init(bool all)
{
add_generic_keys();
add_cmg_keys(all);
}
void key_exit(void)
{
unsigned int i;
for (i = 0; i < num_keys; i++) {
free(keys[i].name);
free(keys[i].cmg_str);
}
free(keys);
free(selected_keys);
}
static int cmp_keys(const void *a, const void *b)
{
const struct key_t * const *a_key = a;
const struct key_t * const *b_key = b;
return strcmp((*a_key)->name, (*b_key)->name);
}
void key_sort_selected(void)
{
qsort(selected_keys, num_selected_keys, sizeof(struct key_t *),
cmp_keys);
}
struct key_t *key_get_by_index(unsigned int i, bool selected)
{
if (selected)
return i < num_selected_keys ? selected_keys[i] : NULL;
return i < num_keys ? &keys[i] : NULL;
}
struct key_t *key_get_by_name(const char *name)
{
struct key_t *key;
key_for_each(key) {
if (strcmp(key->name, name) == 0)
return key;
}
return NULL;
}
void key_select(struct key_t *key)
{
struct key_t *k;
/* Prevent duplicates. */
key_for_each_selected(k) {
if (k == key)
return;
}
util_add_array(&selected_keys, &num_selected_keys, key);
}
void key_select_by_groups(int groups, bool found)
{
struct key_t *key;
key_for_each(key) {
if (found && !key->found)
continue;
if (!(groups & (int)key->group))
continue;
key_select(key);
}
}
void key_select_by_cmg(int cmg)
{
struct key_t *key;
key_for_each(key) {
if (IS_CMG_MASK(key->cmg_mask, cmg))
key_select(key);
}
}
void key_select_all(void)
{
struct key_t *key;
key_for_each(key)
key_select(key);
}
int key_get_selected_groups(void)
{
struct key_t *key;
int groups = 0;
key_for_each_selected(key)
groups |= (int)key->group;
return groups;
}