18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Data gathering module for Linux-VM Monitor Stream, Stage 1. 48c2ecf20Sopenharmony_ci * Collects misc. OS related data (CPU utilization, running processes). 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2003, 2006 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "appldata" 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/errno.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel_stat.h> 198c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 208c2ecf20Sopenharmony_ci#include <linux/sched.h> 218c2ecf20Sopenharmony_ci#include <linux/sched/loadavg.h> 228c2ecf20Sopenharmony_ci#include <linux/sched/stat.h> 238c2ecf20Sopenharmony_ci#include <asm/appldata.h> 248c2ecf20Sopenharmony_ci#include <asm/smp.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "appldata.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * OS data 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * This is accessed as binary data by z/VM. If changes to it can't be avoided, 328c2ecf20Sopenharmony_ci * the structure version (product ID, see appldata_base.c) needs to be changed 338c2ecf20Sopenharmony_ci * as well and all documentation and z/VM applications using it must be 348c2ecf20Sopenharmony_ci * updated. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct appldata_os_per_cpu { 378c2ecf20Sopenharmony_ci u32 per_cpu_user; /* timer ticks spent in user mode */ 388c2ecf20Sopenharmony_ci u32 per_cpu_nice; /* ... spent with modified priority */ 398c2ecf20Sopenharmony_ci u32 per_cpu_system; /* ... spent in kernel mode */ 408c2ecf20Sopenharmony_ci u32 per_cpu_idle; /* ... spent in idle mode */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* New in 2.6 */ 438c2ecf20Sopenharmony_ci u32 per_cpu_irq; /* ... spent in interrupts */ 448c2ecf20Sopenharmony_ci u32 per_cpu_softirq; /* ... spent in softirqs */ 458c2ecf20Sopenharmony_ci u32 per_cpu_iowait; /* ... spent while waiting for I/O */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* New in modification level 01 */ 488c2ecf20Sopenharmony_ci u32 per_cpu_steal; /* ... stolen by hypervisor */ 498c2ecf20Sopenharmony_ci u32 cpu_id; /* number of this CPU */ 508c2ecf20Sopenharmony_ci} __attribute__((packed)); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct appldata_os_data { 538c2ecf20Sopenharmony_ci u64 timestamp; 548c2ecf20Sopenharmony_ci u32 sync_count_1; /* after VM collected the record data, */ 558c2ecf20Sopenharmony_ci u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the 568c2ecf20Sopenharmony_ci same. If not, the record has been updated on 578c2ecf20Sopenharmony_ci the Linux side while VM was collecting the 588c2ecf20Sopenharmony_ci (possibly corrupt) data */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci u32 nr_cpus; /* number of (virtual) CPUs */ 618c2ecf20Sopenharmony_ci u32 per_cpu_size; /* size of the per-cpu data struct */ 628c2ecf20Sopenharmony_ci u32 cpu_offset; /* offset of the first per-cpu data struct */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci u32 nr_running; /* number of runnable threads */ 658c2ecf20Sopenharmony_ci u32 nr_threads; /* number of threads */ 668c2ecf20Sopenharmony_ci u32 avenrun[3]; /* average nr. of running processes during */ 678c2ecf20Sopenharmony_ci /* the last 1, 5 and 15 minutes */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* New in 2.6 */ 708c2ecf20Sopenharmony_ci u32 nr_iowait; /* number of blocked threads 718c2ecf20Sopenharmony_ci (waiting for I/O) */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* per cpu data */ 748c2ecf20Sopenharmony_ci struct appldata_os_per_cpu os_cpu[]; 758c2ecf20Sopenharmony_ci} __attribute__((packed)); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic struct appldata_os_data *appldata_os_data; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic struct appldata_ops ops = { 808c2ecf20Sopenharmony_ci .name = "os", 818c2ecf20Sopenharmony_ci .record_nr = APPLDATA_RECORD_OS_ID, 828c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 838c2ecf20Sopenharmony_ci .mod_lvl = {0xF0, 0xF1}, /* EBCDIC "01" */ 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * appldata_get_os_data() 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * gather OS data 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic void appldata_get_os_data(void *data) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int i, j, rc; 958c2ecf20Sopenharmony_ci struct appldata_os_data *os_data; 968c2ecf20Sopenharmony_ci unsigned int new_size; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci os_data = data; 998c2ecf20Sopenharmony_ci os_data->sync_count_1++; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci os_data->nr_threads = nr_threads; 1028c2ecf20Sopenharmony_ci os_data->nr_running = nr_running(); 1038c2ecf20Sopenharmony_ci os_data->nr_iowait = nr_iowait(); 1048c2ecf20Sopenharmony_ci os_data->avenrun[0] = avenrun[0] + (FIXED_1/200); 1058c2ecf20Sopenharmony_ci os_data->avenrun[1] = avenrun[1] + (FIXED_1/200); 1068c2ecf20Sopenharmony_ci os_data->avenrun[2] = avenrun[2] + (FIXED_1/200); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci j = 0; 1098c2ecf20Sopenharmony_ci for_each_online_cpu(i) { 1108c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_user = 1118c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_USER]); 1128c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_nice = 1138c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_NICE]); 1148c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_system = 1158c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]); 1168c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_idle = 1178c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_IDLE]); 1188c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_irq = 1198c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_IRQ]); 1208c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_softirq = 1218c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]); 1228c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_iowait = 1238c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_IOWAIT]); 1248c2ecf20Sopenharmony_ci os_data->os_cpu[j].per_cpu_steal = 1258c2ecf20Sopenharmony_ci nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_STEAL]); 1268c2ecf20Sopenharmony_ci os_data->os_cpu[j].cpu_id = i; 1278c2ecf20Sopenharmony_ci j++; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci os_data->nr_cpus = j; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci new_size = struct_size(os_data, os_cpu, os_data->nr_cpus); 1338c2ecf20Sopenharmony_ci if (ops.size != new_size) { 1348c2ecf20Sopenharmony_ci if (ops.active) { 1358c2ecf20Sopenharmony_ci rc = appldata_diag(APPLDATA_RECORD_OS_ID, 1368c2ecf20Sopenharmony_ci APPLDATA_START_INTERVAL_REC, 1378c2ecf20Sopenharmony_ci (unsigned long) ops.data, new_size, 1388c2ecf20Sopenharmony_ci ops.mod_lvl); 1398c2ecf20Sopenharmony_ci if (rc != 0) 1408c2ecf20Sopenharmony_ci pr_err("Starting a new OS data collection " 1418c2ecf20Sopenharmony_ci "failed with rc=%d\n", rc); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci rc = appldata_diag(APPLDATA_RECORD_OS_ID, 1448c2ecf20Sopenharmony_ci APPLDATA_STOP_REC, 1458c2ecf20Sopenharmony_ci (unsigned long) ops.data, ops.size, 1468c2ecf20Sopenharmony_ci ops.mod_lvl); 1478c2ecf20Sopenharmony_ci if (rc != 0) 1488c2ecf20Sopenharmony_ci pr_err("Stopping a faulty OS data " 1498c2ecf20Sopenharmony_ci "collection failed with rc=%d\n", rc); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci ops.size = new_size; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci os_data->timestamp = get_tod_clock(); 1548c2ecf20Sopenharmony_ci os_data->sync_count_2++; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* 1598c2ecf20Sopenharmony_ci * appldata_os_init() 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * init data, register ops 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic int __init appldata_os_init(void) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int rc, max_size; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci max_size = struct_size(appldata_os_data, os_cpu, num_possible_cpus()); 1688c2ecf20Sopenharmony_ci if (max_size > APPLDATA_MAX_REC_SIZE) { 1698c2ecf20Sopenharmony_ci pr_err("Maximum OS record size %i exceeds the maximum " 1708c2ecf20Sopenharmony_ci "record size %i\n", max_size, APPLDATA_MAX_REC_SIZE); 1718c2ecf20Sopenharmony_ci rc = -ENOMEM; 1728c2ecf20Sopenharmony_ci goto out; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci appldata_os_data = kzalloc(max_size, GFP_KERNEL | GFP_DMA); 1768c2ecf20Sopenharmony_ci if (appldata_os_data == NULL) { 1778c2ecf20Sopenharmony_ci rc = -ENOMEM; 1788c2ecf20Sopenharmony_ci goto out; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu); 1828c2ecf20Sopenharmony_ci appldata_os_data->cpu_offset = offsetof(struct appldata_os_data, 1838c2ecf20Sopenharmony_ci os_cpu); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ops.data = appldata_os_data; 1868c2ecf20Sopenharmony_ci ops.callback = &appldata_get_os_data; 1878c2ecf20Sopenharmony_ci rc = appldata_register_ops(&ops); 1888c2ecf20Sopenharmony_ci if (rc != 0) 1898c2ecf20Sopenharmony_ci kfree(appldata_os_data); 1908c2ecf20Sopenharmony_ciout: 1918c2ecf20Sopenharmony_ci return rc; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * appldata_os_exit() 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * unregister ops 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic void __exit appldata_os_exit(void) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci appldata_unregister_ops(&ops); 2028c2ecf20Sopenharmony_ci kfree(appldata_os_data); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cimodule_init(appldata_os_init); 2078c2ecf20Sopenharmony_cimodule_exit(appldata_os_exit); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Gerald Schaefer"); 2118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Linux-VM Monitor Stream, OS statistics"); 212