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>
144 lines
3.5 KiB
C
144 lines
3.5 KiB
C
/*
|
|
* Support for CMG 1 channel-path statistics
|
|
*
|
|
* 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 "cmg.h"
|
|
#include "cmg_helper.h"
|
|
#include "column.h"
|
|
#include "key.h"
|
|
|
|
#include "lib/util_base.h"
|
|
#include "lib/zt_common.h"
|
|
|
|
/* Macros to convert generic cmg_data_t into CMG-specific ones. */
|
|
#define get_cue(d, x) ((struct cue1_t *)&((d)->x.cue))
|
|
#define get_metrics(d) ((struct metrics1_t *)&((d)->metrics))
|
|
|
|
/* CMG 1 format Channel-Utilization-Entry. */
|
|
struct cue1_t {
|
|
u8 cuiv;
|
|
u32 timestamp:24;
|
|
u32 channel_path_busy_time_cpc;
|
|
u32 channel_path_busy_time;
|
|
} __packed;
|
|
|
|
STATIC_ASSERT(sizeof(struct cue1_t) <= sizeof(cue_t));
|
|
|
|
/* Metrics based on CMG 1 format CUEs. */
|
|
struct metrics1_t {
|
|
double interval;
|
|
double util_total;
|
|
double util_part;
|
|
};
|
|
|
|
STATIC_ASSERT(sizeof(struct metrics1_t) <= sizeof(metrics_t));
|
|
|
|
/* IDs of columns that should be shown by default in table output. */
|
|
static const enum column_id_t default_column_ids[] = {
|
|
COL_CHPID,
|
|
COL_TYPE,
|
|
COL_CMG,
|
|
COL_SHARED,
|
|
COL_SPEED,
|
|
COL_UTIL_PART,
|
|
COL_UTIL_TOTAL,
|
|
/* End of list. */
|
|
COL_END
|
|
};
|
|
|
|
static void pr_cue(struct cmg_pair_t **a, unsigned int *n,
|
|
struct cmg_data_t *data)
|
|
{
|
|
struct cue1_t *cue = get_cue(data, util_b);
|
|
|
|
pr_u32(a, n, cue, timestamp);
|
|
pr_cue_u32(a, n, cue, channel_path_busy_time_cpc);
|
|
pr_cue_u32(a, n, cue, channel_path_busy_time);
|
|
}
|
|
|
|
static void pr_metrics(struct cmg_pair_t **a, unsigned int *n,
|
|
struct cmg_data_t *data)
|
|
{
|
|
struct metrics1_t *metrics = get_metrics(data);
|
|
|
|
pr_metric(a, n, metrics, interval, CMG_NUMBER, COL_INTERVAL);
|
|
pr_metric(a, n, metrics, util_total, CMG_PERCENT, COL_UTIL_TOTAL);
|
|
pr_metric(a, n, metrics, util_part, CMG_PERCENT, COL_UTIL_PART);
|
|
}
|
|
|
|
static struct cmg_pair_t *get_values(struct cmg_data_t *data, int groups)
|
|
{
|
|
struct cmg_pair_t *array = NULL;
|
|
unsigned int num = 0;
|
|
|
|
if (groups & KEY_GRP_UTIL)
|
|
pr_cue(&array, &num, data);
|
|
if (groups & KEY_GRP_METRICS)
|
|
pr_metrics(&array, &num, data);
|
|
|
|
/* Add terminating null-element. */
|
|
util_expand_array(&array, &num);
|
|
array[num - 1].key = NULL;
|
|
|
|
return array;
|
|
}
|
|
|
|
/* Initialize metrics in @m. */
|
|
static void init_metrics(struct metrics1_t *m)
|
|
{
|
|
m->interval = METRICS_INIT;
|
|
m->util_total = METRICS_INIT;
|
|
m->util_part = METRICS_INIT;
|
|
}
|
|
|
|
/* Recalculate metrics in @data. */
|
|
static void update_metrics(struct cmg_data_t *data)
|
|
{
|
|
struct metrics1_t *m = get_metrics(data);
|
|
struct cue1_t *a = get_cue(data, util_a);
|
|
struct cue1_t *b = get_cue(data, util_b);
|
|
u32 ticks, delta;
|
|
|
|
init_metrics(m);
|
|
|
|
ticks = get_delta(a->timestamp, b->timestamp, CUE_TS_WIDTH);
|
|
if (ticks == 0)
|
|
return;
|
|
|
|
/* interval = t2 - t1 */
|
|
m->interval = tick_to_s(ticks);
|
|
|
|
/* util_total = 100.0 * ticks_busy_cpc / ticks_total */
|
|
if (cue_valid2(a, b, channel_path_busy_time_cpc)) {
|
|
delta = field_delta(channel_path_busy_time_cpc, a, b);
|
|
m->util_total = 100.0 * delta / ticks;
|
|
}
|
|
/* util_part = 100.0 * ticks_busy / ticks_total */
|
|
if (cue_valid2(a, b, channel_path_busy_time)) {
|
|
delta = field_delta(channel_path_busy_time, a, b);
|
|
m->util_part = 100.0 * delta / ticks;
|
|
}
|
|
}
|
|
|
|
/* Object defining this CMG. */
|
|
static struct cmg_t cmg1 = {
|
|
.cmg = 1,
|
|
.selected = false,
|
|
.found = 0,
|
|
.has_cmcb = false,
|
|
.default_column_ids = default_column_ids,
|
|
.get_values = &get_values,
|
|
.update_metrics = &update_metrics,
|
|
};
|
|
|
|
/* Add to CMG registry. */
|
|
static void __attribute__((constructor)) cmg1_ctr(void)
|
|
{
|
|
cmg_add(&cmg1);
|
|
}
|