mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
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>
431 lines
7.1 KiB
C
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);
|
|
}
|