Blame view

arch/s390/appldata/appldata_os.c 7.97 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * arch/s390/appldata/appldata_os.c
   *
   * Data gathering module for Linux-VM Monitor Stream, Stage 1.
   * Collects misc. OS related data (CPU utilization, running processes).
   *
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
7
   * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   *
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
9
   * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/errno.h>
  #include <linux/kernel_stat.h>
  #include <linux/netdevice.h>
  #include <linux/sched.h>
1f38d6134   Gerald Schaefer   [S390] cleanup ap...
18
  #include <asm/appldata.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  #include <asm/smp.h>
  
  #include "appldata.h"
  
  
  #define MY_PRINT_NAME	"appldata_os"		/* for debug messages, etc. */
  #define LOAD_INT(x) ((x) >> FSHIFT)
  #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
  
  /*
   * OS data
   *
   * This is accessed as binary data by z/VM. If changes to it can't be avoided,
   * the structure version (product ID, see appldata_base.c) needs to be changed
   * as well and all documentation and z/VM applications using it must be
   * updated.
   *
   * The record layout is documented in the Linux for zSeries Device Drivers
   * book:
   * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
   */
  struct appldata_os_per_cpu {
  	u32 per_cpu_user;	/* timer ticks spent in user mode   */
  	u32 per_cpu_nice;	/* ... spent with modified priority */
  	u32 per_cpu_system;	/* ... spent in kernel mode         */
  	u32 per_cpu_idle;	/* ... spent in idle mode           */
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
45
  	/* New in 2.6 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
  	u32 per_cpu_irq;	/* ... spent in interrupts          */
  	u32 per_cpu_softirq;	/* ... spent in softirqs            */
  	u32 per_cpu_iowait;	/* ... spent while waiting for I/O  */
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
49
50
51
52
  
  	/* New in modification level 01 */
  	u32 per_cpu_steal;	/* ... stolen by hypervisor	    */
  	u32 cpu_id;		/* number of this CPU		    */
f26d583e4   Gerald Schaefer   [PATCH] s390: dea...
53
  } __attribute__((packed));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  
  struct appldata_os_data {
  	u64 timestamp;
  	u32 sync_count_1;	/* after VM collected the record data, */
  	u32 sync_count_2;	/* sync_count_1 and sync_count_2 should be the
  				   same. If not, the record has been updated on
  				   the Linux side while VM was collecting the
  				   (possibly corrupt) data */
  
  	u32 nr_cpus;		/* number of (virtual) CPUs        */
  	u32 per_cpu_size;	/* size of the per-cpu data struct */
  	u32 cpu_offset;		/* offset of the first per-cpu data struct */
  
  	u32 nr_running;		/* number of runnable threads      */
  	u32 nr_threads;		/* number of threads               */
  	u32 avenrun[3];		/* average nr. of running processes during */
  				/* the last 1, 5 and 15 minutes */
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
71
  	/* New in 2.6 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	u32 nr_iowait;		/* number of blocked threads
  				   (waiting for I/O)               */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
  
  	/* per cpu data */
  	struct appldata_os_per_cpu os_cpu[0];
f26d583e4   Gerald Schaefer   [PATCH] s390: dea...
77
  } __attribute__((packed));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
  
  static struct appldata_os_data *appldata_os_data;
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
80
81
82
83
84
85
86
  static struct appldata_ops ops = {
  	.ctl_nr    = CTL_APPLDATA_OS,
  	.name	   = "os",
  	.record_nr = APPLDATA_RECORD_OS_ID,
  	.owner	   = THIS_MODULE,
  	.mod_lvl   = {0xF0, 0xF1},		/* EBCDIC "01" */
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  
  static inline void appldata_print_debug(struct appldata_os_data *os_data)
  {
  	int a0, a1, a2, i;
  
  	P_DEBUG("--- OS - RECORD ---
  ");
  	P_DEBUG("nr_threads   = %u
  ", os_data->nr_threads);
  	P_DEBUG("nr_running   = %u
  ", os_data->nr_running);
  	P_DEBUG("nr_iowait    = %u
  ", os_data->nr_iowait);
  	P_DEBUG("avenrun(int) = %8x / %8x / %8x
  ", os_data->avenrun[0],
  		os_data->avenrun[1], os_data->avenrun[2]);
  	a0 = os_data->avenrun[0];
  	a1 = os_data->avenrun[1];
  	a2 = os_data->avenrun[2];
  	P_DEBUG("avenrun(float) = %d.%02d / %d.%02d / %d.%02d
  ",
  		LOAD_INT(a0), LOAD_FRAC(a0), LOAD_INT(a1), LOAD_FRAC(a1),
  		LOAD_INT(a2), LOAD_FRAC(a2));
  
  	P_DEBUG("nr_cpus = %u
  ", os_data->nr_cpus);
  	for (i = 0; i < os_data->nr_cpus; i++) {
  		P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
115
116
117
118
  			"idle = %u, irq = %u, softirq = %u, iowait = %u, "
  			"steal = %u
  ",
  				os_data->os_cpu[i].cpu_id,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
  				os_data->os_cpu[i].per_cpu_user,
  				os_data->os_cpu[i].per_cpu_nice,
  				os_data->os_cpu[i].per_cpu_system,
  				os_data->os_cpu[i].per_cpu_idle,
  				os_data->os_cpu[i].per_cpu_irq,
  				os_data->os_cpu[i].per_cpu_softirq,
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
125
126
  				os_data->os_cpu[i].per_cpu_iowait,
  				os_data->os_cpu[i].per_cpu_steal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  	}
  
  	P_DEBUG("sync_count_1 = %u
  ", os_data->sync_count_1);
  	P_DEBUG("sync_count_2 = %u
  ", os_data->sync_count_2);
  	P_DEBUG("timestamp    = %lX
  ", os_data->timestamp);
  }
  
  /*
   * appldata_get_os_data()
   *
   * gather OS data
   */
  static void appldata_get_os_data(void *data)
  {
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
144
  	int i, j, rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  	struct appldata_os_data *os_data;
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
146
  	unsigned int new_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
  
  	os_data = data;
  	os_data->sync_count_1++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
158
159
  	os_data->nr_threads = nr_threads;
  	os_data->nr_running = nr_running();
  	os_data->nr_iowait  = nr_iowait();
  	os_data->avenrun[0] = avenrun[0] + (FIXED_1/200);
  	os_data->avenrun[1] = avenrun[1] + (FIXED_1/200);
  	os_data->avenrun[2] = avenrun[2] + (FIXED_1/200);
  
  	j = 0;
  	for_each_online_cpu(i) {
  		os_data->os_cpu[j].per_cpu_user =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
160
  			cputime_to_jiffies(kstat_cpu(i).cpustat.user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  		os_data->os_cpu[j].per_cpu_nice =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
162
  			cputime_to_jiffies(kstat_cpu(i).cpustat.nice);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  		os_data->os_cpu[j].per_cpu_system =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
164
  			cputime_to_jiffies(kstat_cpu(i).cpustat.system);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  		os_data->os_cpu[j].per_cpu_idle =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
166
  			cputime_to_jiffies(kstat_cpu(i).cpustat.idle);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  		os_data->os_cpu[j].per_cpu_irq =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
168
  			cputime_to_jiffies(kstat_cpu(i).cpustat.irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  		os_data->os_cpu[j].per_cpu_softirq =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
170
  			cputime_to_jiffies(kstat_cpu(i).cpustat.softirq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		os_data->os_cpu[j].per_cpu_iowait =
089545f0c   Martin Schwidefsky   [PATCH] s390: cpu...
172
  			cputime_to_jiffies(kstat_cpu(i).cpustat.iowait);
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
173
174
175
  		os_data->os_cpu[j].per_cpu_steal =
  			cputime_to_jiffies(kstat_cpu(i).cpustat.steal);
  		os_data->os_cpu[j].cpu_id = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  		j++;
  	}
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  	os_data->nr_cpus = j;
  
  	new_size = sizeof(struct appldata_os_data) +
  		   (os_data->nr_cpus * sizeof(struct appldata_os_per_cpu));
  	if (ops.size != new_size) {
  		if (ops.active) {
  			rc = appldata_diag(APPLDATA_RECORD_OS_ID,
  					   APPLDATA_START_INTERVAL_REC,
  					   (unsigned long) ops.data, new_size,
  					   ops.mod_lvl);
  			if (rc != 0) {
  				P_ERROR("os: START NEW DIAG 0xDC failed, "
  					"return code: %d, new size = %i
  ", rc,
  					new_size);
  				P_INFO("os: stopping old record now
  ");
  			} else
  				P_INFO("os: new record size = %i
  ", new_size);
  
  			rc = appldata_diag(APPLDATA_RECORD_OS_ID,
  					   APPLDATA_STOP_REC,
  					   (unsigned long) ops.data, ops.size,
  					   ops.mod_lvl);
  			if (rc != 0)
  				P_ERROR("os: STOP OLD DIAG 0xDC failed, "
  					"return code: %d, old size = %i
  ", rc,
  					ops.size);
  			else
  				P_INFO("os: old record size = %i stopped
  ",
  					ops.size);
  		}
  		ops.size = new_size;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
220
  	os_data->timestamp = get_clock();
  	os_data->sync_count_2++;
  #ifdef APPLDATA_DEBUG
  	appldata_print_debug(os_data);
  #endif
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
  /*
   * appldata_os_init()
   *
   * init data, register ops
   */
  static int __init appldata_os_init(void)
  {
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
228
  	int rc, max_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229

5b5dd21a8   Gerald Schaefer   [S390] appldata e...
230
231
232
233
234
235
  	max_size = sizeof(struct appldata_os_data) +
  		   (NR_CPUS * sizeof(struct appldata_os_per_cpu));
  	if (max_size > APPLDATA_MAX_REC_SIZE) {
  		P_ERROR("Max. size of OS record = %i, bigger than maximum "
  			"record size (%i)
  ", max_size, APPLDATA_MAX_REC_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
  		rc = -ENOMEM;
  		goto out;
  	}
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
239
240
  	P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu
  ", max_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  		sizeof(struct appldata_os_per_cpu));
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
242
  	appldata_os_data = kzalloc(max_size, GFP_DMA);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
  	if (appldata_os_data == NULL) {
  		P_ERROR("No memory for %s!
  ", ops.name);
  		rc = -ENOMEM;
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
  
  	appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
  	appldata_os_data->cpu_offset   = offsetof(struct appldata_os_data,
  							os_cpu);
  	P_DEBUG("cpu offset = %u
  ", appldata_os_data->cpu_offset);
  
  	ops.data = appldata_os_data;
5b5dd21a8   Gerald Schaefer   [S390] appldata e...
257
  	ops.callback  = &appldata_get_os_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  	rc = appldata_register_ops(&ops);
  	if (rc != 0) {
  		P_ERROR("Error registering ops, rc = %i
  ", rc);
  		kfree(appldata_os_data);
  	} else {
  		P_DEBUG("%s-ops registered!
  ", ops.name);
  	}
  out:
  	return rc;
  }
  
  /*
   * appldata_os_exit()
   *
   * unregister ops
   */
  static void __exit appldata_os_exit(void)
  {
  	appldata_unregister_ops(&ops);
  	kfree(appldata_os_data);
  	P_DEBUG("%s-ops unregistered!
  ", ops.name);
  }
  
  
  module_init(appldata_os_init);
  module_exit(appldata_os_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Gerald Schaefer");
  MODULE_DESCRIPTION("Linux-VM Monitor Stream, OS statistics");