devstat.c (50476) | devstat.c (81133) |
---|---|
1/* 2 * Copyright (c) 1997, 1998 Kenneth D. Merry. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 11 unchanged lines hidden (view full) --- 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * | 1/* 2 * Copyright (c) 1997, 1998 Kenneth D. Merry. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 11 unchanged lines hidden (view full) --- 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * |
28 * $FreeBSD: head/lib/libdevstat/devstat.c 50476 1999-08-28 00:22:10Z peter $ | 28 * $FreeBSD: head/lib/libdevstat/devstat.c 81133 2001-08-04 18:25:48Z tmm $ |
29 */ 30 31#include <sys/types.h> 32#include <sys/sysctl.h> 33#include <sys/errno.h> 34#include <sys/dkstat.h> | 29 */ 30 31#include <sys/types.h> 32#include <sys/sysctl.h> 33#include <sys/errno.h> 34#include <sys/dkstat.h> |
35#include <sys/queue.h> |
|
35 36#include <ctype.h> 37#include <err.h> | 36 37#include <ctype.h> 38#include <err.h> |
39#include <fcntl.h> 40#include <limits.h> |
|
38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> | 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> |
44#include <stdarg.h> 45#include <kvm.h> |
|
41 42#include "devstat.h" 43 | 46 47#include "devstat.h" 48 |
49typedef enum { 50 DEVSTAT_ARG_NOTYPE, 51 DEVSTAT_ARG_UINT64, 52 DEVSTAT_ARG_LD 53} devstat_arg_type; 54 |
|
44char devstat_errbuf[DEVSTAT_ERRBUF_SIZE]; 45 46/* 47 * Table to match descriptive strings with device types. These are in 48 * order from most common to least common to speed search time. 49 */ 50struct devstat_match_table match_table[] = { 51 {"da", DEVSTAT_TYPE_DIRECT, DEVSTAT_MATCH_TYPE}, --- 11 unchanged lines hidden (view full) --- 63 {"printer", DEVSTAT_TYPE_PRINTER, DEVSTAT_MATCH_TYPE}, 64 {"floppy", DEVSTAT_TYPE_FLOPPY, DEVSTAT_MATCH_TYPE}, 65 {"proc", DEVSTAT_TYPE_PROCESSOR, DEVSTAT_MATCH_TYPE}, 66 {"comm", DEVSTAT_TYPE_COMM, DEVSTAT_MATCH_TYPE}, 67 {"enclosure", DEVSTAT_TYPE_ENCLOSURE, DEVSTAT_MATCH_TYPE}, 68 {NULL, 0, 0} 69}; 70 | 55char devstat_errbuf[DEVSTAT_ERRBUF_SIZE]; 56 57/* 58 * Table to match descriptive strings with device types. These are in 59 * order from most common to least common to speed search time. 60 */ 61struct devstat_match_table match_table[] = { 62 {"da", DEVSTAT_TYPE_DIRECT, DEVSTAT_MATCH_TYPE}, --- 11 unchanged lines hidden (view full) --- 74 {"printer", DEVSTAT_TYPE_PRINTER, DEVSTAT_MATCH_TYPE}, 75 {"floppy", DEVSTAT_TYPE_FLOPPY, DEVSTAT_MATCH_TYPE}, 76 {"proc", DEVSTAT_TYPE_PROCESSOR, DEVSTAT_MATCH_TYPE}, 77 {"comm", DEVSTAT_TYPE_COMM, DEVSTAT_MATCH_TYPE}, 78 {"enclosure", DEVSTAT_TYPE_ENCLOSURE, DEVSTAT_MATCH_TYPE}, 79 {NULL, 0, 0} 80}; 81 |
82struct devstat_args { 83 devstat_metric metric; 84 devstat_arg_type argtype; 85} devstat_arg_list[] = { 86 { DSM_NONE, DEVSTAT_ARG_NOTYPE }, 87 { DSM_TOTAL_BYTES, DEVSTAT_ARG_UINT64 }, 88 { DSM_TOTAL_BYTES_READ, DEVSTAT_ARG_UINT64 }, 89 { DSM_TOTAL_BYTES_WRITE, DEVSTAT_ARG_UINT64 }, 90 { DSM_TOTAL_TRANSFERS, DEVSTAT_ARG_UINT64 }, 91 { DSM_TOTAL_TRANSFERS_READ, DEVSTAT_ARG_UINT64 }, 92 { DSM_TOTAL_TRANSFERS_WRITE, DEVSTAT_ARG_UINT64 }, 93 { DSM_TOTAL_TRANSFERS_OTHER, DEVSTAT_ARG_UINT64 }, 94 { DSM_TOTAL_BLOCKS, DEVSTAT_ARG_UINT64 }, 95 { DSM_TOTAL_BLOCKS_READ, DEVSTAT_ARG_UINT64 }, 96 { DSM_TOTAL_BLOCKS_WRITE, DEVSTAT_ARG_UINT64 }, 97 { DSM_KB_PER_TRANSFER, DEVSTAT_ARG_LD }, 98 { DSM_KB_PER_TRANSFER_READ, DEVSTAT_ARG_LD }, 99 { DSM_KB_PER_TRANSFER_WRITE, DEVSTAT_ARG_LD }, 100 { DSM_TRANSFERS_PER_SECOND, DEVSTAT_ARG_LD }, 101 { DSM_TRANSFERS_PER_SECOND_READ, DEVSTAT_ARG_LD }, 102 { DSM_TRANSFERS_PER_SECOND_WRITE, DEVSTAT_ARG_LD }, 103 { DSM_TRANSFERS_PER_SECOND_OTHER, DEVSTAT_ARG_LD }, 104 { DSM_MB_PER_SECOND, DEVSTAT_ARG_LD }, 105 { DSM_MB_PER_SECOND_READ, DEVSTAT_ARG_LD }, 106 { DSM_MB_PER_SECOND_WRITE, DEVSTAT_ARG_LD }, 107 { DSM_BLOCKS_PER_SECOND, DEVSTAT_ARG_LD }, 108 { DSM_BLOCKS_PER_SECOND_READ, DEVSTAT_ARG_LD }, 109 { DSM_BLOCKS_PER_SECOND_WRITE, DEVSTAT_ARG_LD }, 110 { DSM_MS_PER_TRANSACTION, DEVSTAT_ARG_LD }, 111 { DSM_MS_PER_TRANSACTION_READ, DEVSTAT_ARG_LD }, 112 { DSM_MS_PER_TRANSACTION_WRITE, DEVSTAT_ARG_LD } 113}; 114 115static char *namelist[] = { 116#define X_NUMDEVS 0 117 "_devstat_num_devs", 118#define X_GENERATION 1 119 "_devstat_generation", 120#define X_VERSION 2 121 "_devstat_version", 122#define X_DEVICE_STATQ 3 123 "_device_statq", 124#define X_END 4 125}; 126 |
|
71/* 72 * Local function declarations. 73 */ 74static int compare_select(const void *arg1, const void *arg2); | 127/* 128 * Local function declarations. 129 */ 130static int compare_select(const void *arg1, const void *arg2); |
131static int readkmem(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes); 132static int readkmem_nl(kvm_t *kd, char *name, void *buf, size_t nbytes); 133static char *get_devstat_kvm(kvm_t *kd); |
|
75 | 134 |
135#define KREADNL(kd, var, val) \ 136 readkmem_nl(kd, namelist[var], &val, sizeof(val)) 137 |
|
76int | 138int |
77getnumdevs(void) | 139devstat_getnumdevs(kvm_t *kd) |
78{ 79 size_t numdevsize; 80 int numdevs; | 140{ 141 size_t numdevsize; 142 int numdevs; |
81 char *func_name = "getnumdevs"; | 143 char *func_name = "devstat_getnumdevs"; |
82 83 numdevsize = sizeof(int); 84 85 /* 86 * Find out how many devices we have in the system. 87 */ | 144 145 numdevsize = sizeof(int); 146 147 /* 148 * Find out how many devices we have in the system. 149 */ |
88 if (sysctlbyname("kern.devstat.numdevs", &numdevs, 89 &numdevsize, NULL, 0) == -1) { 90 sprintf(devstat_errbuf, "%s: error getting number of devices\n" 91 "%s: %s", func_name, func_name, strerror(errno)); 92 return(-1); 93 } else 94 return(numdevs); | 150 if (kd == NULL) { 151 if (sysctlbyname("kern.devstat.numdevs", &numdevs, 152 &numdevsize, NULL, 0) == -1) { 153 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 154 "%s: error getting number of devices\n" 155 "%s: %s", func_name, func_name, 156 strerror(errno)); 157 return(-1); 158 } else 159 return(numdevs); 160 } else { 161 if (KREADNL(kd, X_NUMDEVS, numdevs) == -1) 162 return(-1); 163 else 164 return(numdevs); 165 } |
95} 96 97/* 98 * This is an easy way to get the generation number, but the generation is 99 * supplied in a more atmoic manner by the kern.devstat.all sysctl. 100 * Because this generation sysctl is separate from the statistics sysctl, 101 * the device list and the generation could change between the time that 102 * this function is called and the device list is retreived. 103 */ 104long | 166} 167 168/* 169 * This is an easy way to get the generation number, but the generation is 170 * supplied in a more atmoic manner by the kern.devstat.all sysctl. 171 * Because this generation sysctl is separate from the statistics sysctl, 172 * the device list and the generation could change between the time that 173 * this function is called and the device list is retreived. 174 */ 175long |
105getgeneration(void) | 176devstat_getgeneration(kvm_t *kd) |
106{ 107 size_t gensize; 108 long generation; | 177{ 178 size_t gensize; 179 long generation; |
109 char *func_name = "getgeneration"; | 180 char *func_name = "devstat_getgeneration"; |
110 111 gensize = sizeof(long); 112 113 /* 114 * Get the current generation number. 115 */ | 181 182 gensize = sizeof(long); 183 184 /* 185 * Get the current generation number. 186 */ |
116 if (sysctlbyname("kern.devstat.generation", &generation, 117 &gensize, NULL, 0) == -1) { 118 sprintf(devstat_errbuf,"%s: error getting devstat generation\n" 119 "%s: %s", func_name, func_name, strerror(errno)); 120 return(-1); 121 } else 122 return(generation); | 187 if (kd == NULL) { 188 if (sysctlbyname("kern.devstat.generation", &generation, 189 &gensize, NULL, 0) == -1) { 190 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 191 "%s: error getting devstat generation\n%s: %s", 192 func_name, func_name, strerror(errno)); 193 return(-1); 194 } else 195 return(generation); 196 } else { 197 if (KREADNL(kd, X_GENERATION, generation) == -1) 198 return(-1); 199 else 200 return(generation); 201 } |
123} 124 125/* 126 * Get the current devstat version. The return value of this function 127 * should be compared with DEVSTAT_VERSION, which is defined in 128 * sys/devicestat.h. This will enable userland programs to determine 129 * whether they are out of sync with the kernel. 130 */ 131int | 202} 203 204/* 205 * Get the current devstat version. The return value of this function 206 * should be compared with DEVSTAT_VERSION, which is defined in 207 * sys/devicestat.h. This will enable userland programs to determine 208 * whether they are out of sync with the kernel. 209 */ 210int |
132getversion(void) | 211devstat_getversion(kvm_t *kd) |
133{ 134 size_t versize; 135 int version; | 212{ 213 size_t versize; 214 int version; |
136 char *func_name = "getversion"; | 215 char *func_name = "devstat_getversion"; |
137 138 versize = sizeof(int); 139 140 /* 141 * Get the current devstat version. 142 */ | 216 217 versize = sizeof(int); 218 219 /* 220 * Get the current devstat version. 221 */ |
143 if (sysctlbyname("kern.devstat.version", &version, &versize, 144 NULL, 0) == -1) { 145 sprintf(devstat_errbuf, "%s: error getting devstat version\n" 146 "%s: %s", func_name, func_name, strerror(errno)); 147 return(-1); 148 } else 149 return(version); | 222 if (kd == NULL) { 223 if (sysctlbyname("kern.devstat.version", &version, &versize, 224 NULL, 0) == -1) { 225 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 226 "%s: error getting devstat version\n%s: %s", 227 func_name, func_name, strerror(errno)); 228 return(-1); 229 } else 230 return(version); 231 } else { 232 if (KREADNL(kd, X_VERSION, version) == -1) 233 return(-1); 234 else 235 return(version); 236 } |
150} 151 152/* 153 * Check the devstat version we know about against the devstat version the 154 * kernel knows about. If they don't match, print an error into the 155 * devstat error buffer, and return -1. If they match, return 0. 156 */ 157int | 237} 238 239/* 240 * Check the devstat version we know about against the devstat version the 241 * kernel knows about. If they don't match, print an error into the 242 * devstat error buffer, and return -1. If they match, return 0. 243 */ 244int |
158checkversion(void) | 245devstat_checkversion(kvm_t *kd) |
159{ 160 int retval = 0; 161 int errlen = 0; | 246{ 247 int retval = 0; 248 int errlen = 0; |
162 char *func_name = "checkversion"; | 249 char *func_name = "devstat_checkversion"; |
163 int version; 164 | 250 int version; 251 |
165 version = getversion(); | 252 version = devstat_getversion(kd); |
166 167 if (version != DEVSTAT_VERSION) { 168 int buflen = 0; 169 char tmpstr[256]; 170 171 /* 172 * This is really pretty silly, but basically the idea is 173 * that if getversion() returns an error (i.e. -1), then it --- 47 unchanged lines hidden (view full) --- 221 * generation number. 222 * 223 * Return values: 224 * -1 -- error 225 * 0 -- device list is unchanged 226 * 1 -- device list has changed 227 */ 228int | 253 254 if (version != DEVSTAT_VERSION) { 255 int buflen = 0; 256 char tmpstr[256]; 257 258 /* 259 * This is really pretty silly, but basically the idea is 260 * that if getversion() returns an error (i.e. -1), then it --- 47 unchanged lines hidden (view full) --- 308 * generation number. 309 * 310 * Return values: 311 * -1 -- error 312 * 0 -- device list is unchanged 313 * 1 -- device list has changed 314 */ 315int |
229getdevs(struct statinfo *stats) | 316devstat_getdevs(kvm_t *kd, struct statinfo *stats) |
230{ 231 int error; 232 size_t dssize; 233 int oldnumdevs; 234 long oldgeneration; 235 int retval = 0; 236 struct devinfo *dinfo; | 317{ 318 int error; 319 size_t dssize; 320 int oldnumdevs; 321 long oldgeneration; 322 int retval = 0; 323 struct devinfo *dinfo; |
237 char *func_name = "getdevs"; | 324 char *func_name = "devstat_getdevs"; |
238 239 dinfo = stats->dinfo; 240 241 if (dinfo == NULL) { | 325 326 dinfo = stats->dinfo; 327 328 if (dinfo == NULL) { |
242 sprintf(devstat_errbuf, "%s: stats->dinfo was NULL", func_name); | 329 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 330 "%s: stats->dinfo was NULL", func_name); |
243 return(-1); 244 } 245 246 oldnumdevs = dinfo->numdevs; 247 oldgeneration = dinfo->generation; 248 | 331 return(-1); 332 } 333 334 oldnumdevs = dinfo->numdevs; 335 oldgeneration = dinfo->generation; 336 |
249 /* 250 * If this is our first time through, mem_ptr will be null. 251 */ 252 if (dinfo->mem_ptr == NULL) { 253 /* 254 * Get the number of devices. If it's negative, it's an 255 * error. Don't bother setting the error string, since 256 * getnumdevs() has already done that for us. 257 */ 258 if ((dinfo->numdevs = getnumdevs()) < 0) 259 return(-1); 260 261 /* 262 * The kern.devstat.all sysctl returns the current generation 263 * number, as well as all the devices. So we need four 264 * bytes more. 265 */ 266 dssize =(dinfo->numdevs * sizeof(struct devstat)) +sizeof(long); 267 dinfo->mem_ptr = (u_int8_t *)malloc(dssize); 268 } else 269 dssize =(dinfo->numdevs * sizeof(struct devstat)) +sizeof(long); 270 | |
271 /* Get the current time when we get the stats */ 272 gettimeofday(&stats->busy_time, NULL); 273 | 337 /* Get the current time when we get the stats */ 338 gettimeofday(&stats->busy_time, NULL); 339 |
274 /* 275 * Request all of the devices. We only really allow for one 276 * ENOMEM failure. It would, of course, be possible to just go in 277 * a loop and keep reallocing the device structure until we don't 278 * get ENOMEM back. I'm not sure it's worth it, though. If 279 * devices are being added to the system that quickly, maybe the 280 * user can just wait until all devices are added. 281 */ 282 if ((error = sysctlbyname("kern.devstat.all", dinfo->mem_ptr, 283 &dssize, NULL, 0)) == -1) { 284 /* 285 * If we get ENOMEM back, that means that there are 286 * more devices now, so we need to allocate more 287 * space for the device array. 288 */ 289 if (errno == ENOMEM) { | 340 if (kd == NULL) { 341 /* If this is our first time through, mem_ptr will be null. */ 342 if (dinfo->mem_ptr == NULL) { |
290 /* | 343 /* |
291 * No need to set the error string here, getnumdevs() 292 * will do that if it fails. | 344 * Get the number of devices. If it's negative, it's an 345 * error. Don't bother setting the error string, since 346 * getnumdevs() has already done that for us. |
293 */ 294 if ((dinfo->numdevs = getnumdevs()) < 0) 295 return(-1); | 347 */ 348 if ((dinfo->numdevs = getnumdevs()) < 0) 349 return(-1); |
296 | 350 351 /* 352 * The kern.devstat.all sysctl returns the current 353 * generation number, as well as all the devices. 354 * So we need four bytes more. 355 */ |
297 dssize = (dinfo->numdevs * sizeof(struct devstat)) + | 356 dssize = (dinfo->numdevs * sizeof(struct devstat)) + |
298 sizeof(long); 299 dinfo->mem_ptr = (u_int8_t *)realloc(dinfo->mem_ptr, 300 dssize); 301 if ((error = sysctlbyname("kern.devstat.all", 302 dinfo->mem_ptr, &dssize, NULL, 0)) == -1) { 303 sprintf(devstat_errbuf, | 357 sizeof(long); 358 dinfo->mem_ptr = (u_int8_t *)malloc(dssize); 359 } else 360 dssize = (dinfo->numdevs * sizeof(struct devstat)) + 361 sizeof(long); 362 363 /* 364 * Request all of the devices. We only really allow for one 365 * ENOMEM failure. It would, of course, be possible to just go 366 * in a loop and keep reallocing the device structure until we 367 * don't get ENOMEM back. I'm not sure it's worth it, though. 368 * If devices are being added to the system that quickly, maybe 369 * the user can just wait until all devices are added. 370 */ 371 if ((error = sysctlbyname("kern.devstat.all", dinfo->mem_ptr, 372 &dssize, NULL, 0)) == -1) { 373 /* 374 * If we get ENOMEM back, that means that there are 375 * more devices now, so we need to allocate more 376 * space for the device array. 377 */ 378 if (errno == ENOMEM) { 379 /* 380 * No need to set the error string here, 381 * getnumdevs() will do that if it fails. 382 */ 383 if ((dinfo->numdevs = getnumdevs()) < 0) 384 return(-1); 385 386 dssize = (dinfo->numdevs * 387 sizeof(struct devstat)) + sizeof(long); 388 dinfo->mem_ptr = (u_int8_t *) 389 realloc(dinfo->mem_ptr, dssize); 390 if ((error = sysctlbyname("kern.devstat.all", 391 dinfo->mem_ptr, &dssize, NULL, 0)) == -1) { 392 snprintf(devstat_errbuf, 393 sizeof(devstat_errbuf), 394 "%s: error getting device " 395 "stats\n%s: %s", func_name, 396 func_name, strerror(errno)); 397 return(-1); 398 } 399 } else { 400 snprintf(devstat_errbuf, sizeof(devstat_errbuf), |
304 "%s: error getting device stats\n" 305 "%s: %s", func_name, func_name, 306 strerror(errno)); 307 return(-1); 308 } | 401 "%s: error getting device stats\n" 402 "%s: %s", func_name, func_name, 403 strerror(errno)); 404 return(-1); 405 } |
309 } else { 310 sprintf(devstat_errbuf, 311 "%s: error getting device stats\n" 312 "%s: %s", func_name, func_name, 313 strerror(errno)); 314 return(-1); 315 } 316 } | 406 } |
317 | 407 |
408 } else { 409 /* 410 * This is of course non-atomic, but since we are working 411 * on a core dump, the generation is unlikely to change 412 */ 413 if ((dinfo->numdevs = getnumdevs()) == -1) 414 return(-1); 415 if ((dinfo->mem_ptr = get_devstat_kvm(kd)) == NULL) 416 return(-1); 417 } |
|
318 /* 319 * The sysctl spits out the generation as the first four bytes, 320 * then all of the device statistics structures. 321 */ 322 dinfo->generation = *(long *)dinfo->mem_ptr; 323 324 /* 325 * If the generation has changed, and if the current number of --- 84 unchanged lines hidden (view full) --- 410 * - the selection generation may be changed to match the current generation 411 * 412 * Return values: 413 * -1 -- error 414 * 0 -- selected devices are unchanged 415 * 1 -- selected devices changed 416 */ 417int | 418 /* 419 * The sysctl spits out the generation as the first four bytes, 420 * then all of the device statistics structures. 421 */ 422 dinfo->generation = *(long *)dinfo->mem_ptr; 423 424 /* 425 * If the generation has changed, and if the current number of --- 84 unchanged lines hidden (view full) --- 510 * - the selection generation may be changed to match the current generation 511 * 512 * Return values: 513 * -1 -- error 514 * 0 -- selected devices are unchanged 515 * 1 -- selected devices changed 516 */ 517int |
418selectdevs(struct device_selection **dev_select, int *num_selected, 419 int *num_selections, long *select_generation, 420 long current_generation, struct devstat *devices, int numdevs, 421 struct devstat_match *matches, int num_matches, 422 char **dev_selections, int num_dev_selections, 423 devstat_select_mode select_mode, int maxshowdevs, int perf_select) | 518devstat_selectdevs(struct device_selection **dev_select, int *num_selected, 519 int *num_selections, long *select_generation, 520 long current_generation, struct devstat *devices, 521 int numdevs, struct devstat_match *matches, int num_matches, 522 char **dev_selections, int num_dev_selections, 523 devstat_select_mode select_mode, int maxshowdevs, 524 int perf_select) |
424{ 425 register int i, j, k; 426 int init_selections = 0, init_selected_var = 0; 427 struct device_selection *old_dev_select = NULL; 428 int old_num_selections = 0, old_num_selected; 429 int selection_number = 0; 430 int changed = 0, found = 0; 431 --- 442 unchanged lines hidden (view full) --- 874 return(0); 875} 876 877/* 878 * Take a string with the general format "arg1,arg2,arg3", and build a 879 * device matching expression from it. 880 */ 881int | 525{ 526 register int i, j, k; 527 int init_selections = 0, init_selected_var = 0; 528 struct device_selection *old_dev_select = NULL; 529 int old_num_selections = 0, old_num_selected; 530 int selection_number = 0; 531 int changed = 0, found = 0; 532 --- 442 unchanged lines hidden (view full) --- 975 return(0); 976} 977 978/* 979 * Take a string with the general format "arg1,arg2,arg3", and build a 980 * device matching expression from it. 981 */ 982int |
882buildmatch(char *match_str, struct devstat_match **matches, int *num_matches) | 983devstat_buildmatch(char *match_str, struct devstat_match **matches, 984 int *num_matches) |
883{ 884 char *tstr[5]; 885 char **tempstr; 886 int num_args; 887 register int i, j; | 985{ 986 char *tstr[5]; 987 char **tempstr; 988 int num_args; 989 register int i, j; |
888 char *func_name = "buildmatch"; | 990 char *func_name = "devstat_buildmatch"; |
889 890 /* We can't do much without a string to parse */ 891 if (match_str == NULL) { | 991 992 /* We can't do much without a string to parse */ 993 if (match_str == NULL) { |
892 sprintf(devstat_errbuf, "%s: no match expression", func_name); | 994 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 995 "%s: no match expression", func_name); |
893 return(-1); 894 } 895 896 /* 897 * Break the (comma delimited) input string out into separate strings. 898 */ 899 for (tempstr = tstr, num_args = 0; 900 (*tempstr = strsep(&match_str, ",")) != NULL && (num_args < 5); 901 num_args++) 902 if (**tempstr != '\0') 903 if (++tempstr >= &tstr[5]) 904 break; 905 906 /* The user gave us too many type arguments */ 907 if (num_args > 3) { | 996 return(-1); 997 } 998 999 /* 1000 * Break the (comma delimited) input string out into separate strings. 1001 */ 1002 for (tempstr = tstr, num_args = 0; 1003 (*tempstr = strsep(&match_str, ",")) != NULL && (num_args < 5); 1004 num_args++) 1005 if (**tempstr != '\0') 1006 if (++tempstr >= &tstr[5]) 1007 break; 1008 1009 /* The user gave us too many type arguments */ 1010 if (num_args > 3) { |
908 sprintf(devstat_errbuf, "%s: too many type arguments", 909 func_name); | 1011 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1012 "%s: too many type arguments", func_name); |
910 return(-1); 911 } 912 913 /* 914 * Since you can't realloc a pointer that hasn't been malloced 915 * first, we malloc first and then realloc. 916 */ 917 if (*num_matches == 0) --- 48 unchanged lines hidden (view full) --- 966 strlen(match_table[j].match_str)) == 0) { 967 /* 968 * Make sure the user hasn't specified two 969 * items of the same type, like "da" and 970 * "cd". One device cannot be both. 971 */ 972 if (((*matches)[*num_matches].match_fields & 973 match_table[j].match_field) != 0) { | 1013 return(-1); 1014 } 1015 1016 /* 1017 * Since you can't realloc a pointer that hasn't been malloced 1018 * first, we malloc first and then realloc. 1019 */ 1020 if (*num_matches == 0) --- 48 unchanged lines hidden (view full) --- 1069 strlen(match_table[j].match_str)) == 0) { 1070 /* 1071 * Make sure the user hasn't specified two 1072 * items of the same type, like "da" and 1073 * "cd". One device cannot be both. 1074 */ 1075 if (((*matches)[*num_matches].match_fields & 1076 match_table[j].match_field) != 0) { |
974 sprintf(devstat_errbuf, | 1077 snprintf(devstat_errbuf, 1078 sizeof(devstat_errbuf), |
975 "%s: cannot have more than " 976 "one match item in a single " 977 "category", func_name); 978 return(-1); 979 } 980 /* 981 * If we've gotten this far, we have a 982 * winner. Set the appropriate fields in --- 44 unchanged lines hidden (view full) --- 1027{ 1028 u_int64_t totalbytes, totaltransfers, totalblocks; 1029 char *func_name = "compute_stats"; 1030 1031 /* 1032 * current is the only mandatory field. 1033 */ 1034 if (current == NULL) { | 1079 "%s: cannot have more than " 1080 "one match item in a single " 1081 "category", func_name); 1082 return(-1); 1083 } 1084 /* 1085 * If we've gotten this far, we have a 1086 * winner. Set the appropriate fields in --- 44 unchanged lines hidden (view full) --- 1131{ 1132 u_int64_t totalbytes, totaltransfers, totalblocks; 1133 char *func_name = "compute_stats"; 1134 1135 /* 1136 * current is the only mandatory field. 1137 */ 1138 if (current == NULL) { |
1035 sprintf(devstat_errbuf, "%s: current stats structure was NULL", | 1139 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1140 "%s: current stats structure was NULL", |
1036 func_name); 1037 return(-1); 1038 } 1039 1040 totalbytes = (current->bytes_written + current->bytes_read) - 1041 ((previous) ? (previous->bytes_written + 1042 previous->bytes_read) : 0); 1043 --- 61 unchanged lines hidden (view full) --- 1105 } else 1106 *ms_per_transaction = 0.0; 1107 } 1108 1109 return(0); 1110} 1111 1112long double | 1141 func_name); 1142 return(-1); 1143 } 1144 1145 totalbytes = (current->bytes_written + current->bytes_read) - 1146 ((previous) ? (previous->bytes_written + 1147 previous->bytes_read) : 0); 1148 --- 61 unchanged lines hidden (view full) --- 1210 } else 1211 *ms_per_transaction = 0.0; 1212 } 1213 1214 return(0); 1215} 1216 1217long double |
1113compute_etime(struct timeval cur_time, struct timeval prev_time) | 1218devstat_compute_etime(struct timeval cur_time, struct timeval prev_time) |
1114{ 1115 struct timeval busy_time; 1116 u_int64_t busy_usec; 1117 long double etime; 1118 1119 timersub(&cur_time, &prev_time, &busy_time); 1120 1121 busy_usec = busy_time.tv_sec; 1122 busy_usec *= 1000000; 1123 busy_usec += busy_time.tv_usec; 1124 etime = busy_usec; 1125 etime /= 1000000; 1126 1127 return(etime); 1128} | 1219{ 1220 struct timeval busy_time; 1221 u_int64_t busy_usec; 1222 long double etime; 1223 1224 timersub(&cur_time, &prev_time, &busy_time); 1225 1226 busy_usec = busy_time.tv_sec; 1227 busy_usec *= 1000000; 1228 busy_usec += busy_time.tv_usec; 1229 etime = busy_usec; 1230 etime /= 1000000; 1231 1232 return(etime); 1233} |
1234 1235int 1236devstat_compute_statistics(struct devstat *current, struct devstat *previous, 1237 long double etime, ...) 1238{ 1239 char *func_name = "devstat_compute_statistics"; 1240 u_int64_t totalbytes, totalbytesread, totalbyteswrite; 1241 u_int64_t totaltransfers, totaltransfersread, totaltransferswrite; 1242 u_int64_t totaltransfersother, totalblocks, totalblocksread; 1243 u_int64_t totalblockswrite; 1244 va_list ap; 1245 devstat_metric metric; 1246 u_int64_t *destu64; 1247 long double *destld; 1248 int retval; 1249 1250 retval = 0; 1251 1252 /* 1253 * current is the only mandatory field. 1254 */ 1255 if (current == NULL) { 1256 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1257 "%s: current stats structure was NULL", func_name); 1258 return(-1); 1259 } 1260 1261 totalbytesread = current->bytes_read - 1262 ((previous) ? previous->bytes_read : 0); 1263 totalbyteswrite = current->bytes_written - 1264 ((previous) ? previous->bytes_written : 0); 1265 1266 totalbytes = totalbytesread + totalbyteswrite; 1267 1268 totaltransfersread = current->num_reads - 1269 ((previous) ? previous->num_reads : 0); 1270 1271 totaltransferswrite = current->num_writes - 1272 ((previous) ? previous->num_writes : 0); 1273 1274 totaltransfersother = current->num_other - 1275 ((previous) ? previous->num_other : 0); 1276 1277 totaltransfers = totaltransfersread + totaltransferswrite + 1278 totaltransfersother; 1279 1280 totalblocks = totalbytes; 1281 totalblocksread = totalbytesread; 1282 totalblockswrite = totalbyteswrite; 1283 1284 if (current->block_size > 0) { 1285 totalblocks /= current->block_size; 1286 totalblocksread /= current->block_size; 1287 totalblockswrite /= current->block_size; 1288 } else { 1289 totalblocks /= 512; 1290 totalblocksread /= 512; 1291 totalblockswrite /= 512; 1292 } 1293 1294 va_start(ap, etime); 1295 1296 while ((metric = (devstat_metric)va_arg(ap, devstat_metric)) != 0) { 1297 1298 if (metric == DSM_NONE) 1299 break; 1300 1301 if (metric >= DSM_MAX) { 1302 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1303 "%s: metric %d is out of range", func_name, 1304 metric); 1305 retval = -1; 1306 goto bailout; 1307 } 1308 1309 switch (devstat_arg_list[metric].argtype) { 1310 case DEVSTAT_ARG_UINT64: 1311 destu64 = (u_int64_t *)va_arg(ap, u_int64_t *); 1312 if (destu64 == NULL) { 1313 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1314 "%s: argument type not u_int64_t * or " 1315 "argument type missing", func_name); 1316 retval = -1; 1317 goto bailout; 1318 break; /* NOTREACHED */ 1319 } 1320 break; 1321 case DEVSTAT_ARG_LD: 1322 destld = (long double *)va_arg(ap, long double *); 1323 if (destld == NULL) { 1324 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1325 "%s: argument type not long double * " 1326 "or argument type missing", func_name); 1327 retval = -1; 1328 goto bailout; 1329 break; /* NOTREACHED */ 1330 } 1331 break; 1332 default: 1333 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1334 "%s: unknown argument type %d", func_name, 1335 devstat_arg_list[metric].argtype); 1336 retval = -1; 1337 goto bailout; 1338 break; /* NOTREACHED */ 1339 } 1340 1341 switch (metric) { 1342 case DSM_TOTAL_BYTES: 1343 *destu64 = totalbytes; 1344 break; 1345 case DSM_TOTAL_BYTES_READ: 1346 *destu64 = totalbytesread; 1347 break; 1348 case DSM_TOTAL_BYTES_WRITE: 1349 *destu64 = totalbyteswrite; 1350 break; 1351 case DSM_TOTAL_TRANSFERS: 1352 *destu64 = totaltransfers; 1353 break; 1354 case DSM_TOTAL_TRANSFERS_READ: 1355 *destu64 = totaltransfersread; 1356 break; 1357 case DSM_TOTAL_TRANSFERS_WRITE: 1358 *destu64 = totaltransferswrite; 1359 break; 1360 case DSM_TOTAL_TRANSFERS_OTHER: 1361 *destu64 = totaltransfersother; 1362 break; 1363 case DSM_TOTAL_BLOCKS: 1364 *destu64 = totalblocks; 1365 break; 1366 case DSM_TOTAL_BLOCKS_READ: 1367 *destu64 = totalblocksread; 1368 break; 1369 case DSM_TOTAL_BLOCKS_WRITE: 1370 *destu64 = totalblockswrite; 1371 break; 1372 case DSM_KB_PER_TRANSFER: 1373 *destld = totalbytes; 1374 *destld /= 1024; 1375 if (totaltransfers > 0) 1376 *destld /= totaltransfers; 1377 else 1378 *destld = 0.0; 1379 break; 1380 case DSM_KB_PER_TRANSFER_READ: 1381 *destld = totalbytesread; 1382 *destld /= 1024; 1383 if (totaltransfersread > 0) 1384 *destld /= totaltransfersread; 1385 else 1386 *destld = 0.0; 1387 break; 1388 case DSM_KB_PER_TRANSFER_WRITE: 1389 *destld = totalbyteswrite; 1390 *destld /= 1024; 1391 if (totaltransferswrite > 0) 1392 *destld /= totaltransferswrite; 1393 else 1394 *destld = 0.0; 1395 break; 1396 case DSM_TRANSFERS_PER_SECOND: 1397 if (etime > 0.0) { 1398 *destld = totaltransfers; 1399 *destld /= etime; 1400 } else 1401 *destld = 0.0; 1402 break; 1403 case DSM_TRANSFERS_PER_SECOND_READ: 1404 if (etime > 0.0) { 1405 *destld = totaltransfersread; 1406 *destld /= etime; 1407 } else 1408 *destld = 0.0; 1409 break; 1410 case DSM_TRANSFERS_PER_SECOND_WRITE: 1411 if (etime > 0.0) { 1412 *destld = totaltransferswrite; 1413 *destld /= etime; 1414 } else 1415 *destld = 0.0; 1416 break; 1417 case DSM_TRANSFERS_PER_SECOND_OTHER: 1418 if (etime > 0.0) { 1419 *destld = totaltransfersother; 1420 *destld /= etime; 1421 } else 1422 *destld = 0.0; 1423 break; 1424 case DSM_MB_PER_SECOND: 1425 *destld = totalbytes; 1426 *destld /= 1024 * 1024; 1427 if (etime > 0.0) 1428 *destld /= etime; 1429 else 1430 *destld = 0.0; 1431 break; 1432 case DSM_MB_PER_SECOND_READ: 1433 *destld = totalbytesread; 1434 *destld /= 1024 * 1024; 1435 if (etime > 0.0) 1436 *destld /= etime; 1437 else 1438 *destld = 0.0; 1439 break; 1440 case DSM_MB_PER_SECOND_WRITE: 1441 *destld = totalbyteswrite; 1442 *destld /= 1024 * 1024; 1443 if (etime > 0.0) 1444 *destld /= etime; 1445 else 1446 *destld = 0.0; 1447 break; 1448 case DSM_BLOCKS_PER_SECOND: 1449 *destld = totalblocks; 1450 if (etime > 0.0) 1451 *destld /= etime; 1452 else 1453 *destld = 0.0; 1454 break; 1455 case DSM_BLOCKS_PER_SECOND_READ: 1456 *destld = totalblocksread; 1457 if (etime > 0.0) 1458 *destld /= etime; 1459 else 1460 *destld = 0.0; 1461 break; 1462 case DSM_BLOCKS_PER_SECOND_WRITE: 1463 *destld = totalblockswrite; 1464 if (etime > 0.0) 1465 *destld /= etime; 1466 else 1467 *destld = 0.0; 1468 break; 1469 /* 1470 * This calculation is somewhat bogus. It simply divides 1471 * the elapsed time by the total number of transactions 1472 * completed. While that does give the caller a good 1473 * picture of the average rate of transaction completion, 1474 * it doesn't necessarily give the caller a good view of 1475 * how long transactions took to complete on average. 1476 * Those two numbers will be different for a device that 1477 * can handle more than one transaction at a time. e.g. 1478 * SCSI disks doing tagged queueing. 1479 * 1480 * The only way to accurately determine the real average 1481 * time per transaction would be to compute and store the 1482 * time on a per-transaction basis. That currently isn't 1483 * done in the kernel, and would only be desireable if it 1484 * could be implemented in a somewhat non-intrusive and high 1485 * performance way. 1486 */ 1487 case DSM_MS_PER_TRANSACTION: 1488 if (totaltransfers > 0) { 1489 *destld = etime; 1490 *destld /= totaltransfers; 1491 *destld *= 1000; 1492 } else 1493 *destld = 0.0; 1494 break; 1495 /* 1496 * As above, these next two really only give the average 1497 * rate of completion for read and write transactions, not 1498 * the average time the transaction took to complete. 1499 */ 1500 case DSM_MS_PER_TRANSACTION_READ: 1501 if (totaltransfersread > 0) { 1502 *destld = etime; 1503 *destld /= totaltransfersread; 1504 *destld *= 1000; 1505 } else 1506 *destld = 0.0; 1507 break; 1508 case DSM_MS_PER_TRANSACTION_WRITE: 1509 if (totaltransferswrite > 0) { 1510 *destld = etime; 1511 *destld /= totaltransferswrite; 1512 *destld *= 1000; 1513 } else 1514 *destld = 0.0; 1515 break; 1516 default: 1517 /* 1518 * This shouldn't happen, since we should have 1519 * caught any out of range metrics at the top of 1520 * the loop. 1521 */ 1522 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1523 "%s: unknown metric %d", func_name, metric); 1524 retval = -1; 1525 goto bailout; 1526 break; /* NOTREACHED */ 1527 } 1528 } 1529 1530bailout: 1531 1532 va_end(ap); 1533 return(retval); 1534} 1535 1536static int 1537readkmem(kvm_t *kd, unsigned long addr, void *buf, size_t nbytes) 1538{ 1539 char *func_name = "readkmem"; 1540 1541 if (kvm_read(kd, addr, buf, nbytes) == -1) { 1542 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1543 "%s: error reading value (kvm_read): %s", func_name, 1544 kvm_geterr(kd)); 1545 return(-1); 1546 } 1547 return(0); 1548} 1549 1550static int 1551readkmem_nl(kvm_t *kd, char *name, void *buf, size_t nbytes) 1552{ 1553 char *func_name = "readkmem_nl"; 1554 struct nlist nl[2] = { { name }, { NULL } }; 1555 1556 if (kvm_nlist(kd, nl) == -1) { 1557 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1558 "%s: error getting name list (kvm_nlist): %s", 1559 func_name, kvm_geterr(kd)); 1560 return(-1); 1561 } 1562 return(readkmem(kd, nl[0].n_value, buf, nbytes)); 1563} 1564 1565/* 1566 * This duplicates the functionality of the kernel sysctl handler for poking 1567 * through crash dumps. 1568 */ 1569static char * 1570get_devstat_kvm(kvm_t *kd) 1571{ 1572 int error, i, wp; 1573 long gen; 1574 struct devstat *nds; 1575 struct devstat ds; 1576 struct devstatlist dhead; 1577 int num_devs; 1578 char *rv = NULL; 1579 char *func_name = "get_devstat_kvm"; 1580 1581 if ((num_devs = getnumdevs()) <= 0) 1582 return(NULL); 1583 error = 0; 1584 if (KREADNL(kd, X_DEVICE_STATQ, dhead) == -1) 1585 return(NULL); 1586 1587 nds = STAILQ_FIRST(&dhead); 1588 1589 if ((rv = malloc(sizeof(gen))) == NULL) { 1590 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1591 "%s: out of memory (initial malloc failed)", 1592 func_name); 1593 return(NULL); 1594 } 1595 gen = getgeneration(); 1596 memcpy(rv, &gen, sizeof(gen)); 1597 wp = sizeof(gen); 1598 /* 1599 * Now push out all the devices. 1600 */ 1601 for (i = 0; (nds != NULL) && (i < num_devs); 1602 nds = STAILQ_NEXT(nds, dev_links), i++) { 1603 if (readkmem(kd, (long)nds, &ds, sizeof(ds)) == -1) { 1604 free(rv); 1605 return(NULL); 1606 } 1607 nds = &ds; 1608 rv = (char *)reallocf(rv, sizeof(gen) + 1609 sizeof(ds) * (i + 1)); 1610 if (rv == NULL) { 1611 snprintf(devstat_errbuf, sizeof(devstat_errbuf), 1612 "%s: out of memory (malloc failed)", 1613 func_name); 1614 return(NULL); 1615 } 1616 memcpy(rv + wp, &ds, sizeof(ds)); 1617 wp += sizeof(ds); 1618 } 1619 return(rv); 1620} 1621 1622/* 1623 * Compatability functions for libdevstat 2. These are deprecated and may 1624 * eventually be removed. 1625 */ 1626int 1627getnumdevs(void) 1628{ 1629 return(devstat_getnumdevs(NULL)); 1630} 1631 1632long 1633getgeneration(void) 1634{ 1635 return(devstat_getgeneration(NULL)); 1636} 1637 1638int 1639getversion(void) 1640{ 1641 return(devstat_getversion(NULL)); 1642} 1643 1644int 1645checkversion(void) 1646{ 1647 return(devstat_checkversion(NULL)); 1648} 1649 1650int 1651getdevs(struct statinfo *stats) 1652{ 1653 return(devstat_getdevs(NULL, stats)); 1654} 1655 1656int 1657selectdevs(struct device_selection **dev_select, int *num_selected, 1658 int *num_selections, long *select_generation, 1659 long current_generation, struct devstat *devices, int numdevs, 1660 struct devstat_match *matches, int num_matches, 1661 char **dev_selections, int num_dev_selections, 1662 devstat_select_mode select_mode, int maxshowdevs, 1663 int perf_select) 1664{ 1665 1666 return(devstat_selectdevs(dev_select, num_selected, num_selections, 1667 select_generation, current_generation, devices, numdevs, 1668 matches, num_matches, dev_selections, num_dev_selections, 1669 select_mode, maxshowdevs, perf_select)); 1670} 1671 1672int 1673buildmatch(char *match_str, struct devstat_match **matches, 1674 int *num_matches) 1675{ 1676 return(devstat_buildmatch(match_str, matches, num_matches)); 1677} 1678 1679long double 1680compute_etime(struct timeval cur_time, struct timeval prev_time) 1681{ 1682 return(devstat_compute_etime(cur_time, prev_time)); 1683} |
|