Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Data gathering module for Linux-VM Monitor Stream, Stage 1.
0004  * Collects misc. OS related data (CPU utilization, running processes).
0005  *
0006  * Copyright IBM Corp. 2003, 2006
0007  *
0008  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
0009  */
0010 
0011 #define KMSG_COMPONENT  "appldata"
0012 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0013 
0014 #include <linux/module.h>
0015 #include <linux/init.h>
0016 #include <linux/slab.h>
0017 #include <linux/errno.h>
0018 #include <linux/kernel_stat.h>
0019 #include <linux/netdevice.h>
0020 #include <linux/sched.h>
0021 #include <linux/sched/loadavg.h>
0022 #include <linux/sched/stat.h>
0023 #include <asm/appldata.h>
0024 #include <asm/smp.h>
0025 
0026 #include "appldata.h"
0027 
0028 /*
0029  * OS data
0030  *
0031  * This is accessed as binary data by z/VM. If changes to it can't be avoided,
0032  * the structure version (product ID, see appldata_base.c) needs to be changed
0033  * as well and all documentation and z/VM applications using it must be
0034  * updated.
0035  */
0036 struct appldata_os_per_cpu {
0037     u32 per_cpu_user;   /* timer ticks spent in user mode   */
0038     u32 per_cpu_nice;   /* ... spent with modified priority */
0039     u32 per_cpu_system; /* ... spent in kernel mode         */
0040     u32 per_cpu_idle;   /* ... spent in idle mode           */
0041 
0042     /* New in 2.6 */
0043     u32 per_cpu_irq;    /* ... spent in interrupts          */
0044     u32 per_cpu_softirq;    /* ... spent in softirqs            */
0045     u32 per_cpu_iowait; /* ... spent while waiting for I/O  */
0046 
0047     /* New in modification level 01 */
0048     u32 per_cpu_steal;  /* ... stolen by hypervisor     */
0049     u32 cpu_id;     /* number of this CPU           */
0050 } __attribute__((packed));
0051 
0052 struct appldata_os_data {
0053     u64 timestamp;
0054     u32 sync_count_1;   /* after VM collected the record data, */
0055     u32 sync_count_2;   /* sync_count_1 and sync_count_2 should be the
0056                    same. If not, the record has been updated on
0057                    the Linux side while VM was collecting the
0058                    (possibly corrupt) data */
0059 
0060     u32 nr_cpus;        /* number of (virtual) CPUs        */
0061     u32 per_cpu_size;   /* size of the per-cpu data struct */
0062     u32 cpu_offset;     /* offset of the first per-cpu data struct */
0063 
0064     u32 nr_running;     /* number of runnable threads      */
0065     u32 nr_threads;     /* number of threads               */
0066     u32 avenrun[3];     /* average nr. of running processes during */
0067                 /* the last 1, 5 and 15 minutes */
0068 
0069     /* New in 2.6 */
0070     u32 nr_iowait;      /* number of blocked threads
0071                    (waiting for I/O)               */
0072 
0073     /* per cpu data */
0074     struct appldata_os_per_cpu os_cpu[];
0075 } __attribute__((packed));
0076 
0077 static struct appldata_os_data *appldata_os_data;
0078 
0079 static struct appldata_ops ops = {
0080     .name      = "os",
0081     .record_nr = APPLDATA_RECORD_OS_ID,
0082     .owner     = THIS_MODULE,
0083     .mod_lvl   = {0xF0, 0xF1},      /* EBCDIC "01" */
0084 };
0085 
0086 
0087 /*
0088  * appldata_get_os_data()
0089  *
0090  * gather OS data
0091  */
0092 static void appldata_get_os_data(void *data)
0093 {
0094     int i, j, rc;
0095     struct appldata_os_data *os_data;
0096     unsigned int new_size;
0097 
0098     os_data = data;
0099     os_data->sync_count_1++;
0100 
0101     os_data->nr_threads = nr_threads;
0102     os_data->nr_running = nr_running();
0103     os_data->nr_iowait  = nr_iowait();
0104     os_data->avenrun[0] = avenrun[0] + (FIXED_1/200);
0105     os_data->avenrun[1] = avenrun[1] + (FIXED_1/200);
0106     os_data->avenrun[2] = avenrun[2] + (FIXED_1/200);
0107 
0108     j = 0;
0109     for_each_online_cpu(i) {
0110         os_data->os_cpu[j].per_cpu_user =
0111             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_USER]);
0112         os_data->os_cpu[j].per_cpu_nice =
0113             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_NICE]);
0114         os_data->os_cpu[j].per_cpu_system =
0115             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]);
0116         os_data->os_cpu[j].per_cpu_idle =
0117             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_IDLE]);
0118         os_data->os_cpu[j].per_cpu_irq =
0119             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_IRQ]);
0120         os_data->os_cpu[j].per_cpu_softirq =
0121             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]);
0122         os_data->os_cpu[j].per_cpu_iowait =
0123             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_IOWAIT]);
0124         os_data->os_cpu[j].per_cpu_steal =
0125             nsecs_to_jiffies(kcpustat_cpu(i).cpustat[CPUTIME_STEAL]);
0126         os_data->os_cpu[j].cpu_id = i;
0127         j++;
0128     }
0129 
0130     os_data->nr_cpus = j;
0131 
0132     new_size = struct_size(os_data, os_cpu, os_data->nr_cpus);
0133     if (ops.size != new_size) {
0134         if (ops.active) {
0135             rc = appldata_diag(APPLDATA_RECORD_OS_ID,
0136                        APPLDATA_START_INTERVAL_REC,
0137                        (unsigned long) ops.data, new_size,
0138                        ops.mod_lvl);
0139             if (rc != 0)
0140                 pr_err("Starting a new OS data collection "
0141                        "failed with rc=%d\n", rc);
0142 
0143             rc = appldata_diag(APPLDATA_RECORD_OS_ID,
0144                        APPLDATA_STOP_REC,
0145                        (unsigned long) ops.data, ops.size,
0146                        ops.mod_lvl);
0147             if (rc != 0)
0148                 pr_err("Stopping a faulty OS data "
0149                        "collection failed with rc=%d\n", rc);
0150         }
0151         ops.size = new_size;
0152     }
0153     os_data->timestamp = get_tod_clock();
0154     os_data->sync_count_2++;
0155 }
0156 
0157 
0158 /*
0159  * appldata_os_init()
0160  *
0161  * init data, register ops
0162  */
0163 static int __init appldata_os_init(void)
0164 {
0165     int rc, max_size;
0166 
0167     max_size = struct_size(appldata_os_data, os_cpu, num_possible_cpus());
0168     if (max_size > APPLDATA_MAX_REC_SIZE) {
0169         pr_err("Maximum OS record size %i exceeds the maximum "
0170                "record size %i\n", max_size, APPLDATA_MAX_REC_SIZE);
0171         rc = -ENOMEM;
0172         goto out;
0173     }
0174 
0175     appldata_os_data = kzalloc(max_size, GFP_KERNEL | GFP_DMA);
0176     if (appldata_os_data == NULL) {
0177         rc = -ENOMEM;
0178         goto out;
0179     }
0180 
0181     appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
0182     appldata_os_data->cpu_offset   = offsetof(struct appldata_os_data,
0183                             os_cpu);
0184 
0185     ops.data = appldata_os_data;
0186     ops.callback  = &appldata_get_os_data;
0187     rc = appldata_register_ops(&ops);
0188     if (rc != 0)
0189         kfree(appldata_os_data);
0190 out:
0191     return rc;
0192 }
0193 
0194 /*
0195  * appldata_os_exit()
0196  *
0197  * unregister ops
0198  */
0199 static void __exit appldata_os_exit(void)
0200 {
0201     appldata_unregister_ops(&ops);
0202     kfree(appldata_os_data);
0203 }
0204 
0205 
0206 module_init(appldata_os_init);
0207 module_exit(appldata_os_exit);
0208 
0209 MODULE_LICENSE("GPL");
0210 MODULE_AUTHOR("Gerald Schaefer");
0211 MODULE_DESCRIPTION("Linux-VM Monitor Stream, OS statistics");