perfmonger 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.dir-locals.el +2 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/COPYING +674 -0
- data/Gemfile +5 -0
- data/HOWTO.md +15 -0
- data/NEWS +115 -0
- data/README.md +61 -0
- data/Rakefile +8 -0
- data/bin/perfmonger +6 -0
- data/data/NOTICE +8 -0
- data/data/Twitter_Bootstrap_LICENSE.txt +176 -0
- data/data/assets/css/bootstrap-responsive.css +1109 -0
- data/data/assets/css/bootstrap.css +6167 -0
- data/data/assets/css/perfmonger.css +17 -0
- data/data/assets/dashboard.erb +319 -0
- data/data/assets/img/glyphicons-halflings-white.png +0 -0
- data/data/assets/img/glyphicons-halflings.png +0 -0
- data/data/assets/js/bootstrap.js +2280 -0
- data/data/assets/js/bootstrap.min.js +6 -0
- data/data/assets/js/canvasjs.js +9042 -0
- data/data/assets/js/canvasjs.min.js +271 -0
- data/data/sysstat.ioconf +268 -0
- data/ext/perfmonger/extconf.rb +19 -0
- data/ext/perfmonger/perfmonger.h +58 -0
- data/ext/perfmonger/perfmonger_record.c +754 -0
- data/ext/perfmonger/sysstat/common.c +627 -0
- data/ext/perfmonger/sysstat/common.h +207 -0
- data/ext/perfmonger/sysstat/ioconf.c +515 -0
- data/ext/perfmonger/sysstat/ioconf.h +84 -0
- data/ext/perfmonger/sysstat/iostat.c +1100 -0
- data/ext/perfmonger/sysstat/iostat.h +121 -0
- data/ext/perfmonger/sysstat/libsysstat.h +19 -0
- data/ext/perfmonger/sysstat/mpstat.c +953 -0
- data/ext/perfmonger/sysstat/mpstat.h +79 -0
- data/ext/perfmonger/sysstat/rd_stats.c +2388 -0
- data/ext/perfmonger/sysstat/rd_stats.h +651 -0
- data/ext/perfmonger/sysstat/sysconfig.h +13 -0
- data/lib/perfmonger/cli.rb +115 -0
- data/lib/perfmonger/command/base_command.rb +39 -0
- data/lib/perfmonger/command/fingerprint.rb +453 -0
- data/lib/perfmonger/command/plot.rb +429 -0
- data/lib/perfmonger/command/record.rb +32 -0
- data/lib/perfmonger/command/record_option.rb +149 -0
- data/lib/perfmonger/command/server.rb +294 -0
- data/lib/perfmonger/command/stat.rb +60 -0
- data/lib/perfmonger/command/stat_option.rb +29 -0
- data/lib/perfmonger/command/summary.rb +402 -0
- data/lib/perfmonger/config.rb +6 -0
- data/lib/perfmonger/version.rb +5 -0
- data/lib/perfmonger.rb +12 -0
- data/misc/release-howto.txt +17 -0
- data/misc/sample-cpu.png +0 -0
- data/misc/sample-read-iops.png +0 -0
- data/perfmonger.gemspec +44 -0
- data/test/run-test.sh +39 -0
- data/test/spec/bin_spec.rb +37 -0
- data/test/spec/data/2devices.expected +42 -0
- data/test/spec/data/2devices.output +42 -0
- data/test/spec/spec_helper.rb +20 -0
- data/test/spec/summary_spec.rb +193 -0
- data/test/test-perfmonger.c +145 -0
- data/test/test.h +9 -0
- metadata +154 -0
@@ -0,0 +1,627 @@
|
|
1
|
+
/*
|
2
|
+
* (C) 2011 Modified by Yuto HAYAMIZU (haya <at> tkl.iis.u-tokyo.ac.jp)
|
3
|
+
*/
|
4
|
+
|
5
|
+
/*
|
6
|
+
* sar, sadc, sadf, mpstat and iostat common routines.
|
7
|
+
* (C) 1999-2010 by Sebastien GODARD (sysstat <at> orange.fr)
|
8
|
+
*
|
9
|
+
***************************************************************************
|
10
|
+
* This program is free software; you can redistribute it and/or modify it *
|
11
|
+
* under the terms of the GNU General Public License as published by the *
|
12
|
+
* Free Software Foundation; either version 2 of the License, or (at your *
|
13
|
+
* option) any later version. *
|
14
|
+
* *
|
15
|
+
* This program is distributed in the hope that it will be useful, but *
|
16
|
+
* WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
|
17
|
+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
|
18
|
+
* for more details. *
|
19
|
+
* *
|
20
|
+
* You should have received a copy of the GNU General Public License along *
|
21
|
+
* with this program; if not, write to the Free Software Foundation, Inc., *
|
22
|
+
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
23
|
+
***************************************************************************
|
24
|
+
*/
|
25
|
+
|
26
|
+
|
27
|
+
#include <stdio.h>
|
28
|
+
#include <string.h>
|
29
|
+
#include <stdlib.h>
|
30
|
+
#include <time.h>
|
31
|
+
#include <errno.h>
|
32
|
+
#include <unistd.h> /* For STDOUT_FILENO, among others */
|
33
|
+
#include <sys/ioctl.h>
|
34
|
+
#include <sys/types.h>
|
35
|
+
#include <dirent.h>
|
36
|
+
|
37
|
+
#include "common.h"
|
38
|
+
#include "ioconf.h"
|
39
|
+
#include "rd_stats.h"
|
40
|
+
|
41
|
+
#ifdef USE_NLS
|
42
|
+
#include <locale.h>
|
43
|
+
#include <libintl.h>
|
44
|
+
#define _(string) gettext(string)
|
45
|
+
#else
|
46
|
+
#define _(string) (string)
|
47
|
+
#endif
|
48
|
+
|
49
|
+
/* Number of ticks per second */
|
50
|
+
unsigned int hz;
|
51
|
+
/* Number of bit shifts to convert pages to kB */
|
52
|
+
unsigned int kb_shift;
|
53
|
+
|
54
|
+
/*
|
55
|
+
***************************************************************************
|
56
|
+
* Get local date and time.
|
57
|
+
*
|
58
|
+
* OUT:
|
59
|
+
* @rectime Current local date and time.
|
60
|
+
*
|
61
|
+
* RETURNS:
|
62
|
+
* Value of time in seconds since the Epoch.
|
63
|
+
***************************************************************************
|
64
|
+
*/
|
65
|
+
time_t get_localtime(struct tm *rectime)
|
66
|
+
{
|
67
|
+
time_t timer;
|
68
|
+
struct tm *ltm;
|
69
|
+
|
70
|
+
time(&timer);
|
71
|
+
ltm = localtime(&timer);
|
72
|
+
|
73
|
+
*rectime = *ltm;
|
74
|
+
return timer;
|
75
|
+
}
|
76
|
+
|
77
|
+
/*
|
78
|
+
***************************************************************************
|
79
|
+
* Get date and time expressed in UTC.
|
80
|
+
*
|
81
|
+
* OUT:
|
82
|
+
* @rectime Current date and time expressed in UTC.
|
83
|
+
*
|
84
|
+
* RETURNS:
|
85
|
+
* Value of time in seconds since the Epoch.
|
86
|
+
***************************************************************************
|
87
|
+
*/
|
88
|
+
time_t get_gmtime(struct tm *rectime)
|
89
|
+
{
|
90
|
+
time_t timer;
|
91
|
+
struct tm *ltm;
|
92
|
+
|
93
|
+
time(&timer);
|
94
|
+
ltm = gmtime(&timer);
|
95
|
+
|
96
|
+
*rectime = *ltm;
|
97
|
+
return timer;
|
98
|
+
}
|
99
|
+
|
100
|
+
/*
|
101
|
+
***************************************************************************
|
102
|
+
* Get date and time and take into account <ENV_TIME_DEFTM> variable.
|
103
|
+
*
|
104
|
+
* OUT:
|
105
|
+
* @rectime Current date and time.
|
106
|
+
*
|
107
|
+
* RETURNS:
|
108
|
+
* Value of time in seconds since the Epoch.
|
109
|
+
***************************************************************************
|
110
|
+
*/
|
111
|
+
time_t get_time(struct tm *rectime)
|
112
|
+
{
|
113
|
+
static int utc = 0;
|
114
|
+
char *e;
|
115
|
+
|
116
|
+
if (!utc) {
|
117
|
+
/* Read environment variable value once */
|
118
|
+
if ((e = getenv(ENV_TIME_DEFTM)) != NULL) {
|
119
|
+
utc = !strcmp(e, K_UTC);
|
120
|
+
}
|
121
|
+
utc++;
|
122
|
+
}
|
123
|
+
|
124
|
+
if (utc == 2)
|
125
|
+
return get_gmtime(rectime);
|
126
|
+
else
|
127
|
+
return get_localtime(rectime);
|
128
|
+
}
|
129
|
+
|
130
|
+
/*
|
131
|
+
***************************************************************************
|
132
|
+
* Count number of comma-separated values in arguments list. For example,
|
133
|
+
* the number will be 3 for the list "foobar -p 1 -p 2,3,4 2 5".
|
134
|
+
*
|
135
|
+
* IN:
|
136
|
+
* @arg_c Number of arguments in the list.
|
137
|
+
* @arg_v Arguments list.
|
138
|
+
*
|
139
|
+
* RETURNS:
|
140
|
+
* Number of comma-separated values in the list.
|
141
|
+
***************************************************************************
|
142
|
+
*/
|
143
|
+
int count_csvalues(int arg_c, char **arg_v)
|
144
|
+
{
|
145
|
+
int opt = 1;
|
146
|
+
int nr = 0;
|
147
|
+
char *t;
|
148
|
+
|
149
|
+
while (opt < arg_c) {
|
150
|
+
if (strchr(arg_v[opt], ',')) {
|
151
|
+
for (t = arg_v[opt]; t; t = strchr(t + 1, ',')) {
|
152
|
+
nr++;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
opt++;
|
156
|
+
}
|
157
|
+
|
158
|
+
return nr;
|
159
|
+
}
|
160
|
+
|
161
|
+
/*
|
162
|
+
***************************************************************************
|
163
|
+
* Look for partitions of a given block device in /sys filesystem.
|
164
|
+
*
|
165
|
+
* IN:
|
166
|
+
* @dev_name Name of the block device.
|
167
|
+
*
|
168
|
+
* RETURNS:
|
169
|
+
* Number of partitions for the given block device.
|
170
|
+
***************************************************************************
|
171
|
+
*/
|
172
|
+
int get_dev_part_nr(char *dev_name)
|
173
|
+
{
|
174
|
+
DIR *dir;
|
175
|
+
struct dirent *drd;
|
176
|
+
char dfile[MAX_PF_NAME], line[MAX_PF_NAME];
|
177
|
+
int part = 0;
|
178
|
+
|
179
|
+
snprintf(dfile, MAX_PF_NAME, "%s/%s", SYSFS_BLOCK, dev_name);
|
180
|
+
dfile[MAX_PF_NAME - 1] = '\0';
|
181
|
+
|
182
|
+
/* Open current device directory in /sys/block */
|
183
|
+
if ((dir = opendir(dfile)) == NULL)
|
184
|
+
return 0;
|
185
|
+
|
186
|
+
/* Get current file entry */
|
187
|
+
while ((drd = readdir(dir)) != NULL) {
|
188
|
+
if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
|
189
|
+
continue;
|
190
|
+
snprintf(line, MAX_PF_NAME, "%s/%s/%s", dfile, drd->d_name, S_STAT);
|
191
|
+
line[MAX_PF_NAME - 1] = '\0';
|
192
|
+
|
193
|
+
/* Try to guess if current entry is a directory containing a stat file */
|
194
|
+
if (!access(line, R_OK)) {
|
195
|
+
/* Yep... */
|
196
|
+
part++;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
/* Close directory */
|
201
|
+
closedir(dir);
|
202
|
+
|
203
|
+
return part;
|
204
|
+
}
|
205
|
+
|
206
|
+
/*
|
207
|
+
***************************************************************************
|
208
|
+
* Look for block devices present in /sys/ filesystem:
|
209
|
+
* Check first that sysfs is mounted (done by trying to open /sys/block
|
210
|
+
* directory), then find number of devices registered.
|
211
|
+
*
|
212
|
+
* IN:
|
213
|
+
* @display_partitions Set to TRUE if partitions must also be counted.
|
214
|
+
*
|
215
|
+
* RETURNS:
|
216
|
+
* Total number of block devices (and partitions if @display_partitions was
|
217
|
+
* set).
|
218
|
+
***************************************************************************
|
219
|
+
*/
|
220
|
+
int get_sysfs_dev_nr(int display_partitions)
|
221
|
+
{
|
222
|
+
DIR *dir;
|
223
|
+
struct dirent *drd;
|
224
|
+
char line[MAX_PF_NAME];
|
225
|
+
int dev = 0;
|
226
|
+
|
227
|
+
/* Open /sys/block directory */
|
228
|
+
if ((dir = opendir(SYSFS_BLOCK)) == NULL)
|
229
|
+
/* sysfs not mounted, or perhaps this is an old kernel */
|
230
|
+
return 0;
|
231
|
+
|
232
|
+
/* Get current file entry in /sys/block directory */
|
233
|
+
while ((drd = readdir(dir)) != NULL) {
|
234
|
+
if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
|
235
|
+
continue;
|
236
|
+
snprintf(line, MAX_PF_NAME, "%s/%s/%s", SYSFS_BLOCK, drd->d_name, S_STAT);
|
237
|
+
line[MAX_PF_NAME - 1] = '\0';
|
238
|
+
|
239
|
+
/* Try to guess if current entry is a directory containing a stat file */
|
240
|
+
if (!access(line, R_OK)) {
|
241
|
+
/* Yep... */
|
242
|
+
dev++;
|
243
|
+
|
244
|
+
if (display_partitions) {
|
245
|
+
/* We also want the number of partitions for this device */
|
246
|
+
dev += get_dev_part_nr(drd->d_name);
|
247
|
+
}
|
248
|
+
}
|
249
|
+
}
|
250
|
+
|
251
|
+
/* Close /sys/block directory */
|
252
|
+
closedir(dir);
|
253
|
+
|
254
|
+
return dev;
|
255
|
+
}
|
256
|
+
|
257
|
+
/*
|
258
|
+
***************************************************************************
|
259
|
+
* Read /proc/devices file and get device-mapper major number.
|
260
|
+
* If device-mapper entry is not found in file, use DEFAULT_DEMAP_MAJOR
|
261
|
+
* number.
|
262
|
+
*
|
263
|
+
* RETURNS:
|
264
|
+
* Device-mapper major number.
|
265
|
+
***************************************************************************
|
266
|
+
*/
|
267
|
+
unsigned int get_devmap_major(void)
|
268
|
+
{
|
269
|
+
FILE *fp;
|
270
|
+
char line[128];
|
271
|
+
unsigned int dm_major = DEFAULT_DEVMAP_MAJOR;
|
272
|
+
|
273
|
+
if ((fp = fopen(DEVICES, "r")) == NULL)
|
274
|
+
return dm_major;
|
275
|
+
|
276
|
+
while (fgets(line, 128, fp) != NULL) {
|
277
|
+
|
278
|
+
if (strstr(line, "device-mapper")) {
|
279
|
+
/* Read device-mapper major number */
|
280
|
+
sscanf(line, "%u", &dm_major);
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
fclose(fp);
|
285
|
+
|
286
|
+
return dm_major;
|
287
|
+
}
|
288
|
+
|
289
|
+
/*
|
290
|
+
***************************************************************************
|
291
|
+
* Print banner.
|
292
|
+
*
|
293
|
+
* IN:
|
294
|
+
* @rectime Date and time to display.
|
295
|
+
* @sysname System name to display.
|
296
|
+
* @release System release number to display.
|
297
|
+
* @nodename Hostname to display.
|
298
|
+
* @machine Machine architecture to display.
|
299
|
+
* @cpu_nr Number of CPU.
|
300
|
+
*
|
301
|
+
* RETURNS:
|
302
|
+
* TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise.
|
303
|
+
***************************************************************************
|
304
|
+
*/
|
305
|
+
int print_gal_header(struct tm *rectime, char *sysname, char *release,
|
306
|
+
char *nodename, char *machine, int cpu_nr)
|
307
|
+
{
|
308
|
+
char cur_date[64];
|
309
|
+
char *e;
|
310
|
+
int rc = 0;
|
311
|
+
|
312
|
+
if (rectime == NULL) {
|
313
|
+
strcpy(cur_date, "?/?/?");
|
314
|
+
}
|
315
|
+
else if (((e = getenv(ENV_TIME_FMT)) != NULL) && !strcmp(e, K_ISO)) {
|
316
|
+
strftime(cur_date, sizeof(cur_date), "%Y-%m-%d", rectime);
|
317
|
+
rc = 1;
|
318
|
+
}
|
319
|
+
else {
|
320
|
+
strftime(cur_date, sizeof(cur_date), "%x", rectime);
|
321
|
+
}
|
322
|
+
|
323
|
+
printf("%s %s (%s) \t%s \t_%s_\t(%d CPU)\n", sysname, release, nodename,
|
324
|
+
cur_date, machine, cpu_nr);
|
325
|
+
|
326
|
+
return rc;
|
327
|
+
}
|
328
|
+
|
329
|
+
#ifdef USE_NLS
|
330
|
+
/*
|
331
|
+
***************************************************************************
|
332
|
+
* Init National Language Support.
|
333
|
+
***************************************************************************
|
334
|
+
*/
|
335
|
+
void init_nls(void)
|
336
|
+
{
|
337
|
+
setlocale(LC_MESSAGES, "");
|
338
|
+
setlocale(LC_CTYPE, "");
|
339
|
+
setlocale(LC_TIME, "");
|
340
|
+
setlocale(LC_NUMERIC, "");
|
341
|
+
|
342
|
+
bindtextdomain(PACKAGE, LOCALEDIR);
|
343
|
+
textdomain(PACKAGE);
|
344
|
+
}
|
345
|
+
#endif
|
346
|
+
|
347
|
+
/*
|
348
|
+
***************************************************************************
|
349
|
+
* Get number of rows for current window.
|
350
|
+
*
|
351
|
+
* RETURNS:
|
352
|
+
* Number of rows.
|
353
|
+
***************************************************************************
|
354
|
+
*/
|
355
|
+
int get_win_height(void)
|
356
|
+
{
|
357
|
+
struct winsize win;
|
358
|
+
/*
|
359
|
+
* This default value will be used whenever STDOUT
|
360
|
+
* is redirected to a pipe or a file
|
361
|
+
*/
|
362
|
+
int rows = 3600 * 24;
|
363
|
+
|
364
|
+
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1) {
|
365
|
+
if (win.ws_row > 2) {
|
366
|
+
rows = win.ws_row - 2;
|
367
|
+
}
|
368
|
+
}
|
369
|
+
return rows;
|
370
|
+
}
|
371
|
+
|
372
|
+
/*
|
373
|
+
***************************************************************************
|
374
|
+
* Remove /dev from path name.
|
375
|
+
*
|
376
|
+
* IN:
|
377
|
+
* @name Device name (may begins with "/dev/")
|
378
|
+
*
|
379
|
+
* RETURNS:
|
380
|
+
* Device basename.
|
381
|
+
***************************************************************************
|
382
|
+
*/
|
383
|
+
char *device_name(char *name)
|
384
|
+
{
|
385
|
+
if (!strncmp(name, "/dev/", 5))
|
386
|
+
return name + 5;
|
387
|
+
|
388
|
+
return name;
|
389
|
+
}
|
390
|
+
|
391
|
+
/*
|
392
|
+
***************************************************************************
|
393
|
+
* Test whether given name is a device or a partition, using sysfs.
|
394
|
+
* This is more straightforward that using ioc_iswhole() function from
|
395
|
+
* ioconf.c which should be used only with kernels that don't have sysfs.
|
396
|
+
*
|
397
|
+
* IN:
|
398
|
+
* @name Device or partition name.
|
399
|
+
*
|
400
|
+
* RETURNS:
|
401
|
+
* TRUE if @name is a (whole) device.
|
402
|
+
***************************************************************************
|
403
|
+
*/
|
404
|
+
int is_device(char *name)
|
405
|
+
{
|
406
|
+
char syspath[PATH_MAX];
|
407
|
+
char *slash;
|
408
|
+
|
409
|
+
/* Some devices may have a slash in their name (eg. cciss/c0d0...) */
|
410
|
+
while ((slash = strchr(name, '/'))) {
|
411
|
+
*slash = '!';
|
412
|
+
}
|
413
|
+
snprintf(syspath, sizeof(syspath), "%s/%s", SYSFS_BLOCK, name);
|
414
|
+
|
415
|
+
return !(access(syspath, F_OK));
|
416
|
+
}
|
417
|
+
|
418
|
+
/*
|
419
|
+
***************************************************************************
|
420
|
+
* Get page shift in kB.
|
421
|
+
***************************************************************************
|
422
|
+
*/
|
423
|
+
void get_kb_shift(void)
|
424
|
+
{
|
425
|
+
int shift = 0;
|
426
|
+
long size;
|
427
|
+
|
428
|
+
/* One can also use getpagesize() to get the size of a page */
|
429
|
+
if ((size = sysconf(_SC_PAGESIZE)) == -1) {
|
430
|
+
perror("sysconf");
|
431
|
+
}
|
432
|
+
|
433
|
+
size >>= 10; /* Assume that a page has a minimum size of 1 kB */
|
434
|
+
|
435
|
+
while (size > 1) {
|
436
|
+
shift++;
|
437
|
+
size >>= 1;
|
438
|
+
}
|
439
|
+
|
440
|
+
kb_shift = (unsigned int) shift;
|
441
|
+
}
|
442
|
+
|
443
|
+
/*
|
444
|
+
***************************************************************************
|
445
|
+
* Get number of clock ticks per second.
|
446
|
+
***************************************************************************
|
447
|
+
*/
|
448
|
+
void get_HZ(void)
|
449
|
+
{
|
450
|
+
long ticks;
|
451
|
+
|
452
|
+
if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
|
453
|
+
perror("sysconf");
|
454
|
+
}
|
455
|
+
|
456
|
+
hz = (unsigned int) ticks;
|
457
|
+
}
|
458
|
+
|
459
|
+
/*
|
460
|
+
***************************************************************************
|
461
|
+
* Handle overflow conditions properly for counters which are read as
|
462
|
+
* unsigned long long, but which can be unsigned long long or
|
463
|
+
* unsigned long only depending on the kernel version used.
|
464
|
+
* @value1 and @value2 being two values successively read for this
|
465
|
+
* counter, if @value2 < @value1 and @value1 <= 0xffffffff, then we can
|
466
|
+
* assume that the counter's type was unsigned long and has overflown, and
|
467
|
+
* so the difference @value2 - @value1 must be casted to this type.
|
468
|
+
* NOTE: These functions should no longer be necessary to handle a particular
|
469
|
+
* stat counter when we can assume that everybody is using a recent kernel
|
470
|
+
* (defining this counter as unsigned long long).
|
471
|
+
***************************************************************************
|
472
|
+
*/
|
473
|
+
double ll_sp_value(unsigned long long value1, unsigned long long value2,
|
474
|
+
unsigned long long itv)
|
475
|
+
{
|
476
|
+
if ((value2 < value1) && (value1 <= 0xffffffff))
|
477
|
+
/* Counter's type was unsigned long and has overflown */
|
478
|
+
return ((double) ((value2 - value1) & 0xffffffff)) / itv * 100;
|
479
|
+
else
|
480
|
+
return SP_VALUE(value1, value2, itv);
|
481
|
+
}
|
482
|
+
|
483
|
+
double ll_s_value(unsigned long long value1, unsigned long long value2,
|
484
|
+
unsigned long long itv)
|
485
|
+
{
|
486
|
+
if ((value2 < value1) && (value1 <= 0xffffffff))
|
487
|
+
/* Counter's type was unsigned long and has overflown */
|
488
|
+
return ((double) ((value2 - value1) & 0xffffffff)) / itv * HZ;
|
489
|
+
else
|
490
|
+
return S_VALUE(value1, value2, itv);
|
491
|
+
}
|
492
|
+
|
493
|
+
/*
|
494
|
+
***************************************************************************
|
495
|
+
* Compute time interval.
|
496
|
+
*
|
497
|
+
* IN:
|
498
|
+
* @prev_uptime Previous uptime value in jiffies.
|
499
|
+
* @curr_uptime Current uptime value in jiffies.
|
500
|
+
*
|
501
|
+
* RETURNS:
|
502
|
+
* Interval of time in jiffies.
|
503
|
+
***************************************************************************
|
504
|
+
*/
|
505
|
+
unsigned long long get_interval(unsigned long long prev_uptime,
|
506
|
+
unsigned long long curr_uptime)
|
507
|
+
{
|
508
|
+
unsigned long long itv;
|
509
|
+
|
510
|
+
/* prev_time=0 when displaying stats since system startup */
|
511
|
+
itv = curr_uptime - prev_uptime;
|
512
|
+
|
513
|
+
if (!itv) { /* Paranoia checking */
|
514
|
+
itv = 1;
|
515
|
+
}
|
516
|
+
|
517
|
+
return itv;
|
518
|
+
}
|
519
|
+
|
520
|
+
/*
|
521
|
+
***************************************************************************
|
522
|
+
* Since ticks may vary slightly from CPU to CPU, we'll want
|
523
|
+
* to recalculate itv based on this CPU's tick count, rather
|
524
|
+
* than that reported by the "cpu" line. Otherwise we
|
525
|
+
* occasionally end up with slightly skewed figures, with
|
526
|
+
* the skew being greater as the time interval grows shorter.
|
527
|
+
*
|
528
|
+
* IN:
|
529
|
+
* @scc Current sample statistics for current CPU.
|
530
|
+
* @scp Previous sample statistics for current CPU.
|
531
|
+
*
|
532
|
+
* RETURNS:
|
533
|
+
* Interval of time based on current CPU.
|
534
|
+
***************************************************************************
|
535
|
+
*/
|
536
|
+
unsigned long long get_per_cpu_interval(struct stats_cpu *scc,
|
537
|
+
struct stats_cpu *scp)
|
538
|
+
{
|
539
|
+
/* Don't take cpu_guest into account because cpu_user already includes it */
|
540
|
+
return ((scc->cpu_user + scc->cpu_nice +
|
541
|
+
scc->cpu_sys + scc->cpu_iowait +
|
542
|
+
scc->cpu_idle + scc->cpu_steal +
|
543
|
+
scc->cpu_hardirq + scc->cpu_softirq) -
|
544
|
+
(scp->cpu_user + scp->cpu_nice +
|
545
|
+
scp->cpu_sys + scp->cpu_iowait +
|
546
|
+
scp->cpu_idle + scp->cpu_steal +
|
547
|
+
scp->cpu_hardirq + scp->cpu_softirq));
|
548
|
+
}
|
549
|
+
|
550
|
+
/*
|
551
|
+
***************************************************************************
|
552
|
+
* Unhandled situation: Panic and exit.
|
553
|
+
*
|
554
|
+
* IN:
|
555
|
+
* @function Function name where situation occured.
|
556
|
+
* @error_code Error code.
|
557
|
+
***************************************************************************
|
558
|
+
*/
|
559
|
+
void sysstat_panic(const char *function, int error_code)
|
560
|
+
{
|
561
|
+
fprintf(stderr, "sysstat: %s[%d]: Last chance handler...\n",
|
562
|
+
function, error_code);
|
563
|
+
exit(1);
|
564
|
+
}
|
565
|
+
|
566
|
+
/*
|
567
|
+
***************************************************************************
|
568
|
+
* Count number of bits set in an array.
|
569
|
+
*
|
570
|
+
* IN:
|
571
|
+
* @ptr Pointer to array.
|
572
|
+
* @size Size of array in bytes.
|
573
|
+
*
|
574
|
+
* RETURNS:
|
575
|
+
* Number of bits set in the array.
|
576
|
+
***************************************************************************
|
577
|
+
*/
|
578
|
+
int count_bits(void *ptr, int size)
|
579
|
+
{
|
580
|
+
int nr = 0, i, k;
|
581
|
+
char *p;
|
582
|
+
|
583
|
+
p = ptr;
|
584
|
+
for (i = 0; i < size; i++, p++) {
|
585
|
+
k = 0x80;
|
586
|
+
while (k) {
|
587
|
+
if (*p & k)
|
588
|
+
nr++;
|
589
|
+
k >>= 1;
|
590
|
+
}
|
591
|
+
}
|
592
|
+
|
593
|
+
return nr;
|
594
|
+
}
|
595
|
+
|
596
|
+
/*
|
597
|
+
***************************************************************************
|
598
|
+
* Compute "extended" device statistics (service time, etc.).
|
599
|
+
*
|
600
|
+
* IN:
|
601
|
+
* @sdc Structure with current device statistics.
|
602
|
+
* @sdp Structure with previous device statistics.
|
603
|
+
* @itv Interval of time in jiffies.
|
604
|
+
*
|
605
|
+
* OUT:
|
606
|
+
* @xds Structure with extended statistics.
|
607
|
+
***************************************************************************
|
608
|
+
*/
|
609
|
+
void compute_ext_disk_stats(struct stats_disk *sdc, struct stats_disk *sdp,
|
610
|
+
unsigned long long itv, struct ext_disk_stats *xds)
|
611
|
+
{
|
612
|
+
double tput
|
613
|
+
= ((double) (sdc->nr_ios - sdp->nr_ios)) * HZ / itv;
|
614
|
+
|
615
|
+
xds->util = S_VALUE(sdp->tot_ticks, sdc->tot_ticks, itv);
|
616
|
+
xds->svctm = tput ? xds->util / tput : 0.0;
|
617
|
+
/*
|
618
|
+
* Kernel gives ticks already in milliseconds for all platforms
|
619
|
+
* => no need for further scaling.
|
620
|
+
*/
|
621
|
+
xds->await = (sdc->nr_ios - sdp->nr_ios) ?
|
622
|
+
((sdc->rd_ticks - sdp->rd_ticks) + (sdc->wr_ticks - sdp->wr_ticks)) /
|
623
|
+
((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
|
624
|
+
xds->arqsz = (sdc->nr_ios - sdp->nr_ios) ?
|
625
|
+
((sdc->rd_sect - sdp->rd_sect) + (sdc->wr_sect - sdp->wr_sect)) /
|
626
|
+
((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
|
627
|
+
}
|