mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Make sure there are two different buffers passed to iconv() to get rid
of the following GCC8 compile warning:
helper.c: In function ‘ht_ebcdic_to_ascii’:
helper.c:103:30: warning: passing argument 2 to restrict-qualified
parameter aliases with argument 4 [-Wrestrict]
iconv(l_iconv_ebcdic_ascii, &inout, &len, &inout, &len);
^~~~~~ ~~~~~~
helper.c:103:38: warning: passing argument 3 to restrict-qualified
parameter aliases with argument 5 [-Wrestrict]
iconv(l_iconv_ebcdic_ascii, &inout, &len, &inout, &len);
^~~~ ~~~~
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
384 lines
7.6 KiB
C
384 lines
7.6 KiB
C
/*
|
|
* hyptop - Show hypervisor performance data on System z
|
|
*
|
|
* Hyptop LPAR data gatherer that operates on debugfs
|
|
*
|
|
* Copyright IBM Corp. 2010, 2017
|
|
*
|
|
* 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 <errno.h>
|
|
#include <iconv.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "dg_debugfs.h"
|
|
#include "helper.h"
|
|
#include "hyptop.h"
|
|
#include "sd.h"
|
|
|
|
#define MTID_MASK 0x1f
|
|
#define LPAR_NAME_LEN 8
|
|
#define TMP_SIZE 64
|
|
#define LPAR_PHYS_FLG 0x80
|
|
#define CPU_TYPE_LEN 16
|
|
#define DEBUGFS_FILE "diag_204"
|
|
|
|
static u64 l_update_time_us;
|
|
static long l_204_buf_size;
|
|
|
|
/*
|
|
* Diag data structure definition
|
|
*/
|
|
|
|
struct l_x_info_blk_hdr {
|
|
u8 npar;
|
|
u8 flags;
|
|
u8 reserved1[6];
|
|
u64 curtod1;
|
|
u64 curtod2;
|
|
u8 reserved[40];
|
|
} __attribute__ ((packed));
|
|
|
|
struct l_x_sys_hdr {
|
|
u8 reserved1;
|
|
u8 cpus;
|
|
u8 rcpus;
|
|
u8 reserved2[5];
|
|
char sys_name[LPAR_NAME_LEN];
|
|
u8 reserved3[33];
|
|
u8 mtid;
|
|
u8 reserved4[46];
|
|
} __attribute__ ((packed));
|
|
|
|
static inline void l_sys_hdr__sys_name(struct l_x_sys_hdr *hdr, char *name)
|
|
{
|
|
ht_ebcdic_to_ascii(hdr->sys_name, name, LPAR_NAME_LEN);
|
|
name[LPAR_NAME_LEN] = 0;
|
|
ht_strstrip(name);
|
|
}
|
|
|
|
struct l_x_cpu_info {
|
|
u16 cpu_addr;
|
|
u8 reserved1[2];
|
|
u8 ctidx;
|
|
u8 reserved2[3];
|
|
u64 acc_time;
|
|
u64 lp_time;
|
|
u8 reserved3[6];
|
|
u8 reserved4[2];
|
|
u64 online_time;
|
|
u8 reserved5[24];
|
|
u64 mt_idle_time;
|
|
u8 reserved6[24];
|
|
} __attribute__ ((packed));
|
|
|
|
static int l_thread_cnt(struct l_x_sys_hdr *hdr)
|
|
{
|
|
return (hdr->mtid & MTID_MASK) + 1;
|
|
}
|
|
|
|
static void l_idx2name(int index, char *name)
|
|
{
|
|
switch (index) {
|
|
case 0:
|
|
strcpy(name, SD_CPU_TYPE_STR_CP);
|
|
break;
|
|
case 3:
|
|
strcpy(name, SD_CPU_TYPE_STR_IFL);
|
|
break;
|
|
default:
|
|
strcpy(name, SD_CPU_TYPE_STR_UN);
|
|
}
|
|
}
|
|
|
|
struct l_x_phys_hdr {
|
|
u8 reserved1[1];
|
|
u8 cpus;
|
|
u8 reserved2[94];
|
|
} __attribute__ ((packed));
|
|
|
|
struct l_x_phys_cpu {
|
|
u16 cpu_addr;
|
|
u8 reserved1[2];
|
|
u8 ctidx;
|
|
u8 reserved2[3];
|
|
u64 mgm_time;
|
|
u8 reserved3[80];
|
|
} __attribute__ ((packed));
|
|
|
|
/*
|
|
* Fill CPU with data
|
|
*/
|
|
static void l_sd_cpu_fill(struct sd_cpu *cpu, struct l_x_cpu_info *cpu_info,
|
|
int threads)
|
|
{
|
|
sd_cpu_cpu_time_us_set(cpu, cpu_info->lp_time);
|
|
if (threads > 1)
|
|
sd_cpu_thread_time_us_set(cpu,
|
|
cpu_info->lp_time * threads - cpu_info->mt_idle_time);
|
|
else
|
|
sd_cpu_thread_time_us_set(cpu, cpu_info->lp_time);
|
|
sd_cpu_mgm_time_us_set(cpu, G0(cpu_info->acc_time - cpu_info->lp_time));
|
|
sd_cpu_online_time_us_set(cpu, cpu_info->online_time);
|
|
sd_cpu_state_set(cpu, SD_CPU_STATE_UNKNOWN);
|
|
}
|
|
|
|
/*
|
|
* Fill system with data
|
|
*/
|
|
static void *l_sd_sys_fill(struct sd_sys *lpar, struct l_x_sys_hdr *sys_hdr)
|
|
{
|
|
struct l_x_cpu_info *cpu_info;
|
|
int i;
|
|
|
|
cpu_info = (struct l_x_cpu_info *) (sys_hdr + 1);
|
|
|
|
for (i = 0; i < sys_hdr->rcpus; i++) {
|
|
char cpu_type[CPU_TYPE_LEN + 1];
|
|
struct sd_cpu *cpu;
|
|
char cpu_id[10];
|
|
|
|
sprintf(cpu_id, "%i", cpu_info->cpu_addr);
|
|
|
|
cpu = sd_cpu_get(lpar, cpu_id);
|
|
if (!cpu) {
|
|
l_idx2name(cpu_info->ctidx, cpu_type);
|
|
cpu = sd_cpu_new(lpar, cpu_id, cpu_type, 1);
|
|
}
|
|
|
|
l_sd_cpu_fill(cpu, cpu_info, lpar->threads_per_core);
|
|
|
|
sd_cpu_commit(cpu);
|
|
cpu_info++;
|
|
}
|
|
return cpu_info;
|
|
}
|
|
|
|
/*
|
|
* Fill one physical CPU with data
|
|
*/
|
|
static void l_sd_cpu_phys_fill(struct sd_sys *sys,
|
|
struct l_x_phys_cpu *cpu_info)
|
|
{
|
|
char cpu_type[CPU_TYPE_LEN + 1];
|
|
char cpu_id[TMP_SIZE];
|
|
struct sd_cpu *cpu;
|
|
|
|
snprintf(cpu_id, TMP_SIZE, "%i", cpu_info->cpu_addr);
|
|
cpu = sd_cpu_get(sys, cpu_id);
|
|
if (!cpu) {
|
|
l_idx2name(cpu_info->ctidx, cpu_type);
|
|
cpu = sd_cpu_new(sys, cpu_id, cpu_type, 1);
|
|
sd_cpu_state_set(cpu, SD_CPU_STATE_UNKNOWN);
|
|
}
|
|
sd_cpu_mgm_time_us_set(cpu, cpu_info->mgm_time);
|
|
sd_cpu_commit(cpu);
|
|
}
|
|
|
|
/*
|
|
* Fill all physical CPUs with data
|
|
*/
|
|
static void l_sd_sys_root_cpu_phys_fill(struct sd_sys *sys,
|
|
struct l_x_phys_hdr *phys_hdr)
|
|
{
|
|
struct l_x_phys_cpu *cpu_info;
|
|
int i;
|
|
|
|
cpu_info = (struct l_x_phys_cpu *) (phys_hdr + 1);
|
|
for (i = 0; i < phys_hdr->cpus; i++) {
|
|
l_sd_cpu_phys_fill(sys, cpu_info);
|
|
cpu_info++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Header for debugfs file "diag_204"
|
|
*/
|
|
struct l_debugfs_d204_hdr {
|
|
u64 len;
|
|
u16 version;
|
|
u8 reserved[54];
|
|
} __attribute__ ((packed));
|
|
|
|
struct l_debugfs_d204 {
|
|
struct l_debugfs_d204_hdr h;
|
|
char buf[];
|
|
} __attribute__ ((packed));
|
|
|
|
/*
|
|
* Read debugfs file
|
|
*/
|
|
static void l_read_debugfs(struct l_debugfs_d204_hdr **hdr,
|
|
struct l_x_info_blk_hdr **data)
|
|
{
|
|
long real_buf_size;
|
|
ssize_t rc;
|
|
void *buf;
|
|
int fh;
|
|
|
|
do {
|
|
fh = dg_debugfs_open(DEBUGFS_FILE);
|
|
*hdr = buf = ht_alloc(l_204_buf_size);
|
|
rc = read(fh, buf, l_204_buf_size);
|
|
if (rc == -1)
|
|
ERR_EXIT_ERRNO("Reading hypervisor data failed");
|
|
close(fh);
|
|
real_buf_size = (*hdr)->len + sizeof(struct l_debugfs_d204_hdr);
|
|
if (rc == real_buf_size)
|
|
break;
|
|
l_204_buf_size = real_buf_size;
|
|
ht_free(buf);
|
|
} while (1);
|
|
*data = buf + sizeof(struct l_debugfs_d204_hdr);
|
|
}
|
|
|
|
/*
|
|
* Fill System Data
|
|
*/
|
|
static void l_sd_sys_root_fill(struct sd_sys *sys)
|
|
{
|
|
struct l_x_info_blk_hdr *time_hdr;
|
|
struct l_debugfs_d204_hdr *hdr;
|
|
struct l_x_sys_hdr *sys_hdr;
|
|
struct sd_sys *lpar;
|
|
char lpar_id[10];
|
|
int i;
|
|
|
|
do {
|
|
l_read_debugfs(&hdr, &time_hdr);
|
|
if (l_update_time_us != ht_ext_tod_2_us(&time_hdr->curtod1)) {
|
|
l_update_time_us = ht_ext_tod_2_us(&time_hdr->curtod1);
|
|
break;
|
|
}
|
|
/*
|
|
* Got old snapshot from kernel. Wait some time until
|
|
* new snapshot is available.
|
|
*/
|
|
ht_free(hdr);
|
|
usleep(DBFS_WAIT_TIME_US);
|
|
} while (1);
|
|
sys_hdr = ((void *) time_hdr) + sizeof(struct l_x_info_blk_hdr);
|
|
for (i = 0; i < time_hdr->npar; i++) {
|
|
l_sys_hdr__sys_name(sys_hdr, lpar_id);
|
|
lpar = sd_sys_get(sys, lpar_id);
|
|
if (!lpar)
|
|
lpar = sd_sys_new(sys, lpar_id);
|
|
lpar->threads_per_core = l_thread_cnt(sys_hdr);
|
|
sys_hdr = l_sd_sys_fill(lpar, sys_hdr);
|
|
sd_sys_commit(lpar);
|
|
}
|
|
|
|
if (time_hdr->flags & LPAR_PHYS_FLG)
|
|
l_sd_sys_root_cpu_phys_fill(sys, (void *) sys_hdr);
|
|
ht_free(hdr);
|
|
sd_sys_commit(sys);
|
|
}
|
|
|
|
/*
|
|
* Update system data
|
|
*/
|
|
static void l_sd_update(void)
|
|
{
|
|
struct sd_sys *root = sd_sys_root_get();
|
|
|
|
sd_sys_update_start(root);
|
|
l_sd_sys_root_fill(root);
|
|
sd_sys_update_end(root, l_update_time_us);
|
|
}
|
|
|
|
/*
|
|
* Supported system items
|
|
*/
|
|
static struct sd_sys_item *l_sys_item_vec[] = {
|
|
&sd_sys_item_core_cnt,
|
|
&sd_sys_item_thread_cnt,
|
|
&sd_sys_item_core_diff,
|
|
&sd_sys_item_thread_diff,
|
|
&sd_sys_item_mgm_diff,
|
|
&sd_sys_item_core,
|
|
&sd_sys_item_thread,
|
|
&sd_sys_item_mgm,
|
|
&sd_sys_item_online,
|
|
NULL,
|
|
};
|
|
|
|
/*
|
|
* Default system items
|
|
*/
|
|
static struct sd_sys_item *l_sys_item_enable_vec[] = {
|
|
&sd_sys_item_core_cnt,
|
|
&sd_sys_item_core_diff,
|
|
&sd_sys_item_mgm_diff,
|
|
&sd_sys_item_core,
|
|
&sd_sys_item_mgm,
|
|
&sd_sys_item_online,
|
|
NULL,
|
|
};
|
|
|
|
/*
|
|
* Supported CPU items
|
|
*/
|
|
static struct sd_cpu_item *l_cpu_item_vec[] = {
|
|
&sd_cpu_item_type,
|
|
&sd_cpu_item_core_diff,
|
|
&sd_cpu_item_thread_diff,
|
|
&sd_cpu_item_mgm_diff,
|
|
&sd_cpu_item_core,
|
|
&sd_cpu_item_thread,
|
|
&sd_cpu_item_mgm,
|
|
&sd_cpu_item_online,
|
|
NULL,
|
|
};
|
|
|
|
/*
|
|
* Default CPU items
|
|
*/
|
|
static struct sd_cpu_item *l_cpu_item_enable_vec[] = {
|
|
&sd_cpu_item_type,
|
|
&sd_cpu_item_core_diff,
|
|
&sd_cpu_item_mgm_diff,
|
|
NULL,
|
|
};
|
|
|
|
/*
|
|
* Supported CPU types
|
|
*/
|
|
static struct sd_cpu_type *l_cpu_type_vec[] = {
|
|
&sd_cpu_type_ifl,
|
|
&sd_cpu_type_cp,
|
|
&sd_cpu_type_un,
|
|
NULL,
|
|
};
|
|
|
|
/*
|
|
* Define data gatherer structure
|
|
*/
|
|
static struct sd_dg l_sd_dg = {
|
|
.update_sys = l_sd_update,
|
|
.cpu_type_vec = l_cpu_type_vec,
|
|
.sys_item_vec = l_sys_item_vec,
|
|
.sys_item_enable_vec = l_sys_item_enable_vec,
|
|
.cpu_item_vec = l_cpu_item_vec,
|
|
.cpu_item_enable_vec = l_cpu_item_enable_vec,
|
|
};
|
|
|
|
/*
|
|
* Initialize LPAR debugfs data gatherer
|
|
*/
|
|
int dg_debugfs_lpar_init(void)
|
|
{
|
|
int fh;
|
|
|
|
l_204_buf_size = sizeof(struct l_debugfs_d204_hdr);
|
|
fh = dg_debugfs_open(DEBUGFS_FILE);
|
|
if (fh < 0)
|
|
return fh;
|
|
else
|
|
close(fh);
|
|
sd_dg_register(&l_sd_dg, 1);
|
|
return 0;
|
|
}
|