Files
s390-tools/zconf/chp/chpstat/column.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

431 lines
7.1 KiB
C

/*
* Registry for supported table columns
*
* 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 <string.h>
#include <stdbool.h>
#include "column.h"
#include "lib/util_base.h"
#include "lib/util_libc.h"
/*
* Use group header for adjacent columns of the same type to improve
* readability.
*
* Single header: UTIL Group header: UTILIZATION
* PART PART TOTAL
*/
#define HDR1_CHP_SINGLE ""
#define HDR1_CHP_GROUP "CHANNEL-PATH"
#define HDR1_UTIL_SINGLE "UTIL"
#define HDR1_UTIL_GROUP "UTILIZATION(%)"
#define HDR1_READ_SINGLE "READ"
#define HDR1_READ_GROUP "READ"
#define HDR1_WRITE_SINGLE "WRITE"
#define HDR1_WRITE_GROUP "WRITE"
#define HDR1_FICON_SINGLE "FICON"
#define HDR1_FICON_GROUP "FICON-OPS"
#define HDR1_HPF_SINGLE "HPF"
#define HDR1_HPF_GROUP "HPF-OPS"
#define HDR1_MSGR_SINGLE "RATE"
#define HDR1_MSGR_GROUP "MSG-RATE"
#define HDR1_MSGSZ_SINGLE "SIZE"
#define HDR1_MSGSZ_GROUP "MSG-SIZE"
#define HDR1_MSG_RCVF_SINGLE "RFAIL"
#define HDR1_MSG_RCVF_GROUP "RECEIVE-FAIL"
static struct column_t columns[] = {
{
COL_CHPID,
"chpid",
COL_OTHER,
"Channel-path ID",
"ID",
HDR1_CHP_SINGLE,
HDR1_CHP_GROUP,
0,
},
{
COL_TYPE,
"type",
COL_OTHER,
"Channel-path type",
"TYP",
HDR1_CHP_SINGLE,
HDR1_CHP_GROUP,
0,
},
{
COL_CMG,
"cmg",
COL_OTHER,
"Channel-measurement group",
"CMG",
HDR1_CHP_SINGLE,
HDR1_CHP_GROUP,
0,
},
{
COL_SPEED,
"speed",
COL_OTHER,
"Operational speed",
"SPEED",
HDR1_CHP_SINGLE,
HDR1_CHP_GROUP,
0,
},
{
COL_SHARED,
"shared",
COL_OTHER,
"Shared channel-path indicator",
"SHR",
HDR1_CHP_SINGLE,
HDR1_CHP_GROUP,
0,
},
{
COL_INTERVAL,
"interval",
COL_OTHER,
"Cumulated statistics update interval",
"INT",
HDR1_CHP_SINGLE,
HDR1_CHP_GROUP,
0,
},
{
COL_UTIL_PART,
"util_part",
COL_PERCENT,
"Partition channel-path utilization in %",
"PART",
HDR1_UTIL_SINGLE,
HDR1_UTIL_GROUP,
0,
},
{
COL_UTIL_TOTAL,
"util_total",
COL_PERCENT,
"Total channel-path utilization in %",
"TOTAL",
HDR1_UTIL_SINGLE,
HDR1_UTIL_GROUP,
0,
},
{
COL_UTIL_BUS,
"util_bus",
COL_PERCENT,
"Bus utilization in %",
"BUS",
HDR1_UTIL_SINGLE,
HDR1_UTIL_GROUP,
0,
},
{
COL_READ_PART,
"read_part",
COL_BPS,
"Partition read throughput in B/s",
"PART",
HDR1_READ_SINGLE,
HDR1_READ_GROUP,
0,
},
{
COL_READ_TOTAL,
"read_total",
COL_BPS,
"Total read throughput in B/s",
"TOTAL",
HDR1_READ_SINGLE,
HDR1_READ_GROUP,
0,
},
{
COL_WRITE_PART,
"write_part",
COL_BPS,
"Partition write throughput in B/s",
"PART",
HDR1_WRITE_SINGLE,
HDR1_WRITE_GROUP,
0,
},
{
COL_WRITE_TOTAL,
"write_total",
COL_BPS,
"Total write throughput in B/s",
"TOTAL",
HDR1_WRITE_SINGLE,
HDR1_WRITE_GROUP,
0,
},
{
COL_FICON_RATE,
"ficon_rate",
COL_NUMBER,
"FICON operations per second",
"RATE",
HDR1_FICON_SINGLE,
HDR1_FICON_GROUP,
0,
},
{
COL_FICON_ACTIVE,
"ficon_active",
COL_NUMBER,
"Avg. concurrently active FICON operations",
"ACTV",
HDR1_FICON_SINGLE,
HDR1_FICON_GROUP,
0,
},
{
COL_FICON_DEFER,
"ficon_defer",
COL_NUMBER,
"Deferred FICON operations per second",
"DEFER",
HDR1_FICON_SINGLE,
HDR1_FICON_GROUP,
0,
},
{
COL_HPF_RATE,
"hpf_rate",
COL_NUMBER,
"HPF operations per second",
"RATE",
HDR1_HPF_SINGLE,
HDR1_HPF_GROUP,
0,
},
{
COL_HPF_ACTIVE,
"hpf_active",
COL_NUMBER,
"Avg. concurrently active HPF operations",
"ACTV",
HDR1_HPF_SINGLE,
HDR1_HPF_GROUP,
0,
},
{
COL_HPF_DEFER,
"hpf_defer",
COL_NUMBER,
"Deferred HPF operations per second",
"DEFER",
HDR1_HPF_SINGLE,
HDR1_HPF_GROUP,
0,
},
{
COL_MSG_RATE_PART,
"msg_rate_part",
COL_NUMBER,
"Partition message send rate per second",
"PART",
HDR1_MSGR_SINGLE,
HDR1_MSGR_GROUP,
0,
},
{
COL_MSG_RATE_TOTAL,
"msg_rate_total",
COL_NUMBER,
"Total message send rate per second",
"TOTAL",
HDR1_MSGR_SINGLE,
HDR1_MSGR_GROUP,
0,
},
{
COL_MSG_SIZE_PART,
"msg_size_part",
COL_NUMBER,
"Partition avg. send message size",
"PART",
HDR1_MSGSZ_SINGLE,
HDR1_MSGSZ_GROUP,
0,
},
{
COL_MSG_SIZE_TOTAL,
"msg_size_total",
COL_NUMBER,
"Total avg. send message size",
"TOTAL",
HDR1_MSGSZ_SINGLE,
HDR1_MSGSZ_GROUP,
0,
},
{
COL_SEND_FAIL_PART,
"send_fail_part",
COL_NUMBER,
"Partition message send fail rate per second",
"PART",
"SNDFAIL",
"SNDFAIL",
0,
},
{
COL_RCV_FAIL_PART,
"rcv_fail_part",
COL_NUMBER,
"Partition message receive fail rate per second",
"PART",
HDR1_MSG_RCVF_SINGLE,
HDR1_MSG_RCVF_GROUP,
0,
},
{
COL_RCV_FAIL_TOTAL,
"rcv_fail_total",
COL_NUMBER,
"Total message receive fail rate per second",
"TOTAL",
HDR1_MSG_RCVF_SINGLE,
HDR1_MSG_RCVF_GROUP,
0,
},
};
/* Columns selected by default. */
static const int default_columns[] = {
COL_CHPID,
COL_TYPE,
COL_CMG,
COL_SHARED,
COL_SPEED,
COL_UTIL_PART,
COL_UTIL_TOTAL,
COL_UTIL_BUS,
COL_READ_PART,
COL_READ_TOTAL,
COL_WRITE_PART,
COL_WRITE_TOTAL,
/* End of list. */
COL_END
};
static struct column_t **selected_cols;
static unsigned int num_selected_cols;
static bool hdr_updated;
struct column_t *column_get_by_index(unsigned int i, bool selected)
{
if (selected)
return i < num_selected_cols ? selected_cols[i] : NULL;
return i < ARRAY_SIZE(columns) ? &columns[i] : NULL;
}
/*
* Retrieve column object by @name or %NULL if column does not exist.
*/
struct column_t *column_get_by_name(const char *name)
{
struct column_t *col;
column_for_each(col) {
if (strcasecmp(col->name, name) == 0)
return col;
}
return NULL;
}
/*
* Add the specified column to the list of selected columns. Discard duplicate
* selections of the same column.
*/
void column_select(struct column_t *col)
{
struct column_t *c;
/* Silently filter out double selection of columns to prevent problems
* with non-unique util_rec name fields. */
column_for_each_selected(c) {
if (c == col)
return;
}
util_add_array(&selected_cols, &num_selected_cols, col);
}
void column_select_id_list(const int *ids)
{
struct column_t *col;
int i;
for (i = 0; ids[i] != COL_END; i++) {
column_for_each(col) {
if (col->id == ids[i]) {
column_select(col);
break;
}
}
}
}
void column_select_default(void)
{
column_select_id_list(default_columns);
}
void column_select_all(void)
{
struct column_t *col;
column_for_each(col)
column_select(col);
}
void column_update_bps_suffix(bool auto_scale, char suffix_char)
{
struct column_t *col;
char *str;
if (auto_scale)
util_asprintf(&str, "(B/s)");
else if (suffix_char)
util_asprintf(&str, "(%ciB/s)", suffix_char);
else
str = util_strdup("(*)");
column_for_each(col) {
if (col->unit != COL_BPS) {
col->hdr1_group = util_strdup(col->hdr1_group);
continue;
}
util_asprintf(&col->hdr1_group, "%s%s", col->hdr1_group, str);
}
free(str);
hdr_updated = true;
}
void column_exit(void)
{
struct column_t *col;
if (hdr_updated) {
column_for_each(col)
free(col->hdr1_group);
}
free(selected_cols);
}