1*5184Sek110237 /* 2*5184Sek110237 * CDDL HEADER START 3*5184Sek110237 * 4*5184Sek110237 * The contents of this file are subject to the terms of the 5*5184Sek110237 * Common Development and Distribution License (the "License"). 6*5184Sek110237 * You may not use this file except in compliance with the License. 7*5184Sek110237 * 8*5184Sek110237 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5184Sek110237 * or http://www.opensolaris.org/os/licensing. 10*5184Sek110237 * See the License for the specific language governing permissions 11*5184Sek110237 * and limitations under the License. 12*5184Sek110237 * 13*5184Sek110237 * When distributing Covered Code, include this CDDL HEADER in each 14*5184Sek110237 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5184Sek110237 * If applicable, add the following below this CDDL HEADER, with the 16*5184Sek110237 * fields enclosed by brackets "[]" replaced with your own identifying 17*5184Sek110237 * information: Portions Copyright [yyyy] [name of copyright owner] 18*5184Sek110237 * 19*5184Sek110237 * CDDL HEADER END 20*5184Sek110237 */ 21*5184Sek110237 /* 22*5184Sek110237 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*5184Sek110237 * Use is subject to license terms. 24*5184Sek110237 */ 25*5184Sek110237 26*5184Sek110237 #pragma ident "%Z%%M% %I% %E% SMI" 27*5184Sek110237 28*5184Sek110237 #include "config.h" 29*5184Sek110237 30*5184Sek110237 #include <stdio.h> 31*5184Sek110237 #include <fcntl.h> 32*5184Sek110237 #include <sys/types.h> 33*5184Sek110237 34*5184Sek110237 #ifdef HAVE_SYSINFO 35*5184Sek110237 #include <sys/sysinfo.h> 36*5184Sek110237 #endif 37*5184Sek110237 38*5184Sek110237 #ifdef HAVE_LIBKSTAT 39*5184Sek110237 #include <kstat.h> 40*5184Sek110237 #include <sys/cpuvar.h> 41*5184Sek110237 #endif /* HAVE_LIBKSTAT */ 42*5184Sek110237 43*5184Sek110237 #include <stdarg.h> 44*5184Sek110237 45*5184Sek110237 #include "filebench.h" 46*5184Sek110237 #include "flowop.h" 47*5184Sek110237 #include "vars.h" 48*5184Sek110237 #include "stats.h" 49*5184Sek110237 50*5184Sek110237 /* 51*5184Sek110237 * A set of routines for collecting and dumping various filebench 52*5184Sek110237 * run statistics. 53*5184Sek110237 */ 54*5184Sek110237 55*5184Sek110237 /* Global statistics */ 56*5184Sek110237 static flowstat_t *globalstats = NULL; 57*5184Sek110237 58*5184Sek110237 static hrtime_t stats_cputime = 0; 59*5184Sek110237 60*5184Sek110237 #ifdef HAVE_LIBKSTAT 61*5184Sek110237 static kstat_ctl_t *kstatp = NULL; 62*5184Sek110237 static kstat_t *sysinfo_ksp = NULL; 63*5184Sek110237 64*5184Sek110237 /* 65*5184Sek110237 * Uses the kstat library or, if it is not available, the /proc/stat file 66*5184Sek110237 * to obtain cpu statistics. Collects statistics for each cpu, initializes 67*5184Sek110237 * a local pointer to the sysinfo kstat, and returns the sum of user and 68*5184Sek110237 * kernel time for all the cpus. 69*5184Sek110237 */ 70*5184Sek110237 static vinteger_t 71*5184Sek110237 kstats_read_cpu(void) 72*5184Sek110237 { 73*5184Sek110237 int ncpus; 74*5184Sek110237 kstat_t **cpu_stat_list = NULL; 75*5184Sek110237 ulong_t cputime_states[CPU_STATES]; 76*5184Sek110237 hrtime_t cputime; 77*5184Sek110237 int i; 78*5184Sek110237 79*5184Sek110237 kstat_t *ksp; 80*5184Sek110237 81*5184Sek110237 if (kstatp == NULL) { 82*5184Sek110237 if ((kstatp = kstat_open()) == (kstat_ctl_t *)NULL) { 83*5184Sek110237 filebench_log(LOG_ERROR, "Cannot read kstats"); 84*5184Sek110237 return (-1); 85*5184Sek110237 } 86*5184Sek110237 } 87*5184Sek110237 88*5184Sek110237 /* 89*5184Sek110237 * Per-CPU statistics 90*5184Sek110237 */ 91*5184Sek110237 92*5184Sek110237 ncpus = 0; 93*5184Sek110237 for (ksp = kstatp->kc_chain; ksp; ksp = ksp->ks_next) 94*5184Sek110237 if (strncmp(ksp->ks_name, "cpu_stat", 8) == 0) 95*5184Sek110237 ncpus++; 96*5184Sek110237 97*5184Sek110237 if ((cpu_stat_list = 98*5184Sek110237 (kstat_t **)malloc(ncpus * sizeof (kstat_t *))) == NULL) { 99*5184Sek110237 filebench_log(LOG_ERROR, "malloc failed"); 100*5184Sek110237 return (-1); 101*5184Sek110237 } 102*5184Sek110237 103*5184Sek110237 ncpus = 0; 104*5184Sek110237 for (ksp = kstatp->kc_chain; ksp; ksp = ksp->ks_next) 105*5184Sek110237 if (strncmp(ksp->ks_name, "cpu_stat", 8) == 0 && 106*5184Sek110237 kstat_read(kstatp, ksp, NULL) != -1) 107*5184Sek110237 cpu_stat_list[ncpus++] = ksp; 108*5184Sek110237 109*5184Sek110237 if (ncpus == 0) { 110*5184Sek110237 filebench_log(LOG_ERROR, 111*5184Sek110237 "kstats can't find any cpu statistics"); 112*5184Sek110237 return (0); 113*5184Sek110237 } 114*5184Sek110237 115*5184Sek110237 if (sysinfo_ksp == NULL) 116*5184Sek110237 sysinfo_ksp = kstat_lookup(kstatp, "unix", 0, "sysinfo"); 117*5184Sek110237 118*5184Sek110237 /* Sum across all CPUs */ 119*5184Sek110237 (void) memset(&cputime_states, 0, sizeof (cputime_states)); 120*5184Sek110237 for (i = 0; i < ncpus; i++) { 121*5184Sek110237 cpu_stat_t cpu_stats; 122*5184Sek110237 int j; 123*5184Sek110237 124*5184Sek110237 (void) kstat_read(kstatp, cpu_stat_list[i], 125*5184Sek110237 (void *) &cpu_stats); 126*5184Sek110237 for (j = 0; j < CPU_STATES; j++) 127*5184Sek110237 cputime_states[j] += cpu_stats.cpu_sysinfo.cpu[j]; 128*5184Sek110237 } 129*5184Sek110237 130*5184Sek110237 cputime = cputime_states[CPU_KERNEL] + cputime_states[CPU_USER]; 131*5184Sek110237 132*5184Sek110237 return (10000000LL * cputime); 133*5184Sek110237 } 134*5184Sek110237 #else /* HAVE_LIBKSTAT */ 135*5184Sek110237 #ifdef HAVE_PROC_STAT 136*5184Sek110237 static FILE *statfd = 0; 137*5184Sek110237 vinteger_t 138*5184Sek110237 kstats_read_cpu(void) 139*5184Sek110237 { 140*5184Sek110237 /* 141*5184Sek110237 * Linux provides system wide statistics in /proc/stat 142*5184Sek110237 * The entry for cpu is 143*5184Sek110237 * cpu 1636 67 1392 208671 5407 20 12 144*5184Sek110237 * cpu0 626 8 997 104476 2499 7 7 145*5184Sek110237 * cpu1 1010 58 395 104195 2907 13 5 146*5184Sek110237 * 147*5184Sek110237 * The number of jiffies (1/100ths of a second) that the 148*5184Sek110237 * system spent in user mode, user mode with low priority 149*5184Sek110237 * (nice), system mode, and the idle task, respectively. 150*5184Sek110237 */ 151*5184Sek110237 unsigned int user, nice, system; 152*5184Sek110237 char cpu[128]; /* placeholder to read "cpu" */ 153*5184Sek110237 if (statfd == 0) { 154*5184Sek110237 statfd = fopen("/proc/stat", "r"); 155*5184Sek110237 if (statfd < 0) { 156*5184Sek110237 filebench_log(LOG_ERROR, "Cannot open /proc/stat"); 157*5184Sek110237 return (-1); 158*5184Sek110237 } 159*5184Sek110237 } 160*5184Sek110237 if (fscanf(statfd, "%s %u %u %u", cpu, &user, &nice, &system) < 0) { 161*5184Sek110237 filebench_log(LOG_ERROR, "Cannot read /proc/stat"); 162*5184Sek110237 return (-1); 163*5184Sek110237 } 164*5184Sek110237 /* convert jiffies to nanosecs */ 165*5184Sek110237 return ((user+nice+system)*1000000); 166*5184Sek110237 } 167*5184Sek110237 168*5184Sek110237 #else /* HAVE_PROC_STAT */ 169*5184Sek110237 vinteger_t 170*5184Sek110237 kstats_read_cpu(void) 171*5184Sek110237 { 172*5184Sek110237 return (0); 173*5184Sek110237 } 174*5184Sek110237 #endif 175*5184Sek110237 #endif /* HAVE_LIBKSTAT */ 176*5184Sek110237 177*5184Sek110237 /* 178*5184Sek110237 * Returns the net cpu time used since the beginning of the run. 179*5184Sek110237 * Just calls kstat_read_cpu() and subtracts stats_cputime which 180*5184Sek110237 * is set at the beginning of the filebench run. 181*5184Sek110237 */ 182*5184Sek110237 static hrtime_t 183*5184Sek110237 kstats_read_cpu_relative(void) 184*5184Sek110237 { 185*5184Sek110237 hrtime_t cputime; 186*5184Sek110237 187*5184Sek110237 cputime = kstats_read_cpu(); 188*5184Sek110237 return (cputime - stats_cputime); 189*5184Sek110237 } 190*5184Sek110237 191*5184Sek110237 /* 192*5184Sek110237 * IO Overhead CPU is the amount of CPU that is incurred running 193*5184Sek110237 * the benchmark infrastructure. 194*5184Sek110237 * 195*5184Sek110237 * It is computed as the sum of micro-state cpu time for each 196*5184Sek110237 * thread around the op being tested. 197*5184Sek110237 * 198*5184Sek110237 * Overhead time is computed for each flow. 199*5184Sek110237 * 200*5184Sek110237 * System overhead is computed as the overhead for I/O flows 201*5184Sek110237 * plus all other time running non-io related flowops 202*5184Sek110237 * 203*5184Sek110237 */ 204*5184Sek110237 205*5184Sek110237 /* 206*5184Sek110237 * Computes and returns the overhead CPU time attibutable to 207*5184Sek110237 * IO type flowops. 208*5184Sek110237 */ 209*5184Sek110237 static hrtime_t 210*5184Sek110237 io_stats_ohead(void) 211*5184Sek110237 { 212*5184Sek110237 flowstat_t *iostat = &globalstats[FLOW_TYPE_IO]; 213*5184Sek110237 flowstat_t *aiostat = &globalstats[FLOW_TYPE_AIO]; 214*5184Sek110237 flowstat_t *glstat = &globalstats[FLOW_TYPE_GLOBAL]; 215*5184Sek110237 216*5184Sek110237 filebench_log(LOG_DEBUG_NEVER, 217*5184Sek110237 "Computing overhead as %lld + %lld - %lld - %lld", 218*5184Sek110237 glstat->fs_mstate[FLOW_MSTATE_OHEAD], 219*5184Sek110237 glstat->fs_mstate[FLOW_MSTATE_CPU], 220*5184Sek110237 iostat->fs_mstate[FLOW_MSTATE_CPU], 221*5184Sek110237 aiostat->fs_mstate[FLOW_MSTATE_CPU]); 222*5184Sek110237 223*5184Sek110237 return ((glstat->fs_mstate[FLOW_MSTATE_OHEAD] + 224*5184Sek110237 glstat->fs_mstate[FLOW_MSTATE_CPU] - 225*5184Sek110237 iostat->fs_mstate[FLOW_MSTATE_CPU] - 226*5184Sek110237 aiostat->fs_mstate[FLOW_MSTATE_CPU])); 227*5184Sek110237 } 228*5184Sek110237 229*5184Sek110237 /* 230*5184Sek110237 * Returns the total overhead CPU time. 231*5184Sek110237 */ 232*5184Sek110237 static hrtime_t 233*5184Sek110237 gl_stats_ohead(void) 234*5184Sek110237 { 235*5184Sek110237 flowstat_t *glstat = &globalstats[FLOW_TYPE_GLOBAL]; 236*5184Sek110237 237*5184Sek110237 return (glstat->fs_mstate[FLOW_MSTATE_OHEAD]); 238*5184Sek110237 } 239*5184Sek110237 240*5184Sek110237 /* 241*5184Sek110237 * Places the value represented by "name" into the var_integer field of the 242*5184Sek110237 * supplied var_t. Compares the supplied "name" with a set of predefined 243*5184Sek110237 * names and calculates the value from the appropriate globalstats field(s). 244*5184Sek110237 */ 245*5184Sek110237 var_t * 246*5184Sek110237 stats_findvar(var_t *var, char *name) 247*5184Sek110237 { 248*5184Sek110237 flowstat_t *iostat = &globalstats[FLOW_TYPE_IO]; 249*5184Sek110237 flowstat_t *aiostat = &globalstats[FLOW_TYPE_AIO]; 250*5184Sek110237 flowstat_t *glstat = &globalstats[FLOW_TYPE_GLOBAL]; 251*5184Sek110237 252*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "reading stats %s", name); 253*5184Sek110237 254*5184Sek110237 if (globalstats == NULL) 255*5184Sek110237 globalstats = malloc(FLOW_TYPES * sizeof (flowstat_t)); 256*5184Sek110237 257*5184Sek110237 if (strcmp(name, "iocount") == 0) { 258*5184Sek110237 var->var_integer = iostat->fs_count + 259*5184Sek110237 aiostat->fs_count; 260*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "reading stats %s = %lld", 261*5184Sek110237 name, var->var_integer); 262*5184Sek110237 return (var); 263*5184Sek110237 } 264*5184Sek110237 265*5184Sek110237 if (strcmp(name, "iorate") == 0) { 266*5184Sek110237 /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ 267*5184Sek110237 var->var_integer = (iostat->fs_count + aiostat->fs_count) / 268*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); 269*5184Sek110237 return (var); 270*5184Sek110237 } 271*5184Sek110237 272*5184Sek110237 273*5184Sek110237 if (strcmp(name, "ioreadrate") == 0) { 274*5184Sek110237 /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ 275*5184Sek110237 var->var_integer = (iostat->fs_rcount + aiostat->fs_rcount) / 276*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); 277*5184Sek110237 return (var); 278*5184Sek110237 } 279*5184Sek110237 280*5184Sek110237 281*5184Sek110237 if (strcmp(name, "iowriterate") == 0) { 282*5184Sek110237 /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ 283*5184Sek110237 var->var_integer = (iostat->fs_wcount + aiostat->fs_wcount) / 284*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); 285*5184Sek110237 return (var); 286*5184Sek110237 } 287*5184Sek110237 288*5184Sek110237 289*5184Sek110237 if (strcmp(name, "iobandwidth") == 0) { 290*5184Sek110237 /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ 291*5184Sek110237 var->var_integer = 292*5184Sek110237 ((iostat->fs_bytes + aiostat->fs_bytes) / (1024 * 1024)) / 293*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS); 294*5184Sek110237 return (var); 295*5184Sek110237 } 296*5184Sek110237 297*5184Sek110237 if (strcmp(name, "iolatency") == 0) { 298*5184Sek110237 var->var_integer = iostat->fs_count ? 299*5184Sek110237 iostat->fs_mstate[FLOW_MSTATE_LAT] / 300*5184Sek110237 (iostat->fs_count * 1000UL) : 0; 301*5184Sek110237 return (var); 302*5184Sek110237 } 303*5184Sek110237 304*5184Sek110237 if (strcmp(name, "iocpu") == 0) { 305*5184Sek110237 var->var_integer = (iostat->fs_count + aiostat->fs_count) ? 306*5184Sek110237 (iostat->fs_mstate[FLOW_MSTATE_CPU] + 307*5184Sek110237 aiostat->fs_mstate[FLOW_MSTATE_CPU]) / ((iostat->fs_count + 308*5184Sek110237 aiostat->fs_count) * 1000UL) : 0; 309*5184Sek110237 return (var); 310*5184Sek110237 } 311*5184Sek110237 312*5184Sek110237 313*5184Sek110237 if (strcmp(name, "oheadcpu") == 0) { 314*5184Sek110237 var->var_integer = (iostat->fs_count + aiostat->fs_count) ? 315*5184Sek110237 io_stats_ohead() / ((iostat->fs_count + 316*5184Sek110237 aiostat->fs_count) * 1000UL) : 0; 317*5184Sek110237 return (var); 318*5184Sek110237 } 319*5184Sek110237 320*5184Sek110237 if (strcmp(name, "iowait") == 0) { 321*5184Sek110237 var->var_integer = iostat->fs_count ? 322*5184Sek110237 iostat->fs_mstate[FLOW_MSTATE_WAIT] / 323*5184Sek110237 (iostat->fs_count * 1000UL) : 0; 324*5184Sek110237 return (var); 325*5184Sek110237 } 326*5184Sek110237 327*5184Sek110237 if (strcmp(name, "syscpu") == 0) { 328*5184Sek110237 /* LINTED E_ASSIGMENT_CAUSE_LOSS_PREC */ 329*5184Sek110237 var->var_integer = glstat->fs_syscpu / 1000.0; 330*5184Sek110237 return (var); 331*5184Sek110237 } 332*5184Sek110237 333*5184Sek110237 if (strcmp(name, "iocpusys") == 0) { 334*5184Sek110237 var->var_integer = (iostat->fs_count + aiostat->fs_count) ? 335*5184Sek110237 iostat->fs_syscpu / ((iostat->fs_count + 336*5184Sek110237 aiostat->fs_count) * 1000UL) : 0; 337*5184Sek110237 338*5184Sek110237 return (var); 339*5184Sek110237 } 340*5184Sek110237 341*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, 342*5184Sek110237 "error reading stats %s", name); 343*5184Sek110237 344*5184Sek110237 return (NULL); 345*5184Sek110237 } 346*5184Sek110237 347*5184Sek110237 /* 348*5184Sek110237 * Initializes the static variable "stats_cputime" with the 349*5184Sek110237 * current cpu time, for use by kstats_read_cpu_relative. 350*5184Sek110237 */ 351*5184Sek110237 void 352*5184Sek110237 stats_init(void) 353*5184Sek110237 { 354*5184Sek110237 #if defined(HAVE_LIBKSTAT) || defined(LINUX_PORT) 355*5184Sek110237 stats_cputime = kstats_read_cpu(); 356*5184Sek110237 #else 357*5184Sek110237 stats_cputime = 0; 358*5184Sek110237 #endif /* HAVE_LIBKSTAT */ 359*5184Sek110237 } 360*5184Sek110237 361*5184Sek110237 /* 362*5184Sek110237 * Add a flowstat b to a, leave sum in a. 363*5184Sek110237 */ 364*5184Sek110237 static void 365*5184Sek110237 stats_add(flowstat_t *a, flowstat_t *b) 366*5184Sek110237 { 367*5184Sek110237 int i; 368*5184Sek110237 369*5184Sek110237 a->fs_count += b->fs_count; 370*5184Sek110237 a->fs_rcount += b->fs_rcount; 371*5184Sek110237 a->fs_wcount += b->fs_wcount; 372*5184Sek110237 a->fs_bytes += b->fs_bytes; 373*5184Sek110237 a->fs_rbytes += b->fs_rbytes; 374*5184Sek110237 a->fs_wbytes += b->fs_wbytes; 375*5184Sek110237 376*5184Sek110237 for (i = 0; i < FLOW_MSTATES; i++) 377*5184Sek110237 a->fs_mstate[i] += b->fs_mstate[i]; 378*5184Sek110237 } 379*5184Sek110237 380*5184Sek110237 /* 381*5184Sek110237 * Takes a "snapshot" of the global statistics. Actually, it calculates 382*5184Sek110237 * them from the local statistics maintained by each flowop. 383*5184Sek110237 * First the routine pauses filebench, then rolls the statistics for 384*5184Sek110237 * each flowop into its associated FLOW_MASTER flowop. 385*5184Sek110237 * Next all the FLOW_MASTER flowops' statistics are written 386*5184Sek110237 * to the log file followed by the global totals. Then filebench 387*5184Sek110237 * operation is allowed to resume. 388*5184Sek110237 */ 389*5184Sek110237 void 390*5184Sek110237 stats_snap(void) 391*5184Sek110237 { 392*5184Sek110237 flowstat_t *iostat = &globalstats[FLOW_TYPE_IO]; 393*5184Sek110237 flowstat_t *aiostat = &globalstats[FLOW_TYPE_AIO]; 394*5184Sek110237 flowstat_t *glstat = &globalstats[FLOW_TYPE_GLOBAL]; 395*5184Sek110237 hrtime_t cputime; 396*5184Sek110237 flowop_t *flowop; 397*5184Sek110237 char *str; 398*5184Sek110237 399*5184Sek110237 if (globalstats == NULL) { 400*5184Sek110237 filebench_log(LOG_ERROR, 401*5184Sek110237 "'stats snap' called before 'stats clear'"); 402*5184Sek110237 return; 403*5184Sek110237 } 404*5184Sek110237 405*5184Sek110237 globalstats->fs_etime = gethrtime(); 406*5184Sek110237 407*5184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Stats period = %ds", 408*5184Sek110237 (globalstats->fs_etime - globalstats->fs_stime) / 1000000000); 409*5184Sek110237 410*5184Sek110237 /* Freeze statistics during update */ 411*5184Sek110237 filebench_shm->bequiet = 1; 412*5184Sek110237 413*5184Sek110237 flowop = filebench_shm->flowoplist; 414*5184Sek110237 while (flowop) { 415*5184Sek110237 flowop_t *flowop_master; 416*5184Sek110237 417*5184Sek110237 if (flowop->fo_instance == FLOW_MASTER) { 418*5184Sek110237 flowop = flowop->fo_next; 419*5184Sek110237 continue; 420*5184Sek110237 } 421*5184Sek110237 422*5184Sek110237 flowop_master = flowop_find_one(flowop->fo_name, 423*5184Sek110237 FLOW_MASTER); 424*5184Sek110237 425*5184Sek110237 /* Roll up per-flowop into global stats */ 426*5184Sek110237 stats_add(&globalstats[flowop->fo_type], 427*5184Sek110237 &flowop->fo_stats); 428*5184Sek110237 stats_add(&globalstats[FLOW_TYPE_GLOBAL], 429*5184Sek110237 &flowop->fo_stats); 430*5184Sek110237 431*5184Sek110237 if (flowop_master && IS_FLOW_ACTIVE(flowop)) { 432*5184Sek110237 flowop_master->fo_stats.fs_active++; 433*5184Sek110237 } 434*5184Sek110237 435*5184Sek110237 if (flowop_master) { 436*5184Sek110237 /* Roll up per-flow stats into master */ 437*5184Sek110237 flowop_master->fo_stats.fs_children++; 438*5184Sek110237 stats_add(&flowop_master->fo_stats, &flowop->fo_stats); 439*5184Sek110237 } else { 440*5184Sek110237 filebench_log(LOG_DEBUG_NEVER, 441*5184Sek110237 "flowop_stats could not find %s", 442*5184Sek110237 flowop->fo_name); 443*5184Sek110237 } 444*5184Sek110237 445*5184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 446*5184Sek110237 "flowop %-20s-%4d - %5d ops, %5.1lf, ops/s %5.1lfmb/s " 447*5184Sek110237 "%8.3fms/op", 448*5184Sek110237 flowop->fo_name, 449*5184Sek110237 flowop->fo_instance, 450*5184Sek110237 flowop->fo_stats.fs_count, 451*5184Sek110237 flowop->fo_stats.fs_count / 452*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 453*5184Sek110237 (flowop->fo_stats.fs_bytes / (1024 * 1024)) / 454*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 455*5184Sek110237 flowop->fo_stats.fs_count ? 456*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_LAT] / 457*5184Sek110237 (flowop->fo_stats.fs_count * 1000000.0) : 0); 458*5184Sek110237 459*5184Sek110237 flowop = flowop->fo_next; 460*5184Sek110237 461*5184Sek110237 } 462*5184Sek110237 463*5184Sek110237 #if defined(HAVE_LIBKSTAT) || defined(LINUX_PORT) 464*5184Sek110237 cputime = kstats_read_cpu_relative(); 465*5184Sek110237 #endif /* HAVE_LIBKSTAT */ 466*5184Sek110237 467*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, 468*5184Sek110237 "cputime = %lld, ohead = %lld", 469*5184Sek110237 cputime / 1000000000, 470*5184Sek110237 io_stats_ohead() / 1000000000); 471*5184Sek110237 iostat->fs_syscpu = 472*5184Sek110237 (cputime > io_stats_ohead()) ? 473*5184Sek110237 (cputime - io_stats_ohead()) : 0; 474*5184Sek110237 glstat->fs_syscpu = 475*5184Sek110237 (cputime > gl_stats_ohead()) ? 476*5184Sek110237 (cputime - gl_stats_ohead()) : 0; 477*5184Sek110237 478*5184Sek110237 479*5184Sek110237 flowop = filebench_shm->flowoplist; 480*5184Sek110237 str = malloc(1048576); 481*5184Sek110237 *str = NULL; 482*5184Sek110237 (void) strcpy(str, "Per-Operation Breakdown\n"); 483*5184Sek110237 while (flowop) { 484*5184Sek110237 char line[1024]; 485*5184Sek110237 486*5184Sek110237 if (flowop->fo_instance != FLOW_MASTER) { 487*5184Sek110237 flowop = flowop->fo_next; 488*5184Sek110237 continue; 489*5184Sek110237 } 490*5184Sek110237 491*5184Sek110237 (void) snprintf(line, sizeof (line), "%-20s %8.0lfops/s " 492*5184Sek110237 "%5.1lfmb/s %8.1fms/op %8.0fus/op-cpu\n", 493*5184Sek110237 flowop->fo_name, 494*5184Sek110237 flowop->fo_stats.fs_count / 495*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 496*5184Sek110237 (flowop->fo_stats.fs_bytes / (1024 * 1024)) / 497*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 498*5184Sek110237 flowop->fo_stats.fs_count ? 499*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_LAT] / 500*5184Sek110237 (flowop->fo_stats.fs_count * 1000000.0) : 0, 501*5184Sek110237 flowop->fo_stats.fs_count ? 502*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_CPU] / 503*5184Sek110237 (flowop->fo_stats.fs_count * 1000.0) : 0); 504*5184Sek110237 (void) strcat(str, line); 505*5184Sek110237 506*5184Sek110237 flowop = flowop->fo_next; 507*5184Sek110237 } 508*5184Sek110237 509*5184Sek110237 filebench_log(LOG_INFO, "%s", str); 510*5184Sek110237 free(str); 511*5184Sek110237 512*5184Sek110237 filebench_log(LOG_INFO, 513*5184Sek110237 "\nIO Summary: %5d ops %5.1lf ops/s, (%0.0lf/%0.0lf r/w) " 514*5184Sek110237 "%5.1lfmb/s, %6.0fus cpu/op, %5.1fms latency", 515*5184Sek110237 iostat->fs_count + aiostat->fs_count, 516*5184Sek110237 (iostat->fs_count + aiostat->fs_count) / 517*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 518*5184Sek110237 (iostat->fs_rcount + aiostat->fs_rcount) / 519*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 520*5184Sek110237 (iostat->fs_wcount + aiostat->fs_wcount) / 521*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 522*5184Sek110237 ((iostat->fs_bytes + aiostat->fs_bytes) / (1024 * 1024)) / 523*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 524*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount + 525*5184Sek110237 aiostat->fs_rcount + aiostat->fs_wcount) ? 526*5184Sek110237 (iostat->fs_syscpu / 1000.0) / 527*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount + 528*5184Sek110237 aiostat->fs_rcount + aiostat->fs_wcount) : 0, 529*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount) ? 530*5184Sek110237 iostat->fs_mstate[FLOW_MSTATE_LAT] / 531*5184Sek110237 ((iostat->fs_rcount + iostat->fs_wcount) * 1000000.0) : 0); 532*5184Sek110237 533*5184Sek110237 534*5184Sek110237 filebench_shm->bequiet = 0; 535*5184Sek110237 } 536*5184Sek110237 537*5184Sek110237 /* 538*5184Sek110237 * Dumps the per-operation statistics and global statistics to the dump file. 539*5184Sek110237 */ 540*5184Sek110237 void 541*5184Sek110237 stats_dump(char *filename) 542*5184Sek110237 { 543*5184Sek110237 flowstat_t *iostat = &globalstats[FLOW_TYPE_IO]; 544*5184Sek110237 flowstat_t *aiostat = &globalstats[FLOW_TYPE_AIO]; 545*5184Sek110237 flowop_t *flowop; 546*5184Sek110237 547*5184Sek110237 (void) strcpy(filebench_shm->dump_filename, filename); 548*5184Sek110237 549*5184Sek110237 filebench_log(LOG_INFO, "in statsdump %s", filename); 550*5184Sek110237 551*5184Sek110237 if (filebench_shm->dump_fd > 0) { 552*5184Sek110237 (void) close(filebench_shm->dump_fd); 553*5184Sek110237 filebench_shm->dump_fd = -1; 554*5184Sek110237 } 555*5184Sek110237 556*5184Sek110237 filebench_log(LOG_DUMP, "Flowop totals:"); 557*5184Sek110237 558*5184Sek110237 flowop = filebench_shm->flowoplist; 559*5184Sek110237 while (flowop) { 560*5184Sek110237 561*5184Sek110237 if (flowop->fo_instance != FLOW_MASTER) { 562*5184Sek110237 flowop = flowop->fo_next; 563*5184Sek110237 continue; 564*5184Sek110237 } 565*5184Sek110237 566*5184Sek110237 filebench_log(LOG_DUMP, 567*5184Sek110237 "%-20s %8.0lfops/s %5.1lfmb/s " 568*5184Sek110237 "%8.1fms/op %8.0fus/op-cpu", 569*5184Sek110237 flowop->fo_name, 570*5184Sek110237 flowop->fo_stats.fs_count / 571*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 572*5184Sek110237 (flowop->fo_stats.fs_bytes / (1024 * 1024)) / 573*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 574*5184Sek110237 flowop->fo_stats.fs_count ? 575*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_LAT] / 576*5184Sek110237 (flowop->fo_stats.fs_count * 1000000.0) : 0, 577*5184Sek110237 flowop->fo_stats.fs_count ? 578*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_CPU] / 579*5184Sek110237 (flowop->fo_stats.fs_count * 1000.0) : 0); 580*5184Sek110237 581*5184Sek110237 flowop = flowop->fo_next; 582*5184Sek110237 } 583*5184Sek110237 584*5184Sek110237 filebench_log(LOG_DUMP, ""); 585*5184Sek110237 filebench_log(LOG_DUMP, 586*5184Sek110237 "IO Summary: %8d ops %8.1lf ops/s, %8.0lf/%0.0lf r/w" 587*5184Sek110237 "%8.1lfmb/s, %8.0fuscpu/op", 588*5184Sek110237 589*5184Sek110237 iostat->fs_count + aiostat->fs_count, 590*5184Sek110237 (iostat->fs_count + aiostat->fs_count) / 591*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 592*5184Sek110237 593*5184Sek110237 (iostat->fs_rcount + aiostat->fs_rcount) / 594*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 595*5184Sek110237 596*5184Sek110237 (iostat->fs_wcount + aiostat->fs_wcount) / 597*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 598*5184Sek110237 599*5184Sek110237 ((iostat->fs_bytes + aiostat->fs_bytes) / (1024 * 1024)) / 600*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS), 601*5184Sek110237 602*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount + 603*5184Sek110237 aiostat->fs_rcount + aiostat->fs_wcount) ? 604*5184Sek110237 (iostat->fs_syscpu / 1000.0) / 605*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount + 606*5184Sek110237 aiostat->fs_rcount + aiostat->fs_wcount) : 0); 607*5184Sek110237 } 608*5184Sek110237 609*5184Sek110237 /* 610*5184Sek110237 * Same as stats_dump, but in xml format. 611*5184Sek110237 */ 612*5184Sek110237 void 613*5184Sek110237 stats_xmldump(char *filename) 614*5184Sek110237 { 615*5184Sek110237 flowstat_t *iostat = &globalstats[FLOW_TYPE_IO]; 616*5184Sek110237 flowstat_t *aiostat = &globalstats[FLOW_TYPE_AIO]; 617*5184Sek110237 flowop_t *flowop; 618*5184Sek110237 619*5184Sek110237 (void) strcpy(filebench_shm->dump_filename, filename); 620*5184Sek110237 621*5184Sek110237 if (filebench_shm->dump_fd > 0) { 622*5184Sek110237 (void) close(filebench_shm->dump_fd); 623*5184Sek110237 filebench_shm->dump_fd = -1; 624*5184Sek110237 } 625*5184Sek110237 626*5184Sek110237 filebench_log(LOG_DUMP, "<stat_doc name=\"Filebench Workload\">"); 627*5184Sek110237 filebench_log(LOG_DUMP, "<stat_group name=\"Flowop totals\">"); 628*5184Sek110237 filebench_log(LOG_DUMP, "<cell_list>"); 629*5184Sek110237 630*5184Sek110237 flowop = filebench_shm->flowoplist; 631*5184Sek110237 while (flowop) { 632*5184Sek110237 if (flowop->fo_instance != FLOW_MASTER) { 633*5184Sek110237 flowop = flowop->fo_next; 634*5184Sek110237 continue; 635*5184Sek110237 } 636*5184Sek110237 637*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.0lf</cell>", 638*5184Sek110237 flowop->fo_stats.fs_count / 639*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS)); 640*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.1lf</cell>", 641*5184Sek110237 (flowop->fo_stats.fs_bytes / (1024 * 1024)) / 642*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS)); 643*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.1lf</cell>", 644*5184Sek110237 flowop->fo_stats.fs_count ? 645*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_LAT] / 646*5184Sek110237 (flowop->fo_stats.fs_count * 1000000.0) : 0); 647*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.0lf</cell>", 648*5184Sek110237 flowop->fo_stats.fs_count ? 649*5184Sek110237 flowop->fo_stats.fs_mstate[FLOW_MSTATE_CPU] / 650*5184Sek110237 (flowop->fo_stats.fs_count * 1000.0) : 0); 651*5184Sek110237 652*5184Sek110237 flowop = flowop->fo_next; 653*5184Sek110237 } 654*5184Sek110237 filebench_log(LOG_DUMP, "</cell_list>"); 655*5184Sek110237 656*5184Sek110237 filebench_log(LOG_DUMP, "<dim_list>"); 657*5184Sek110237 filebench_log(LOG_DUMP, "<dim>"); 658*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>Operations/sec</dimval>"); 659*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>MB/sec</dimval>"); 660*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>Latency (ms per operation)</dimval>"); 661*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>CPU (us per operation)</dimval>"); 662*5184Sek110237 filebench_log(LOG_DUMP, "</dim>"); 663*5184Sek110237 664*5184Sek110237 filebench_log(LOG_DUMP, "<dim>"); 665*5184Sek110237 flowop = filebench_shm->flowoplist; 666*5184Sek110237 while (flowop) { 667*5184Sek110237 if (flowop->fo_instance != FLOW_MASTER) { 668*5184Sek110237 flowop = flowop->fo_next; 669*5184Sek110237 continue; 670*5184Sek110237 } 671*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>%s</dimval>", flowop->fo_name); 672*5184Sek110237 flowop = flowop->fo_next; 673*5184Sek110237 } 674*5184Sek110237 filebench_log(LOG_DUMP, "</dim>"); 675*5184Sek110237 filebench_log(LOG_DUMP, "</dim_list>"); 676*5184Sek110237 filebench_log(LOG_DUMP, "</stat_group>"); 677*5184Sek110237 678*5184Sek110237 filebench_log(LOG_DUMP, "<stat_group name=\"IO Summary\">"); 679*5184Sek110237 filebench_log(LOG_DUMP, "<cell_list>"); 680*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0d</cell>", 681*5184Sek110237 iostat->fs_count + aiostat->fs_count); 682*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.1lf</cell>", 683*5184Sek110237 (iostat->fs_count + aiostat->fs_count) / 684*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS)); 685*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.0lf</cell>", 686*5184Sek110237 (iostat->fs_rcount + aiostat->fs_rcount) / 687*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS)); 688*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.0lf</cell>", 689*5184Sek110237 (iostat->fs_wcount + aiostat->fs_wcount) / 690*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS)); 691*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.1lf</cell>", 692*5184Sek110237 ((iostat->fs_bytes + aiostat->fs_bytes) / (1024 * 1024)) / 693*5184Sek110237 ((globalstats->fs_etime - globalstats->fs_stime) / FSECS)); 694*5184Sek110237 filebench_log(LOG_DUMP, "<cell>%0.0f</cell>", 695*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount + aiostat->fs_rcount + 696*5184Sek110237 aiostat->fs_wcount) ? (iostat->fs_syscpu / 1000.0) / 697*5184Sek110237 (iostat->fs_rcount + iostat->fs_wcount + aiostat->fs_rcount + 698*5184Sek110237 aiostat->fs_wcount) : 0); 699*5184Sek110237 filebench_log(LOG_DUMP, "</cell_list>"); 700*5184Sek110237 701*5184Sek110237 filebench_log(LOG_DUMP, "<dim_list>"); 702*5184Sek110237 filebench_log(LOG_DUMP, "<dim>"); 703*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>Operations</dimval>"); 704*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>Operations/sec</dimval>"); 705*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>Reads</dimval>"); 706*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>Writes</dimval>"); 707*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>MB/sec</dimval>"); 708*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>CPU (us per operation)</dimval>"); 709*5184Sek110237 filebench_log(LOG_DUMP, "</dim>"); 710*5184Sek110237 711*5184Sek110237 filebench_log(LOG_DUMP, "<dim>"); 712*5184Sek110237 filebench_log(LOG_DUMP, "<dimval>IO Summary</dimval>"); 713*5184Sek110237 filebench_log(LOG_DUMP, "</dim>"); 714*5184Sek110237 filebench_log(LOG_DUMP, "</dim_list>"); 715*5184Sek110237 filebench_log(LOG_DUMP, "</stat_group>"); 716*5184Sek110237 filebench_log(LOG_DUMP, "</stat_doc>"); 717*5184Sek110237 } 718*5184Sek110237 719*5184Sek110237 /* 720*5184Sek110237 * Clears all the statistics variables (fo_stats) for every defined flowop. 721*5184Sek110237 * It also creates a global flowstat table if one doesn't already exist and 722*5184Sek110237 * clears it. 723*5184Sek110237 */ 724*5184Sek110237 void 725*5184Sek110237 stats_clear(void) 726*5184Sek110237 { 727*5184Sek110237 flowop_t *flowop; 728*5184Sek110237 729*5184Sek110237 #ifdef HAVE_LIBKSTAT 730*5184Sek110237 stats_cputime = kstats_read_cpu(); 731*5184Sek110237 #else 732*5184Sek110237 stats_cputime = 0; 733*5184Sek110237 #endif /* HAVE_LIBKSTAT */ 734*5184Sek110237 735*5184Sek110237 if (globalstats == NULL) 736*5184Sek110237 globalstats = malloc(FLOW_TYPES * sizeof (flowstat_t)); 737*5184Sek110237 738*5184Sek110237 (void) memset(globalstats, 0, FLOW_TYPES * sizeof (flowstat_t)); 739*5184Sek110237 740*5184Sek110237 flowop = filebench_shm->flowoplist; 741*5184Sek110237 742*5184Sek110237 while (flowop) { 743*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Clearing stats for %s-%d", 744*5184Sek110237 flowop->fo_name, 745*5184Sek110237 flowop->fo_instance); 746*5184Sek110237 (void) memset(&flowop->fo_stats, 0, sizeof (flowstat_t)); 747*5184Sek110237 flowop = flowop->fo_next; 748*5184Sek110237 } 749*5184Sek110237 750*5184Sek110237 (void) memset(globalstats, 0, sizeof (flowstat_t)); 751*5184Sek110237 globalstats->fs_stime = gethrtime(); 752*5184Sek110237 } 753