Home | History | Annotate | Download | only in fio
      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <sys/time.h>
      4 #include <sys/types.h>
      5 #include <sys/stat.h>
      6 #include <dirent.h>
      7 #include <libgen.h>
      8 #include <math.h>
      9 
     10 #include "fio.h"
     11 #include "diskutil.h"
     12 #include "lib/ieee754.h"
     13 #include "json.h"
     14 #include "lib/getrusage.h"
     15 #include "idletime.h"
     16 
     17 static struct fio_mutex *stat_mutex;
     18 
     19 void update_rusage_stat(struct thread_data *td)
     20 {
     21 	struct thread_stat *ts = &td->ts;
     22 
     23 	fio_getrusage(&td->ru_end);
     24 	ts->usr_time += mtime_since(&td->ru_start.ru_utime,
     25 					&td->ru_end.ru_utime);
     26 	ts->sys_time += mtime_since(&td->ru_start.ru_stime,
     27 					&td->ru_end.ru_stime);
     28 	ts->ctx += td->ru_end.ru_nvcsw + td->ru_end.ru_nivcsw
     29 			- (td->ru_start.ru_nvcsw + td->ru_start.ru_nivcsw);
     30 	ts->minf += td->ru_end.ru_minflt - td->ru_start.ru_minflt;
     31 	ts->majf += td->ru_end.ru_majflt - td->ru_start.ru_majflt;
     32 
     33 	memcpy(&td->ru_start, &td->ru_end, sizeof(td->ru_end));
     34 }
     35 
     36 /*
     37  * Given a latency, return the index of the corresponding bucket in
     38  * the structure tracking percentiles.
     39  *
     40  * (1) find the group (and error bits) that the value (latency)
     41  * belongs to by looking at its MSB. (2) find the bucket number in the
     42  * group by looking at the index bits.
     43  *
     44  */
     45 static unsigned int plat_val_to_idx(unsigned int val)
     46 {
     47 	unsigned int msb, error_bits, base, offset, idx;
     48 
     49 	/* Find MSB starting from bit 0 */
     50 	if (val == 0)
     51 		msb = 0;
     52 	else
     53 		msb = (sizeof(val)*8) - __builtin_clz(val) - 1;
     54 
     55 	/*
     56 	 * MSB <= (FIO_IO_U_PLAT_BITS-1), cannot be rounded off. Use
     57 	 * all bits of the sample as index
     58 	 */
     59 	if (msb <= FIO_IO_U_PLAT_BITS)
     60 		return val;
     61 
     62 	/* Compute the number of error bits to discard*/
     63 	error_bits = msb - FIO_IO_U_PLAT_BITS;
     64 
     65 	/* Compute the number of buckets before the group */
     66 	base = (error_bits + 1) << FIO_IO_U_PLAT_BITS;
     67 
     68 	/*
     69 	 * Discard the error bits and apply the mask to find the
     70 	 * index for the buckets in the group
     71 	 */
     72 	offset = (FIO_IO_U_PLAT_VAL - 1) & (val >> error_bits);
     73 
     74 	/* Make sure the index does not exceed (array size - 1) */
     75 	idx = (base + offset) < (FIO_IO_U_PLAT_NR - 1) ?
     76 		(base + offset) : (FIO_IO_U_PLAT_NR - 1);
     77 
     78 	return idx;
     79 }
     80 
     81 /*
     82  * Convert the given index of the bucket array to the value
     83  * represented by the bucket
     84  */
     85 static unsigned int plat_idx_to_val(unsigned int idx)
     86 {
     87 	unsigned int error_bits, k, base;
     88 
     89 	assert(idx < FIO_IO_U_PLAT_NR);
     90 
     91 	/* MSB <= (FIO_IO_U_PLAT_BITS-1), cannot be rounded off. Use
     92 	 * all bits of the sample as index */
     93 	if (idx < (FIO_IO_U_PLAT_VAL << 1))
     94 		return idx;
     95 
     96 	/* Find the group and compute the minimum value of that group */
     97 	error_bits = (idx >> FIO_IO_U_PLAT_BITS) - 1;
     98 	base = 1 << (error_bits + FIO_IO_U_PLAT_BITS);
     99 
    100 	/* Find its bucket number of the group */
    101 	k = idx % FIO_IO_U_PLAT_VAL;
    102 
    103 	/* Return the mean of the range of the bucket */
    104 	return base + ((k + 0.5) * (1 << error_bits));
    105 }
    106 
    107 static int double_cmp(const void *a, const void *b)
    108 {
    109 	const fio_fp64_t fa = *(const fio_fp64_t *) a;
    110 	const fio_fp64_t fb = *(const fio_fp64_t *) b;
    111 	int cmp = 0;
    112 
    113 	if (fa.u.f > fb.u.f)
    114 		cmp = 1;
    115 	else if (fa.u.f < fb.u.f)
    116 		cmp = -1;
    117 
    118 	return cmp;
    119 }
    120 
    121 unsigned int calc_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
    122 				   fio_fp64_t *plist, unsigned int **output,
    123 				   unsigned int *maxv, unsigned int *minv)
    124 {
    125 	unsigned long sum = 0;
    126 	unsigned int len, i, j = 0;
    127 	unsigned int oval_len = 0;
    128 	unsigned int *ovals = NULL;
    129 	int is_last;
    130 
    131 	*minv = -1U;
    132 	*maxv = 0;
    133 
    134 	len = 0;
    135 	while (len < FIO_IO_U_LIST_MAX_LEN && plist[len].u.f != 0.0)
    136 		len++;
    137 
    138 	if (!len)
    139 		return 0;
    140 
    141 	/*
    142 	 * Sort the percentile list. Note that it may already be sorted if
    143 	 * we are using the default values, but since it's a short list this
    144 	 * isn't a worry. Also note that this does not work for NaN values.
    145 	 */
    146 	if (len > 1)
    147 		qsort((void *)plist, len, sizeof(plist[0]), double_cmp);
    148 
    149 	/*
    150 	 * Calculate bucket values, note down max and min values
    151 	 */
    152 	is_last = 0;
    153 	for (i = 0; i < FIO_IO_U_PLAT_NR && !is_last; i++) {
    154 		sum += io_u_plat[i];
    155 		while (sum >= (plist[j].u.f / 100.0 * nr)) {
    156 			assert(plist[j].u.f <= 100.0);
    157 
    158 			if (j == oval_len) {
    159 				oval_len += 100;
    160 				ovals = realloc(ovals, oval_len * sizeof(unsigned int));
    161 			}
    162 
    163 			ovals[j] = plat_idx_to_val(i);
    164 			if (ovals[j] < *minv)
    165 				*minv = ovals[j];
    166 			if (ovals[j] > *maxv)
    167 				*maxv = ovals[j];
    168 
    169 			is_last = (j == len - 1);
    170 			if (is_last)
    171 				break;
    172 
    173 			j++;
    174 		}
    175 	}
    176 
    177 	*output = ovals;
    178 	return len;
    179 }
    180 
    181 /*
    182  * Find and display the p-th percentile of clat
    183  */
    184 static void show_clat_percentiles(unsigned int *io_u_plat, unsigned long nr,
    185 				  fio_fp64_t *plist, unsigned int precision)
    186 {
    187 	unsigned int len, j = 0, minv, maxv;
    188 	unsigned int *ovals;
    189 	int is_last, per_line, scale_down;
    190 	char fmt[32];
    191 
    192 	len = calc_clat_percentiles(io_u_plat, nr, plist, &ovals, &maxv, &minv);
    193 	if (!len)
    194 		goto out;
    195 
    196 	/*
    197 	 * We default to usecs, but if the value range is such that we
    198 	 * should scale down to msecs, do that.
    199 	 */
    200 	if (minv > 2000 && maxv > 99999) {
    201 		scale_down = 1;
    202 		log_info("    clat percentiles (msec):\n     |");
    203 	} else {
    204 		scale_down = 0;
    205 		log_info("    clat percentiles (usec):\n     |");
    206 	}
    207 
    208 	snprintf(fmt, sizeof(fmt), "%%1.%uf", precision);
    209 	per_line = (80 - 7) / (precision + 14);
    210 
    211 	for (j = 0; j < len; j++) {
    212 		char fbuf[16], *ptr = fbuf;
    213 
    214 		/* for formatting */
    215 		if (j != 0 && (j % per_line) == 0)
    216 			log_info("     |");
    217 
    218 		/* end of the list */
    219 		is_last = (j == len - 1);
    220 
    221 		if (plist[j].u.f < 10.0)
    222 			ptr += sprintf(fbuf, " ");
    223 
    224 		snprintf(ptr, sizeof(fbuf), fmt, plist[j].u.f);
    225 
    226 		if (scale_down)
    227 			ovals[j] = (ovals[j] + 999) / 1000;
    228 
    229 		log_info(" %sth=[%5u]%c", fbuf, ovals[j], is_last ? '\n' : ',');
    230 
    231 		if (is_last)
    232 			break;
    233 
    234 		if ((j % per_line) == per_line - 1)	/* for formatting */
    235 			log_info("\n");
    236 	}
    237 
    238 out:
    239 	if (ovals)
    240 		free(ovals);
    241 }
    242 
    243 int calc_lat(struct io_stat *is, unsigned long *min, unsigned long *max,
    244 	     double *mean, double *dev)
    245 {
    246 	double n = (double) is->samples;
    247 
    248 	if (n == 0)
    249 		return 0;
    250 
    251 	*min = is->min_val;
    252 	*max = is->max_val;
    253 	*mean = is->mean.u.f;
    254 
    255 	if (n > 1.0)
    256 		*dev = sqrt(is->S.u.f / (n - 1.0));
    257 	else
    258 		*dev = 0;
    259 
    260 	return 1;
    261 }
    262 
    263 void show_group_stats(struct group_run_stats *rs)
    264 {
    265 	char *p1, *p2, *p3, *p4;
    266 	const char *ddir_str[] = { "   READ", "  WRITE" , "   TRIM"};
    267 	int i;
    268 
    269 	log_info("\nRun status group %d (all jobs):\n", rs->groupid);
    270 
    271 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
    272 		const int i2p = is_power_of_2(rs->kb_base);
    273 
    274 		if (!rs->max_run[i])
    275 			continue;
    276 
    277 		p1 = num2str(rs->io_kb[i], 6, rs->kb_base, i2p, 8);
    278 		p2 = num2str(rs->agg[i], 6, rs->kb_base, i2p, rs->unit_base);
    279 		p3 = num2str(rs->min_bw[i], 6, rs->kb_base, i2p, rs->unit_base);
    280 		p4 = num2str(rs->max_bw[i], 6, rs->kb_base, i2p, rs->unit_base);
    281 
    282 		log_info("%s: io=%s, aggrb=%s/s, minb=%s/s, maxb=%s/s,"
    283 			 " mint=%llumsec, maxt=%llumsec\n",
    284 				rs->unified_rw_rep ? "  MIXED" : ddir_str[i],
    285 				p1, p2, p3, p4,
    286 				(unsigned long long) rs->min_run[i],
    287 				(unsigned long long) rs->max_run[i]);
    288 
    289 		free(p1);
    290 		free(p2);
    291 		free(p3);
    292 		free(p4);
    293 	}
    294 }
    295 
    296 void stat_calc_dist(unsigned int *map, unsigned long total, double *io_u_dist)
    297 {
    298 	int i;
    299 
    300 	/*
    301 	 * Do depth distribution calculations
    302 	 */
    303 	for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
    304 		if (total) {
    305 			io_u_dist[i] = (double) map[i] / (double) total;
    306 			io_u_dist[i] *= 100.0;
    307 			if (io_u_dist[i] < 0.1 && map[i])
    308 				io_u_dist[i] = 0.1;
    309 		} else
    310 			io_u_dist[i] = 0.0;
    311 	}
    312 }
    313 
    314 static void stat_calc_lat(struct thread_stat *ts, double *dst,
    315 			  unsigned int *src, int nr)
    316 {
    317 	unsigned long total = ddir_rw_sum(ts->total_io_u);
    318 	int i;
    319 
    320 	/*
    321 	 * Do latency distribution calculations
    322 	 */
    323 	for (i = 0; i < nr; i++) {
    324 		if (total) {
    325 			dst[i] = (double) src[i] / (double) total;
    326 			dst[i] *= 100.0;
    327 			if (dst[i] < 0.01 && src[i])
    328 				dst[i] = 0.01;
    329 		} else
    330 			dst[i] = 0.0;
    331 	}
    332 }
    333 
    334 void stat_calc_lat_u(struct thread_stat *ts, double *io_u_lat)
    335 {
    336 	stat_calc_lat(ts, io_u_lat, ts->io_u_lat_u, FIO_IO_U_LAT_U_NR);
    337 }
    338 
    339 void stat_calc_lat_m(struct thread_stat *ts, double *io_u_lat)
    340 {
    341 	stat_calc_lat(ts, io_u_lat, ts->io_u_lat_m, FIO_IO_U_LAT_M_NR);
    342 }
    343 
    344 static void display_lat(const char *name, unsigned long min, unsigned long max,
    345 			double mean, double dev)
    346 {
    347 	const char *base = "(usec)";
    348 	char *minp, *maxp;
    349 
    350 	if (!usec_to_msec(&min, &max, &mean, &dev))
    351 		base = "(msec)";
    352 
    353 	minp = num2str(min, 6, 1, 0, 0);
    354 	maxp = num2str(max, 6, 1, 0, 0);
    355 
    356 	log_info("    %s %s: min=%s, max=%s, avg=%5.02f,"
    357 		 " stdev=%5.02f\n", name, base, minp, maxp, mean, dev);
    358 
    359 	free(minp);
    360 	free(maxp);
    361 }
    362 
    363 static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
    364 			     int ddir)
    365 {
    366 	const char *ddir_str[] = { "read ", "write", "trim" };
    367 	unsigned long min, max, runt;
    368 	unsigned long long bw, iops;
    369 	double mean, dev;
    370 	char *io_p, *bw_p, *iops_p;
    371 	int i2p;
    372 
    373 	assert(ddir_rw(ddir));
    374 
    375 	if (!ts->runtime[ddir])
    376 		return;
    377 
    378 	i2p = is_power_of_2(rs->kb_base);
    379 	runt = ts->runtime[ddir];
    380 
    381 	bw = (1000 * ts->io_bytes[ddir]) / runt;
    382 	io_p = num2str(ts->io_bytes[ddir], 6, 1, i2p, 8);
    383 	bw_p = num2str(bw, 6, 1, i2p, ts->unit_base);
    384 
    385 	iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
    386 	iops_p = num2str(iops, 6, 1, 0, 0);
    387 
    388 	log_info("  %s: io=%s, bw=%s/s, iops=%s, runt=%6llumsec\n",
    389 				rs->unified_rw_rep ? "mixed" : ddir_str[ddir],
    390 				io_p, bw_p, iops_p,
    391 				(unsigned long long) ts->runtime[ddir]);
    392 
    393 	free(io_p);
    394 	free(bw_p);
    395 	free(iops_p);
    396 
    397 	if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
    398 		display_lat("slat", min, max, mean, dev);
    399 	if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
    400 		display_lat("clat", min, max, mean, dev);
    401 	if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
    402 		display_lat(" lat", min, max, mean, dev);
    403 
    404 	if (ts->clat_percentiles) {
    405 		show_clat_percentiles(ts->io_u_plat[ddir],
    406 					ts->clat_stat[ddir].samples,
    407 					ts->percentile_list,
    408 					ts->percentile_precision);
    409 	}
    410 	if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
    411 		double p_of_agg = 100.0, fkb_base = (double)rs->kb_base;
    412 		const char *bw_str = (rs->unit_base == 1 ? "Kbit" : "KB");
    413 
    414 		if (rs->unit_base == 1) {
    415 			min *= 8.0;
    416 			max *= 8.0;
    417 			mean *= 8.0;
    418 			dev *= 8.0;
    419 		}
    420 
    421 		if (rs->agg[ddir]) {
    422 			p_of_agg = mean * 100 / (double) rs->agg[ddir];
    423 			if (p_of_agg > 100.0)
    424 				p_of_agg = 100.0;
    425 		}
    426 
    427 		if (mean > fkb_base * fkb_base) {
    428 			min /= fkb_base;
    429 			max /= fkb_base;
    430 			mean /= fkb_base;
    431 			dev /= fkb_base;
    432 			bw_str = (rs->unit_base == 1 ? "Mbit" : "MB");
    433 		}
    434 
    435 		log_info("    bw (%-4s/s): min=%5lu, max=%5lu, per=%3.2f%%,"
    436 			 " avg=%5.02f, stdev=%5.02f\n", bw_str, min, max,
    437 							p_of_agg, mean, dev);
    438 	}
    439 }
    440 
    441 static int show_lat(double *io_u_lat, int nr, const char **ranges,
    442 		    const char *msg)
    443 {
    444 	int new_line = 1, i, line = 0, shown = 0;
    445 
    446 	for (i = 0; i < nr; i++) {
    447 		if (io_u_lat[i] <= 0.0)
    448 			continue;
    449 		shown = 1;
    450 		if (new_line) {
    451 			if (line)
    452 				log_info("\n");
    453 			log_info("    lat (%s) : ", msg);
    454 			new_line = 0;
    455 			line = 0;
    456 		}
    457 		if (line)
    458 			log_info(", ");
    459 		log_info("%s%3.2f%%", ranges[i], io_u_lat[i]);
    460 		line++;
    461 		if (line == 5)
    462 			new_line = 1;
    463 	}
    464 
    465 	if (shown)
    466 		log_info("\n");
    467 
    468 	return shown;
    469 }
    470 
    471 static void show_lat_u(double *io_u_lat_u)
    472 {
    473 	const char *ranges[] = { "2=", "4=", "10=", "20=", "50=", "100=",
    474 				 "250=", "500=", "750=", "1000=", };
    475 
    476 	show_lat(io_u_lat_u, FIO_IO_U_LAT_U_NR, ranges, "usec");
    477 }
    478 
    479 static void show_lat_m(double *io_u_lat_m)
    480 {
    481 	const char *ranges[] = { "2=", "4=", "10=", "20=", "50=", "100=",
    482 				 "250=", "500=", "750=", "1000=", "2000=",
    483 				 ">=2000=", };
    484 
    485 	show_lat(io_u_lat_m, FIO_IO_U_LAT_M_NR, ranges, "msec");
    486 }
    487 
    488 static void show_latencies(struct thread_stat *ts)
    489 {
    490 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    491 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    492 
    493 	stat_calc_lat_u(ts, io_u_lat_u);
    494 	stat_calc_lat_m(ts, io_u_lat_m);
    495 
    496 	show_lat_u(io_u_lat_u);
    497 	show_lat_m(io_u_lat_m);
    498 }
    499 
    500 static void show_thread_status_normal(struct thread_stat *ts,
    501 				      struct group_run_stats *rs)
    502 {
    503 	double usr_cpu, sys_cpu;
    504 	unsigned long runtime;
    505 	double io_u_dist[FIO_IO_U_MAP_NR];
    506 	time_t time_p;
    507 	char time_buf[64];
    508 
    509 	if (!(ts->io_bytes[DDIR_READ] + ts->io_bytes[DDIR_WRITE] +
    510 	    ts->io_bytes[DDIR_TRIM]) && !(ts->total_io_u[DDIR_READ] +
    511 	    ts->total_io_u[DDIR_WRITE] + ts->total_io_u[DDIR_TRIM]))
    512 		return;
    513 
    514 	time(&time_p);
    515 	os_ctime_r((const time_t *) &time_p, time_buf, sizeof(time_buf));
    516 
    517 	if (!ts->error) {
    518 		log_info("%s: (groupid=%d, jobs=%d): err=%2d: pid=%d: %s",
    519 					ts->name, ts->groupid, ts->members,
    520 					ts->error, (int) ts->pid, time_buf);
    521 	} else {
    522 		log_info("%s: (groupid=%d, jobs=%d): err=%2d (%s): pid=%d: %s",
    523 					ts->name, ts->groupid, ts->members,
    524 					ts->error, ts->verror, (int) ts->pid,
    525 					time_buf);
    526 	}
    527 
    528 	if (strlen(ts->description))
    529 		log_info("  Description  : [%s]\n", ts->description);
    530 
    531 	if (ts->io_bytes[DDIR_READ])
    532 		show_ddir_status(rs, ts, DDIR_READ);
    533 	if (ts->io_bytes[DDIR_WRITE])
    534 		show_ddir_status(rs, ts, DDIR_WRITE);
    535 	if (ts->io_bytes[DDIR_TRIM])
    536 		show_ddir_status(rs, ts, DDIR_TRIM);
    537 
    538 	show_latencies(ts);
    539 
    540 	runtime = ts->total_run_time;
    541 	if (runtime) {
    542 		double runt = (double) runtime;
    543 
    544 		usr_cpu = (double) ts->usr_time * 100 / runt;
    545 		sys_cpu = (double) ts->sys_time * 100 / runt;
    546 	} else {
    547 		usr_cpu = 0;
    548 		sys_cpu = 0;
    549 	}
    550 
    551 	log_info("  cpu          : usr=%3.2f%%, sys=%3.2f%%, ctx=%llu,"
    552 		 " majf=%llu, minf=%llu\n", usr_cpu, sys_cpu,
    553 			(unsigned long long) ts->ctx,
    554 			(unsigned long long) ts->majf,
    555 			(unsigned long long) ts->minf);
    556 
    557 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    558 	log_info("  IO depths    : 1=%3.1f%%, 2=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%,"
    559 		 " 16=%3.1f%%, 32=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
    560 					io_u_dist[1], io_u_dist[2],
    561 					io_u_dist[3], io_u_dist[4],
    562 					io_u_dist[5], io_u_dist[6]);
    563 
    564 	stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
    565 	log_info("     submit    : 0=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%, 16=%3.1f%%,"
    566 		 " 32=%3.1f%%, 64=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
    567 					io_u_dist[1], io_u_dist[2],
    568 					io_u_dist[3], io_u_dist[4],
    569 					io_u_dist[5], io_u_dist[6]);
    570 	stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
    571 	log_info("     complete  : 0=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%, 16=%3.1f%%,"
    572 		 " 32=%3.1f%%, 64=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
    573 					io_u_dist[1], io_u_dist[2],
    574 					io_u_dist[3], io_u_dist[4],
    575 					io_u_dist[5], io_u_dist[6]);
    576 	log_info("     issued    : total=r=%llu/w=%llu/d=%llu,"
    577 				 " short=r=%llu/w=%llu/d=%llu\n",
    578 					(unsigned long long) ts->total_io_u[0],
    579 					(unsigned long long) ts->total_io_u[1],
    580 					(unsigned long long) ts->total_io_u[2],
    581 					(unsigned long long) ts->short_io_u[0],
    582 					(unsigned long long) ts->short_io_u[1],
    583 					(unsigned long long) ts->short_io_u[2]);
    584 	if (ts->continue_on_error) {
    585 		log_info("     errors    : total=%llu, first_error=%d/<%s>\n",
    586 					(unsigned long long)ts->total_err_count,
    587 					ts->first_error,
    588 					strerror(ts->first_error));
    589 	}
    590 	if (ts->latency_depth) {
    591 		log_info("     latency   : target=%llu, window=%llu, percentile=%.2f%%, depth=%u\n",
    592 					(unsigned long long)ts->latency_target,
    593 					(unsigned long long)ts->latency_window,
    594 					ts->latency_percentile.u.f,
    595 					ts->latency_depth);
    596 	}
    597 }
    598 
    599 static void show_ddir_status_terse(struct thread_stat *ts,
    600 				   struct group_run_stats *rs, int ddir)
    601 {
    602 	unsigned long min, max;
    603 	unsigned long long bw, iops;
    604 	unsigned int *ovals = NULL;
    605 	double mean, dev;
    606 	unsigned int len, minv, maxv;
    607 	int i;
    608 
    609 	assert(ddir_rw(ddir));
    610 
    611 	iops = bw = 0;
    612 	if (ts->runtime[ddir]) {
    613 		uint64_t runt = ts->runtime[ddir];
    614 
    615 		bw = ((1000 * ts->io_bytes[ddir]) / runt) / 1024;
    616 		iops = (1000 * (uint64_t) ts->total_io_u[ddir]) / runt;
    617 	}
    618 
    619 	log_info(";%llu;%llu;%llu;%llu",
    620 		(unsigned long long) ts->io_bytes[ddir] >> 10, bw, iops,
    621 					(unsigned long long) ts->runtime[ddir]);
    622 
    623 	if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
    624 		log_info(";%lu;%lu;%f;%f", min, max, mean, dev);
    625 	else
    626 		log_info(";%lu;%lu;%f;%f", 0UL, 0UL, 0.0, 0.0);
    627 
    628 	if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
    629 		log_info(";%lu;%lu;%f;%f", min, max, mean, dev);
    630 	else
    631 		log_info(";%lu;%lu;%f;%f", 0UL, 0UL, 0.0, 0.0);
    632 
    633 	if (ts->clat_percentiles) {
    634 		len = calc_clat_percentiles(ts->io_u_plat[ddir],
    635 					ts->clat_stat[ddir].samples,
    636 					ts->percentile_list, &ovals, &maxv,
    637 					&minv);
    638 	} else
    639 		len = 0;
    640 
    641 	for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
    642 		if (i >= len) {
    643 			log_info(";0%%=0");
    644 			continue;
    645 		}
    646 		log_info(";%f%%=%u", ts->percentile_list[i].u.f, ovals[i]);
    647 	}
    648 
    649 	if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
    650 		log_info(";%lu;%lu;%f;%f", min, max, mean, dev);
    651 	else
    652 		log_info(";%lu;%lu;%f;%f", 0UL, 0UL, 0.0, 0.0);
    653 
    654 	if (ovals)
    655 		free(ovals);
    656 
    657 	if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
    658 		double p_of_agg = 100.0;
    659 
    660 		if (rs->agg[ddir]) {
    661 			p_of_agg = mean * 100 / (double) rs->agg[ddir];
    662 			if (p_of_agg > 100.0)
    663 				p_of_agg = 100.0;
    664 		}
    665 
    666 		log_info(";%lu;%lu;%f%%;%f;%f", min, max, p_of_agg, mean, dev);
    667 	} else
    668 		log_info(";%lu;%lu;%f%%;%f;%f", 0UL, 0UL, 0.0, 0.0, 0.0);
    669 }
    670 
    671 static void add_ddir_status_json(struct thread_stat *ts,
    672 		struct group_run_stats *rs, int ddir, struct json_object *parent)
    673 {
    674 	unsigned long min, max;
    675 	unsigned long long bw, iops;
    676 	unsigned int *ovals = NULL;
    677 	double mean, dev;
    678 	unsigned int len, minv, maxv;
    679 	int i;
    680 	const char *ddirname[] = {"read", "write", "trim"};
    681 	struct json_object *dir_object, *tmp_object, *percentile_object;
    682 	char buf[120];
    683 	double p_of_agg = 100.0;
    684 
    685 	assert(ddir_rw(ddir));
    686 
    687 	if (ts->unified_rw_rep && ddir != DDIR_READ)
    688 		return;
    689 
    690 	dir_object = json_create_object();
    691 	json_object_add_value_object(parent,
    692 		ts->unified_rw_rep ? "mixed" : ddirname[ddir], dir_object);
    693 
    694 	iops = bw = 0;
    695 	if (ts->runtime[ddir]) {
    696 		uint64_t runt = ts->runtime[ddir];
    697 
    698 		bw = ((1000 * ts->io_bytes[ddir]) / runt) / 1024;
    699 		iops = (1000 * (uint64_t) ts->total_io_u[ddir]) / runt;
    700 	}
    701 
    702 	json_object_add_value_int(dir_object, "io_bytes", ts->io_bytes[ddir] >> 10);
    703 	json_object_add_value_int(dir_object, "bw", bw);
    704 	json_object_add_value_int(dir_object, "iops", iops);
    705 	json_object_add_value_int(dir_object, "runtime", ts->runtime[ddir]);
    706 
    707 	if (!calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev)) {
    708 		min = max = 0;
    709 		mean = dev = 0.0;
    710 	}
    711 	tmp_object = json_create_object();
    712 	json_object_add_value_object(dir_object, "slat", tmp_object);
    713 	json_object_add_value_int(tmp_object, "min", min);
    714 	json_object_add_value_int(tmp_object, "max", max);
    715 	json_object_add_value_float(tmp_object, "mean", mean);
    716 	json_object_add_value_float(tmp_object, "stddev", dev);
    717 
    718 	if (!calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev)) {
    719 		min = max = 0;
    720 		mean = dev = 0.0;
    721 	}
    722 	tmp_object = json_create_object();
    723 	json_object_add_value_object(dir_object, "clat", tmp_object);
    724 	json_object_add_value_int(tmp_object, "min", min);
    725 	json_object_add_value_int(tmp_object, "max", max);
    726 	json_object_add_value_float(tmp_object, "mean", mean);
    727 	json_object_add_value_float(tmp_object, "stddev", dev);
    728 
    729 	if (ts->clat_percentiles) {
    730 		len = calc_clat_percentiles(ts->io_u_plat[ddir],
    731 					ts->clat_stat[ddir].samples,
    732 					ts->percentile_list, &ovals, &maxv,
    733 					&minv);
    734 	} else
    735 		len = 0;
    736 
    737 	percentile_object = json_create_object();
    738 	json_object_add_value_object(tmp_object, "percentile", percentile_object);
    739 	for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
    740 		if (i >= len) {
    741 			json_object_add_value_int(percentile_object, "0.00", 0);
    742 			continue;
    743 		}
    744 		snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
    745 		json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
    746 	}
    747 
    748 	if (!calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev)) {
    749 		min = max = 0;
    750 		mean = dev = 0.0;
    751 	}
    752 	tmp_object = json_create_object();
    753 	json_object_add_value_object(dir_object, "lat", tmp_object);
    754 	json_object_add_value_int(tmp_object, "min", min);
    755 	json_object_add_value_int(tmp_object, "max", max);
    756 	json_object_add_value_float(tmp_object, "mean", mean);
    757 	json_object_add_value_float(tmp_object, "stddev", dev);
    758 	if (ovals)
    759 		free(ovals);
    760 
    761 	if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
    762 		if (rs->agg[ddir]) {
    763 			p_of_agg = mean * 100 / (double) rs->agg[ddir];
    764 			if (p_of_agg > 100.0)
    765 				p_of_agg = 100.0;
    766 		}
    767 	} else {
    768 		min = max = 0;
    769 		p_of_agg = mean = dev = 0.0;
    770 	}
    771 	json_object_add_value_int(dir_object, "bw_min", min);
    772 	json_object_add_value_int(dir_object, "bw_max", max);
    773 	json_object_add_value_float(dir_object, "bw_agg", p_of_agg);
    774 	json_object_add_value_float(dir_object, "bw_mean", mean);
    775 	json_object_add_value_float(dir_object, "bw_dev", dev);
    776 }
    777 
    778 static void show_thread_status_terse_v2(struct thread_stat *ts,
    779 					struct group_run_stats *rs)
    780 {
    781 	double io_u_dist[FIO_IO_U_MAP_NR];
    782 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    783 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    784 	double usr_cpu, sys_cpu;
    785 	int i;
    786 
    787 	/* General Info */
    788 	log_info("2;%s;%d;%d", ts->name, ts->groupid, ts->error);
    789 	/* Log Read Status */
    790 	show_ddir_status_terse(ts, rs, DDIR_READ);
    791 	/* Log Write Status */
    792 	show_ddir_status_terse(ts, rs, DDIR_WRITE);
    793 	/* Log Trim Status */
    794 	show_ddir_status_terse(ts, rs, DDIR_TRIM);
    795 
    796 	/* CPU Usage */
    797 	if (ts->total_run_time) {
    798 		double runt = (double) ts->total_run_time;
    799 
    800 		usr_cpu = (double) ts->usr_time * 100 / runt;
    801 		sys_cpu = (double) ts->sys_time * 100 / runt;
    802 	} else {
    803 		usr_cpu = 0;
    804 		sys_cpu = 0;
    805 	}
    806 
    807 	log_info(";%f%%;%f%%;%llu;%llu;%llu", usr_cpu, sys_cpu,
    808 						(unsigned long long) ts->ctx,
    809 						(unsigned long long) ts->majf,
    810 						(unsigned long long) ts->minf);
    811 
    812 	/* Calc % distribution of IO depths, usecond, msecond latency */
    813 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    814 	stat_calc_lat_u(ts, io_u_lat_u);
    815 	stat_calc_lat_m(ts, io_u_lat_m);
    816 
    817 	/* Only show fixed 7 I/O depth levels*/
    818 	log_info(";%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%",
    819 			io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3],
    820 			io_u_dist[4], io_u_dist[5], io_u_dist[6]);
    821 
    822 	/* Microsecond latency */
    823 	for (i = 0; i < FIO_IO_U_LAT_U_NR; i++)
    824 		log_info(";%3.2f%%", io_u_lat_u[i]);
    825 	/* Millisecond latency */
    826 	for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
    827 		log_info(";%3.2f%%", io_u_lat_m[i]);
    828 	/* Additional output if continue_on_error set - default off*/
    829 	if (ts->continue_on_error)
    830 		log_info(";%llu;%d", (unsigned long long) ts->total_err_count, ts->first_error);
    831 	log_info("\n");
    832 
    833 	/* Additional output if description is set */
    834 	if (strlen(ts->description))
    835 		log_info(";%s", ts->description);
    836 
    837 	log_info("\n");
    838 }
    839 
    840 static void show_thread_status_terse_v3_v4(struct thread_stat *ts,
    841 					   struct group_run_stats *rs, int ver)
    842 {
    843 	double io_u_dist[FIO_IO_U_MAP_NR];
    844 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    845 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    846 	double usr_cpu, sys_cpu;
    847 	int i;
    848 
    849 	/* General Info */
    850 	log_info("%d;%s;%s;%d;%d", ver, fio_version_string,
    851 					ts->name, ts->groupid, ts->error);
    852 	/* Log Read Status */
    853 	show_ddir_status_terse(ts, rs, DDIR_READ);
    854 	/* Log Write Status */
    855 	show_ddir_status_terse(ts, rs, DDIR_WRITE);
    856 	/* Log Trim Status */
    857 	if (ver == 4)
    858 		show_ddir_status_terse(ts, rs, DDIR_TRIM);
    859 
    860 	/* CPU Usage */
    861 	if (ts->total_run_time) {
    862 		double runt = (double) ts->total_run_time;
    863 
    864 		usr_cpu = (double) ts->usr_time * 100 / runt;
    865 		sys_cpu = (double) ts->sys_time * 100 / runt;
    866 	} else {
    867 		usr_cpu = 0;
    868 		sys_cpu = 0;
    869 	}
    870 
    871 	log_info(";%f%%;%f%%;%llu;%llu;%llu", usr_cpu, sys_cpu,
    872 						(unsigned long long) ts->ctx,
    873 						(unsigned long long) ts->majf,
    874 						(unsigned long long) ts->minf);
    875 
    876 	/* Calc % distribution of IO depths, usecond, msecond latency */
    877 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    878 	stat_calc_lat_u(ts, io_u_lat_u);
    879 	stat_calc_lat_m(ts, io_u_lat_m);
    880 
    881 	/* Only show fixed 7 I/O depth levels*/
    882 	log_info(";%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%",
    883 			io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3],
    884 			io_u_dist[4], io_u_dist[5], io_u_dist[6]);
    885 
    886 	/* Microsecond latency */
    887 	for (i = 0; i < FIO_IO_U_LAT_U_NR; i++)
    888 		log_info(";%3.2f%%", io_u_lat_u[i]);
    889 	/* Millisecond latency */
    890 	for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
    891 		log_info(";%3.2f%%", io_u_lat_m[i]);
    892 
    893 	/* disk util stats, if any */
    894 	if (is_backend)
    895 		show_disk_util(1, NULL);
    896 
    897 	/* Additional output if continue_on_error set - default off*/
    898 	if (ts->continue_on_error)
    899 		log_info(";%llu;%d", (unsigned long long) ts->total_err_count, ts->first_error);
    900 
    901 	/* Additional output if description is set */
    902 	if (strlen(ts->description))
    903 		log_info(";%s", ts->description);
    904 
    905 	log_info("\n");
    906 }
    907 
    908 static struct json_object *show_thread_status_json(struct thread_stat *ts,
    909 				    struct group_run_stats *rs)
    910 {
    911 	struct json_object *root, *tmp;
    912 	double io_u_dist[FIO_IO_U_MAP_NR];
    913 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    914 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    915 	double usr_cpu, sys_cpu;
    916 	int i;
    917 
    918 	root = json_create_object();
    919 	json_object_add_value_string(root, "jobname", ts->name);
    920 	json_object_add_value_int(root, "groupid", ts->groupid);
    921 	json_object_add_value_int(root, "error", ts->error);
    922 
    923 	add_ddir_status_json(ts, rs, DDIR_READ, root);
    924 	add_ddir_status_json(ts, rs, DDIR_WRITE, root);
    925 	add_ddir_status_json(ts, rs, DDIR_TRIM, root);
    926 
    927 	/* CPU Usage */
    928 	if (ts->total_run_time) {
    929 		double runt = (double) ts->total_run_time;
    930 
    931 		usr_cpu = (double) ts->usr_time * 100 / runt;
    932 		sys_cpu = (double) ts->sys_time * 100 / runt;
    933 	} else {
    934 		usr_cpu = 0;
    935 		sys_cpu = 0;
    936 	}
    937 	json_object_add_value_float(root, "usr_cpu", usr_cpu);
    938 	json_object_add_value_float(root, "sys_cpu", sys_cpu);
    939 	json_object_add_value_int(root, "ctx", ts->ctx);
    940 	json_object_add_value_int(root, "majf", ts->majf);
    941 	json_object_add_value_int(root, "minf", ts->minf);
    942 
    943 
    944 	/* Calc % distribution of IO depths, usecond, msecond latency */
    945 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    946 	stat_calc_lat_u(ts, io_u_lat_u);
    947 	stat_calc_lat_m(ts, io_u_lat_m);
    948 
    949 	tmp = json_create_object();
    950 	json_object_add_value_object(root, "iodepth_level", tmp);
    951 	/* Only show fixed 7 I/O depth levels*/
    952 	for (i = 0; i < 7; i++) {
    953 		char name[20];
    954 		if (i < 6)
    955 			snprintf(name, 20, "%d", 1 << i);
    956 		else
    957 			snprintf(name, 20, ">=%d", 1 << i);
    958 		json_object_add_value_float(tmp, (const char *)name, io_u_dist[i]);
    959 	}
    960 
    961 	tmp = json_create_object();
    962 	json_object_add_value_object(root, "latency_us", tmp);
    963 	/* Microsecond latency */
    964 	for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) {
    965 		const char *ranges[] = { "2", "4", "10", "20", "50", "100",
    966 				 "250", "500", "750", "1000", };
    967 		json_object_add_value_float(tmp, ranges[i], io_u_lat_u[i]);
    968 	}
    969 	/* Millisecond latency */
    970 	tmp = json_create_object();
    971 	json_object_add_value_object(root, "latency_ms", tmp);
    972 	for (i = 0; i < FIO_IO_U_LAT_M_NR; i++) {
    973 		const char *ranges[] = { "2", "4", "10", "20", "50", "100",
    974 				 "250", "500", "750", "1000", "2000",
    975 				 ">=2000", };
    976 		json_object_add_value_float(tmp, ranges[i], io_u_lat_m[i]);
    977 	}
    978 
    979 	/* Additional output if continue_on_error set - default off*/
    980 	if (ts->continue_on_error) {
    981 		json_object_add_value_int(root, "total_err", ts->total_err_count);
    982 		json_object_add_value_int(root, "first_error", ts->first_error);
    983 	}
    984 
    985 	if (ts->latency_depth) {
    986 		json_object_add_value_int(root, "latency_depth", ts->latency_depth);
    987 		json_object_add_value_int(root, "latency_target", ts->latency_target);
    988 		json_object_add_value_float(root, "latency_percentile", ts->latency_percentile.u.f);
    989 		json_object_add_value_int(root, "latency_window", ts->latency_window);
    990 	}
    991 
    992 	/* Additional output if description is set */
    993 	if (strlen(ts->description))
    994 		json_object_add_value_string(root, "desc", ts->description);
    995 
    996 	return root;
    997 }
    998 
    999 static void show_thread_status_terse(struct thread_stat *ts,
   1000 				     struct group_run_stats *rs)
   1001 {
   1002 	if (terse_version == 2)
   1003 		show_thread_status_terse_v2(ts, rs);
   1004 	else if (terse_version == 3 || terse_version == 4)
   1005 		show_thread_status_terse_v3_v4(ts, rs, terse_version);
   1006 	else
   1007 		log_err("fio: bad terse version!? %d\n", terse_version);
   1008 }
   1009 
   1010 struct json_object *show_thread_status(struct thread_stat *ts,
   1011 				       struct group_run_stats *rs)
   1012 {
   1013 	if (output_format == FIO_OUTPUT_TERSE)
   1014 		show_thread_status_terse(ts, rs);
   1015 	else if (output_format == FIO_OUTPUT_JSON)
   1016 		return show_thread_status_json(ts, rs);
   1017 	else
   1018 		show_thread_status_normal(ts, rs);
   1019 	return NULL;
   1020 }
   1021 
   1022 static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr)
   1023 {
   1024 	double mean, S;
   1025 
   1026 	if (src->samples == 0)
   1027 		return;
   1028 
   1029 	dst->min_val = min(dst->min_val, src->min_val);
   1030 	dst->max_val = max(dst->max_val, src->max_val);
   1031 
   1032 	/*
   1033 	 * Compute new mean and S after the merge
   1034 	 * <http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
   1035 	 *  #Parallel_algorithm>
   1036 	 */
   1037 	if (nr == 1) {
   1038 		mean = src->mean.u.f;
   1039 		S = src->S.u.f;
   1040 	} else {
   1041 		double delta = src->mean.u.f - dst->mean.u.f;
   1042 
   1043 		mean = ((src->mean.u.f * src->samples) +
   1044 			(dst->mean.u.f * dst->samples)) /
   1045 			(dst->samples + src->samples);
   1046 
   1047 		S =  src->S.u.f + dst->S.u.f + pow(delta, 2.0) *
   1048 			(dst->samples * src->samples) /
   1049 			(dst->samples + src->samples);
   1050 	}
   1051 
   1052 	dst->samples += src->samples;
   1053 	dst->mean.u.f = mean;
   1054 	dst->S.u.f = S;
   1055 }
   1056 
   1057 void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src)
   1058 {
   1059 	int i;
   1060 
   1061 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
   1062 		if (dst->max_run[i] < src->max_run[i])
   1063 			dst->max_run[i] = src->max_run[i];
   1064 		if (dst->min_run[i] && dst->min_run[i] > src->min_run[i])
   1065 			dst->min_run[i] = src->min_run[i];
   1066 		if (dst->max_bw[i] < src->max_bw[i])
   1067 			dst->max_bw[i] = src->max_bw[i];
   1068 		if (dst->min_bw[i] && dst->min_bw[i] > src->min_bw[i])
   1069 			dst->min_bw[i] = src->min_bw[i];
   1070 
   1071 		dst->io_kb[i] += src->io_kb[i];
   1072 		dst->agg[i] += src->agg[i];
   1073 	}
   1074 
   1075 }
   1076 
   1077 void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src, int nr)
   1078 {
   1079 	int l, k;
   1080 
   1081 	for (l = 0; l < DDIR_RWDIR_CNT; l++) {
   1082 		if (!dst->unified_rw_rep) {
   1083 			sum_stat(&dst->clat_stat[l], &src->clat_stat[l], nr);
   1084 			sum_stat(&dst->slat_stat[l], &src->slat_stat[l], nr);
   1085 			sum_stat(&dst->lat_stat[l], &src->lat_stat[l], nr);
   1086 			sum_stat(&dst->bw_stat[l], &src->bw_stat[l], nr);
   1087 
   1088 			dst->io_bytes[l] += src->io_bytes[l];
   1089 
   1090 			if (dst->runtime[l] < src->runtime[l])
   1091 				dst->runtime[l] = src->runtime[l];
   1092 		} else {
   1093 			sum_stat(&dst->clat_stat[0], &src->clat_stat[l], nr);
   1094 			sum_stat(&dst->slat_stat[0], &src->slat_stat[l], nr);
   1095 			sum_stat(&dst->lat_stat[0], &src->lat_stat[l], nr);
   1096 			sum_stat(&dst->bw_stat[0], &src->bw_stat[l], nr);
   1097 
   1098 			dst->io_bytes[0] += src->io_bytes[l];
   1099 
   1100 			if (dst->runtime[0] < src->runtime[l])
   1101 				dst->runtime[0] = src->runtime[l];
   1102 		}
   1103 	}
   1104 
   1105 	dst->usr_time += src->usr_time;
   1106 	dst->sys_time += src->sys_time;
   1107 	dst->ctx += src->ctx;
   1108 	dst->majf += src->majf;
   1109 	dst->minf += src->minf;
   1110 
   1111 	for (k = 0; k < FIO_IO_U_MAP_NR; k++)
   1112 		dst->io_u_map[k] += src->io_u_map[k];
   1113 	for (k = 0; k < FIO_IO_U_MAP_NR; k++)
   1114 		dst->io_u_submit[k] += src->io_u_submit[k];
   1115 	for (k = 0; k < FIO_IO_U_MAP_NR; k++)
   1116 		dst->io_u_complete[k] += src->io_u_complete[k];
   1117 	for (k = 0; k < FIO_IO_U_LAT_U_NR; k++)
   1118 		dst->io_u_lat_u[k] += src->io_u_lat_u[k];
   1119 	for (k = 0; k < FIO_IO_U_LAT_M_NR; k++)
   1120 		dst->io_u_lat_m[k] += src->io_u_lat_m[k];
   1121 
   1122 	for (k = 0; k < DDIR_RWDIR_CNT; k++) {
   1123 		if (!dst->unified_rw_rep) {
   1124 			dst->total_io_u[k] += src->total_io_u[k];
   1125 			dst->short_io_u[k] += src->short_io_u[k];
   1126 		} else {
   1127 			dst->total_io_u[0] += src->total_io_u[k];
   1128 			dst->short_io_u[0] += src->short_io_u[k];
   1129 		}
   1130 	}
   1131 
   1132 	for (k = 0; k < DDIR_RWDIR_CNT; k++) {
   1133 		int m;
   1134 
   1135 		for (m = 0; m < FIO_IO_U_PLAT_NR; m++) {
   1136 			if (!dst->unified_rw_rep)
   1137 				dst->io_u_plat[k][m] += src->io_u_plat[k][m];
   1138 			else
   1139 				dst->io_u_plat[0][m] += src->io_u_plat[k][m];
   1140 		}
   1141 	}
   1142 
   1143 	dst->total_run_time += src->total_run_time;
   1144 	dst->total_submit += src->total_submit;
   1145 	dst->total_complete += src->total_complete;
   1146 }
   1147 
   1148 void init_group_run_stat(struct group_run_stats *gs)
   1149 {
   1150 	int i;
   1151 	memset(gs, 0, sizeof(*gs));
   1152 
   1153 	for (i = 0; i < DDIR_RWDIR_CNT; i++)
   1154 		gs->min_bw[i] = gs->min_run[i] = ~0UL;
   1155 }
   1156 
   1157 void init_thread_stat(struct thread_stat *ts)
   1158 {
   1159 	int j;
   1160 
   1161 	memset(ts, 0, sizeof(*ts));
   1162 
   1163 	for (j = 0; j < DDIR_RWDIR_CNT; j++) {
   1164 		ts->lat_stat[j].min_val = -1UL;
   1165 		ts->clat_stat[j].min_val = -1UL;
   1166 		ts->slat_stat[j].min_val = -1UL;
   1167 		ts->bw_stat[j].min_val = -1UL;
   1168 	}
   1169 	ts->groupid = -1;
   1170 }
   1171 
   1172 static void __show_run_stats(void)
   1173 {
   1174 	struct group_run_stats *runstats, *rs;
   1175 	struct thread_data *td;
   1176 	struct thread_stat *threadstats, *ts;
   1177 	int i, j, nr_ts, last_ts, idx;
   1178 	int kb_base_warned = 0;
   1179 	int unit_base_warned = 0;
   1180 	struct json_object *root = NULL;
   1181 	struct json_array *array = NULL;
   1182 
   1183 	runstats = malloc(sizeof(struct group_run_stats) * (groupid + 1));
   1184 
   1185 	for (i = 0; i < groupid + 1; i++)
   1186 		init_group_run_stat(&runstats[i]);
   1187 
   1188 	/*
   1189 	 * find out how many threads stats we need. if group reporting isn't
   1190 	 * enabled, it's one-per-td.
   1191 	 */
   1192 	nr_ts = 0;
   1193 	last_ts = -1;
   1194 	for_each_td(td, i) {
   1195 		if (!td->o.group_reporting) {
   1196 			nr_ts++;
   1197 			continue;
   1198 		}
   1199 		if (last_ts == td->groupid)
   1200 			continue;
   1201 
   1202 		last_ts = td->groupid;
   1203 		nr_ts++;
   1204 	}
   1205 
   1206 	threadstats = malloc(nr_ts * sizeof(struct thread_stat));
   1207 
   1208 	for (i = 0; i < nr_ts; i++)
   1209 		init_thread_stat(&threadstats[i]);
   1210 
   1211 	j = 0;
   1212 	last_ts = -1;
   1213 	idx = 0;
   1214 	for_each_td(td, i) {
   1215 		if (idx && (!td->o.group_reporting ||
   1216 		    (td->o.group_reporting && last_ts != td->groupid))) {
   1217 			idx = 0;
   1218 			j++;
   1219 		}
   1220 
   1221 		last_ts = td->groupid;
   1222 
   1223 		ts = &threadstats[j];
   1224 
   1225 		ts->clat_percentiles = td->o.clat_percentiles;
   1226 		ts->percentile_precision = td->o.percentile_precision;
   1227 		memcpy(ts->percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
   1228 
   1229 		idx++;
   1230 		ts->members++;
   1231 
   1232 		if (ts->groupid == -1) {
   1233 			/*
   1234 			 * These are per-group shared already
   1235 			 */
   1236 			strncpy(ts->name, td->o.name, FIO_JOBNAME_SIZE - 1);
   1237 			if (td->o.description)
   1238 				strncpy(ts->description, td->o.description,
   1239 						FIO_JOBDESC_SIZE - 1);
   1240 			else
   1241 				memset(ts->description, 0, FIO_JOBDESC_SIZE);
   1242 
   1243 			/*
   1244 			 * If multiple entries in this group, this is
   1245 			 * the first member.
   1246 			 */
   1247 			ts->thread_number = td->thread_number;
   1248 			ts->groupid = td->groupid;
   1249 
   1250 			/*
   1251 			 * first pid in group, not very useful...
   1252 			 */
   1253 			ts->pid = td->pid;
   1254 
   1255 			ts->kb_base = td->o.kb_base;
   1256 			ts->unit_base = td->o.unit_base;
   1257 			ts->unified_rw_rep = td->o.unified_rw_rep;
   1258 		} else if (ts->kb_base != td->o.kb_base && !kb_base_warned) {
   1259 			log_info("fio: kb_base differs for jobs in group, using"
   1260 				 " %u as the base\n", ts->kb_base);
   1261 			kb_base_warned = 1;
   1262 		} else if (ts->unit_base != td->o.unit_base && !unit_base_warned) {
   1263 			log_info("fio: unit_base differs for jobs in group, using"
   1264 				 " %u as the base\n", ts->unit_base);
   1265 			unit_base_warned = 1;
   1266 		}
   1267 
   1268 		ts->continue_on_error = td->o.continue_on_error;
   1269 		ts->total_err_count += td->total_err_count;
   1270 		ts->first_error = td->first_error;
   1271 		if (!ts->error) {
   1272 			if (!td->error && td->o.continue_on_error &&
   1273 			    td->first_error) {
   1274 				ts->error = td->first_error;
   1275 				ts->verror[sizeof(ts->verror) - 1] = '\0';
   1276 				strncpy(ts->verror, td->verror, sizeof(ts->verror) - 1);
   1277 			} else  if (td->error) {
   1278 				ts->error = td->error;
   1279 				ts->verror[sizeof(ts->verror) - 1] = '\0';
   1280 				strncpy(ts->verror, td->verror, sizeof(ts->verror) - 1);
   1281 			}
   1282 		}
   1283 
   1284 		ts->latency_depth = td->latency_qd;
   1285 		ts->latency_target = td->o.latency_target;
   1286 		ts->latency_percentile = td->o.latency_percentile;
   1287 		ts->latency_window = td->o.latency_window;
   1288 
   1289 		sum_thread_stats(ts, &td->ts, idx);
   1290 	}
   1291 
   1292 	for (i = 0; i < nr_ts; i++) {
   1293 		unsigned long long bw;
   1294 
   1295 		ts = &threadstats[i];
   1296 		rs = &runstats[ts->groupid];
   1297 		rs->kb_base = ts->kb_base;
   1298 		rs->unit_base = ts->unit_base;
   1299 		rs->unified_rw_rep += ts->unified_rw_rep;
   1300 
   1301 		for (j = 0; j < DDIR_RWDIR_CNT; j++) {
   1302 			if (!ts->runtime[j])
   1303 				continue;
   1304 			if (ts->runtime[j] < rs->min_run[j] || !rs->min_run[j])
   1305 				rs->min_run[j] = ts->runtime[j];
   1306 			if (ts->runtime[j] > rs->max_run[j])
   1307 				rs->max_run[j] = ts->runtime[j];
   1308 
   1309 			bw = 0;
   1310 			if (ts->runtime[j]) {
   1311 				unsigned long runt = ts->runtime[j];
   1312 				unsigned long long kb;
   1313 
   1314 				kb = ts->io_bytes[j] / rs->kb_base;
   1315 				bw = kb * 1000 / runt;
   1316 			}
   1317 			if (bw < rs->min_bw[j])
   1318 				rs->min_bw[j] = bw;
   1319 			if (bw > rs->max_bw[j])
   1320 				rs->max_bw[j] = bw;
   1321 
   1322 			rs->io_kb[j] += ts->io_bytes[j] / rs->kb_base;
   1323 		}
   1324 	}
   1325 
   1326 	for (i = 0; i < groupid + 1; i++) {
   1327 		int ddir;
   1328 
   1329 		rs = &runstats[i];
   1330 
   1331 		for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
   1332 			if (rs->max_run[ddir])
   1333 				rs->agg[ddir] = (rs->io_kb[ddir] * 1000) /
   1334 						rs->max_run[ddir];
   1335 		}
   1336 	}
   1337 
   1338 	/*
   1339 	 * don't overwrite last signal output
   1340 	 */
   1341 	if (output_format == FIO_OUTPUT_NORMAL)
   1342 		log_info("\n");
   1343 	else if (output_format == FIO_OUTPUT_JSON) {
   1344 		root = json_create_object();
   1345 		json_object_add_value_string(root, "fio version", fio_version_string);
   1346 		array = json_create_array();
   1347 		json_object_add_value_array(root, "jobs", array);
   1348 	}
   1349 
   1350 	for (i = 0; i < nr_ts; i++) {
   1351 		ts = &threadstats[i];
   1352 		rs = &runstats[ts->groupid];
   1353 
   1354 		if (is_backend)
   1355 			fio_server_send_ts(ts, rs);
   1356 		else if (output_format == FIO_OUTPUT_TERSE)
   1357 			show_thread_status_terse(ts, rs);
   1358 		else if (output_format == FIO_OUTPUT_JSON) {
   1359 			struct json_object *tmp = show_thread_status_json(ts, rs);
   1360 			json_array_add_value_object(array, tmp);
   1361 		} else
   1362 			show_thread_status_normal(ts, rs);
   1363 	}
   1364 	if (output_format == FIO_OUTPUT_JSON) {
   1365 		/* disk util stats, if any */
   1366 		show_disk_util(1, root);
   1367 
   1368 		show_idle_prof_stats(FIO_OUTPUT_JSON, root);
   1369 
   1370 		json_print_object(root);
   1371 		log_info("\n");
   1372 		json_free_object(root);
   1373 	}
   1374 
   1375 	for (i = 0; i < groupid + 1; i++) {
   1376 		rs = &runstats[i];
   1377 
   1378 		rs->groupid = i;
   1379 		if (is_backend)
   1380 			fio_server_send_gs(rs);
   1381 		else if (output_format == FIO_OUTPUT_NORMAL)
   1382 			show_group_stats(rs);
   1383 	}
   1384 
   1385 	if (is_backend)
   1386 		fio_server_send_du();
   1387 	else if (output_format == FIO_OUTPUT_NORMAL) {
   1388 		show_disk_util(0, NULL);
   1389 		show_idle_prof_stats(FIO_OUTPUT_NORMAL, NULL);
   1390 	}
   1391 
   1392 	if ( !(output_format == FIO_OUTPUT_TERSE) && append_terse_output) {
   1393 		log_info("\nAdditional Terse Output:\n");
   1394 
   1395 		for (i = 0; i < nr_ts; i++) {
   1396 			ts = &threadstats[i];
   1397 			rs = &runstats[ts->groupid];
   1398 			show_thread_status_terse(ts, rs);
   1399 		}
   1400 	}
   1401 
   1402 	log_info_flush();
   1403 	free(runstats);
   1404 	free(threadstats);
   1405 }
   1406 
   1407 void show_run_stats(void)
   1408 {
   1409 	fio_mutex_down(stat_mutex);
   1410 	__show_run_stats();
   1411 	fio_mutex_up(stat_mutex);
   1412 }
   1413 
   1414 static void *__show_running_run_stats(void fio_unused *arg)
   1415 {
   1416 	struct thread_data *td;
   1417 	unsigned long long *rt;
   1418 	struct timeval tv;
   1419 	int i;
   1420 
   1421 	rt = malloc(thread_number * sizeof(unsigned long long));
   1422 	fio_gettime(&tv, NULL);
   1423 
   1424 	for_each_td(td, i) {
   1425 		rt[i] = mtime_since(&td->start, &tv);
   1426 		if (td_read(td) && td->io_bytes[DDIR_READ])
   1427 			td->ts.runtime[DDIR_READ] += rt[i];
   1428 		if (td_write(td) && td->io_bytes[DDIR_WRITE])
   1429 			td->ts.runtime[DDIR_WRITE] += rt[i];
   1430 		if (td_trim(td) && td->io_bytes[DDIR_TRIM])
   1431 			td->ts.runtime[DDIR_TRIM] += rt[i];
   1432 
   1433 		td->update_rusage = 1;
   1434 		td->ts.io_bytes[DDIR_READ] = td->io_bytes[DDIR_READ];
   1435 		td->ts.io_bytes[DDIR_WRITE] = td->io_bytes[DDIR_WRITE];
   1436 		td->ts.io_bytes[DDIR_TRIM] = td->io_bytes[DDIR_TRIM];
   1437 		td->ts.total_run_time = mtime_since(&td->epoch, &tv);
   1438 	}
   1439 
   1440 	for_each_td(td, i) {
   1441 		if (td->rusage_sem) {
   1442 			td->update_rusage = 1;
   1443 			fio_mutex_down(td->rusage_sem);
   1444 		}
   1445 		td->update_rusage = 0;
   1446 	}
   1447 
   1448 	__show_run_stats();
   1449 
   1450 	for_each_td(td, i) {
   1451 		if (td_read(td) && td->io_bytes[DDIR_READ])
   1452 			td->ts.runtime[DDIR_READ] -= rt[i];
   1453 		if (td_write(td) && td->io_bytes[DDIR_WRITE])
   1454 			td->ts.runtime[DDIR_WRITE] -= rt[i];
   1455 		if (td_trim(td) && td->io_bytes[DDIR_TRIM])
   1456 			td->ts.runtime[DDIR_TRIM] -= rt[i];
   1457 	}
   1458 
   1459 	free(rt);
   1460 	fio_mutex_up(stat_mutex);
   1461 	return NULL;
   1462 }
   1463 
   1464 /*
   1465  * Called from signal handler. It _should_ be safe to just run this inline
   1466  * in the sig handler, but we should be disturbing the system less by just
   1467  * creating a thread to do it.
   1468  */
   1469 void show_running_run_stats(void)
   1470 {
   1471 	pthread_t thread;
   1472 
   1473 	fio_mutex_down(stat_mutex);
   1474 
   1475 	if (!pthread_create(&thread, NULL, __show_running_run_stats, NULL)) {
   1476 		int err;
   1477 
   1478 		err = pthread_detach(thread);
   1479 		if (err)
   1480 			log_err("fio: DU thread detach failed: %s\n", strerror(err));
   1481 
   1482 		return;
   1483 	}
   1484 
   1485 	fio_mutex_up(stat_mutex);
   1486 }
   1487 
   1488 static int status_interval_init;
   1489 static struct timeval status_time;
   1490 static int status_file_disabled;
   1491 
   1492 #define FIO_STATUS_FILE		"fio-dump-status"
   1493 
   1494 static int check_status_file(void)
   1495 {
   1496 	struct stat sb;
   1497 	const char *temp_dir;
   1498 	char fio_status_file_path[PATH_MAX];
   1499 
   1500 	if (status_file_disabled)
   1501 		return 0;
   1502 
   1503 	temp_dir = getenv("TMPDIR");
   1504 	if (temp_dir == NULL) {
   1505 		temp_dir = getenv("TEMP");
   1506 		if (temp_dir && strlen(temp_dir) >= PATH_MAX)
   1507 			temp_dir = NULL;
   1508 	}
   1509 	if (temp_dir == NULL)
   1510 		temp_dir = "/tmp";
   1511 
   1512 	snprintf(fio_status_file_path, sizeof(fio_status_file_path), "%s/%s", temp_dir, FIO_STATUS_FILE);
   1513 
   1514 	if (stat(fio_status_file_path, &sb))
   1515 		return 0;
   1516 
   1517 	if (unlink(fio_status_file_path) < 0) {
   1518 		log_err("fio: failed to unlink %s: %s\n", fio_status_file_path,
   1519 							strerror(errno));
   1520 		log_err("fio: disabling status file updates\n");
   1521 		status_file_disabled = 1;
   1522 	}
   1523 
   1524 	return 1;
   1525 }
   1526 
   1527 void check_for_running_stats(void)
   1528 {
   1529 	if (status_interval) {
   1530 		if (!status_interval_init) {
   1531 			fio_gettime(&status_time, NULL);
   1532 			status_interval_init = 1;
   1533 		} else if (mtime_since_now(&status_time) >= status_interval) {
   1534 			show_running_run_stats();
   1535 			fio_gettime(&status_time, NULL);
   1536 			return;
   1537 		}
   1538 	}
   1539 	if (check_status_file()) {
   1540 		show_running_run_stats();
   1541 		return;
   1542 	}
   1543 }
   1544 
   1545 static inline void add_stat_sample(struct io_stat *is, unsigned long data)
   1546 {
   1547 	double val = data;
   1548 	double delta;
   1549 
   1550 	if (data > is->max_val)
   1551 		is->max_val = data;
   1552 	if (data < is->min_val)
   1553 		is->min_val = data;
   1554 
   1555 	delta = val - is->mean.u.f;
   1556 	if (delta) {
   1557 		is->mean.u.f += delta / (is->samples + 1.0);
   1558 		is->S.u.f += delta * (val - is->mean.u.f);
   1559 	}
   1560 
   1561 	is->samples++;
   1562 }
   1563 
   1564 static void __add_log_sample(struct io_log *iolog, unsigned long val,
   1565 			     enum fio_ddir ddir, unsigned int bs,
   1566 			     unsigned long t)
   1567 {
   1568 	const int nr_samples = iolog->nr_samples;
   1569 
   1570 	if (iolog->disabled)
   1571 		return;
   1572 
   1573 	if (!iolog->nr_samples)
   1574 		iolog->avg_last = t;
   1575 
   1576 	if (iolog->nr_samples == iolog->max_samples) {
   1577 		int new_size = sizeof(struct io_sample) * iolog->max_samples*2;
   1578 		void *new_log;
   1579 
   1580 		new_log = realloc(iolog->log, new_size);
   1581 		if (!new_log) {
   1582 			log_err("fio: failed extending iolog! Will stop logging.\n");
   1583 			iolog->disabled = 1;
   1584 			return;
   1585 		}
   1586 		iolog->log = new_log;
   1587 		iolog->max_samples <<= 1;
   1588 	}
   1589 
   1590 	iolog->log[nr_samples].val = val;
   1591 	iolog->log[nr_samples].time = t;
   1592 	iolog->log[nr_samples].ddir = ddir;
   1593 	iolog->log[nr_samples].bs = bs;
   1594 	iolog->nr_samples++;
   1595 }
   1596 
   1597 static inline void reset_io_stat(struct io_stat *ios)
   1598 {
   1599 	ios->max_val = ios->min_val = ios->samples = 0;
   1600 	ios->mean.u.f = ios->S.u.f = 0;
   1601 }
   1602 
   1603 void reset_io_stats(struct thread_data *td)
   1604 {
   1605 	struct thread_stat *ts = &td->ts;
   1606 	int i, j;
   1607 
   1608 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
   1609 		reset_io_stat(&ts->clat_stat[i]);
   1610 		reset_io_stat(&ts->slat_stat[i]);
   1611 		reset_io_stat(&ts->lat_stat[i]);
   1612 		reset_io_stat(&ts->bw_stat[i]);
   1613 		reset_io_stat(&ts->iops_stat[i]);
   1614 
   1615 		ts->io_bytes[i] = 0;
   1616 		ts->runtime[i] = 0;
   1617 
   1618 		for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
   1619 			ts->io_u_plat[i][j] = 0;
   1620 	}
   1621 
   1622 	for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
   1623 		ts->io_u_map[i] = 0;
   1624 		ts->io_u_submit[i] = 0;
   1625 		ts->io_u_complete[i] = 0;
   1626 		ts->io_u_lat_u[i] = 0;
   1627 		ts->io_u_lat_m[i] = 0;
   1628 		ts->total_submit = 0;
   1629 		ts->total_complete = 0;
   1630 	}
   1631 
   1632 	for (i = 0; i < 3; i++) {
   1633 		ts->total_io_u[i] = 0;
   1634 		ts->short_io_u[i] = 0;
   1635 	}
   1636 }
   1637 
   1638 static void _add_stat_to_log(struct io_log *iolog, unsigned long elapsed)
   1639 {
   1640 	/*
   1641 	 * Note an entry in the log. Use the mean from the logged samples,
   1642 	 * making sure to properly round up. Only write a log entry if we
   1643 	 * had actual samples done.
   1644 	 */
   1645 	if (iolog->avg_window[DDIR_READ].samples) {
   1646 		unsigned long mr;
   1647 
   1648 		mr = iolog->avg_window[DDIR_READ].mean.u.f + 0.50;
   1649 		__add_log_sample(iolog, mr, DDIR_READ, 0, elapsed);
   1650 	}
   1651 	if (iolog->avg_window[DDIR_WRITE].samples) {
   1652 		unsigned long mw;
   1653 
   1654 		mw = iolog->avg_window[DDIR_WRITE].mean.u.f + 0.50;
   1655 		__add_log_sample(iolog, mw, DDIR_WRITE, 0, elapsed);
   1656 	}
   1657 	if (iolog->avg_window[DDIR_TRIM].samples) {
   1658 		unsigned long mw;
   1659 
   1660 		mw = iolog->avg_window[DDIR_TRIM].mean.u.f + 0.50;
   1661 		__add_log_sample(iolog, mw, DDIR_TRIM, 0, elapsed);
   1662 	}
   1663 
   1664 	reset_io_stat(&iolog->avg_window[DDIR_READ]);
   1665 	reset_io_stat(&iolog->avg_window[DDIR_WRITE]);
   1666 	reset_io_stat(&iolog->avg_window[DDIR_TRIM]);
   1667 }
   1668 
   1669 static void add_log_sample(struct thread_data *td, struct io_log *iolog,
   1670 			   unsigned long val, enum fio_ddir ddir,
   1671 			   unsigned int bs)
   1672 {
   1673 	unsigned long elapsed, this_window;
   1674 
   1675 	if (!ddir_rw(ddir))
   1676 		return;
   1677 
   1678 	elapsed = mtime_since_now(&td->epoch);
   1679 
   1680 	/*
   1681 	 * If no time averaging, just add the log sample.
   1682 	 */
   1683 	if (!iolog->avg_msec) {
   1684 		__add_log_sample(iolog, val, ddir, bs, elapsed);
   1685 		return;
   1686 	}
   1687 
   1688 	/*
   1689 	 * Add the sample. If the time period has passed, then
   1690 	 * add that entry to the log and clear.
   1691 	 */
   1692 	add_stat_sample(&iolog->avg_window[ddir], val);
   1693 
   1694 	/*
   1695 	 * If period hasn't passed, adding the above sample is all we
   1696 	 * need to do.
   1697 	 */
   1698 	this_window = elapsed - iolog->avg_last;
   1699 	if (this_window < iolog->avg_msec)
   1700 		return;
   1701 
   1702 	_add_stat_to_log(iolog, elapsed);
   1703 
   1704 	iolog->avg_last = elapsed;
   1705 }
   1706 
   1707 void finalize_logs(struct thread_data *td)
   1708 {
   1709 	unsigned long elapsed;
   1710 
   1711 	elapsed = mtime_since_now(&td->epoch);
   1712 
   1713 	if (td->clat_log)
   1714 		_add_stat_to_log(td->clat_log, elapsed);
   1715 	if (td->slat_log)
   1716 		_add_stat_to_log(td->slat_log, elapsed);
   1717 	if (td->lat_log)
   1718 		_add_stat_to_log(td->lat_log, elapsed);
   1719 	if (td->bw_log)
   1720 		_add_stat_to_log(td->bw_log, elapsed);
   1721 	if (td->iops_log)
   1722 		_add_stat_to_log(td->iops_log, elapsed);
   1723 }
   1724 
   1725 void add_agg_sample(unsigned long val, enum fio_ddir ddir, unsigned int bs)
   1726 {
   1727 	struct io_log *iolog;
   1728 
   1729 	if (!ddir_rw(ddir))
   1730 		return;
   1731 
   1732 	iolog = agg_io_log[ddir];
   1733 	__add_log_sample(iolog, val, ddir, bs, mtime_since_genesis());
   1734 }
   1735 
   1736 static void add_clat_percentile_sample(struct thread_stat *ts,
   1737 				unsigned long usec, enum fio_ddir ddir)
   1738 {
   1739 	unsigned int idx = plat_val_to_idx(usec);
   1740 	assert(idx < FIO_IO_U_PLAT_NR);
   1741 
   1742 	ts->io_u_plat[ddir][idx]++;
   1743 }
   1744 
   1745 void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
   1746 		     unsigned long usec, unsigned int bs)
   1747 {
   1748 	struct thread_stat *ts = &td->ts;
   1749 
   1750 	if (!ddir_rw(ddir))
   1751 		return;
   1752 
   1753 	add_stat_sample(&ts->clat_stat[ddir], usec);
   1754 
   1755 	if (td->clat_log)
   1756 		add_log_sample(td, td->clat_log, usec, ddir, bs);
   1757 
   1758 	if (ts->clat_percentiles)
   1759 		add_clat_percentile_sample(ts, usec, ddir);
   1760 }
   1761 
   1762 void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
   1763 		     unsigned long usec, unsigned int bs)
   1764 {
   1765 	struct thread_stat *ts = &td->ts;
   1766 
   1767 	if (!ddir_rw(ddir))
   1768 		return;
   1769 
   1770 	add_stat_sample(&ts->slat_stat[ddir], usec);
   1771 
   1772 	if (td->slat_log)
   1773 		add_log_sample(td, td->slat_log, usec, ddir, bs);
   1774 }
   1775 
   1776 void add_lat_sample(struct thread_data *td, enum fio_ddir ddir,
   1777 		    unsigned long usec, unsigned int bs)
   1778 {
   1779 	struct thread_stat *ts = &td->ts;
   1780 
   1781 	if (!ddir_rw(ddir))
   1782 		return;
   1783 
   1784 	add_stat_sample(&ts->lat_stat[ddir], usec);
   1785 
   1786 	if (td->lat_log)
   1787 		add_log_sample(td, td->lat_log, usec, ddir, bs);
   1788 }
   1789 
   1790 void add_bw_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs,
   1791 		   struct timeval *t)
   1792 {
   1793 	struct thread_stat *ts = &td->ts;
   1794 	unsigned long spent, rate;
   1795 
   1796 	if (!ddir_rw(ddir))
   1797 		return;
   1798 
   1799 	spent = mtime_since(&td->bw_sample_time, t);
   1800 	if (spent < td->o.bw_avg_time)
   1801 		return;
   1802 
   1803 	/*
   1804 	 * Compute both read and write rates for the interval.
   1805 	 */
   1806 	for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
   1807 		uint64_t delta;
   1808 
   1809 		delta = td->this_io_bytes[ddir] - td->stat_io_bytes[ddir];
   1810 		if (!delta)
   1811 			continue; /* No entries for interval */
   1812 
   1813 		if (spent)
   1814 			rate = delta * 1000 / spent / 1024;
   1815 		else
   1816 			rate = 0;
   1817 
   1818 		add_stat_sample(&ts->bw_stat[ddir], rate);
   1819 
   1820 		if (td->bw_log)
   1821 			add_log_sample(td, td->bw_log, rate, ddir, bs);
   1822 
   1823 		td->stat_io_bytes[ddir] = td->this_io_bytes[ddir];
   1824 	}
   1825 
   1826 	fio_gettime(&td->bw_sample_time, NULL);
   1827 }
   1828 
   1829 void add_iops_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs,
   1830 		     struct timeval *t)
   1831 {
   1832 	struct thread_stat *ts = &td->ts;
   1833 	unsigned long spent, iops;
   1834 
   1835 	if (!ddir_rw(ddir))
   1836 		return;
   1837 
   1838 	spent = mtime_since(&td->iops_sample_time, t);
   1839 	if (spent < td->o.iops_avg_time)
   1840 		return;
   1841 
   1842 	/*
   1843 	 * Compute both read and write rates for the interval.
   1844 	 */
   1845 	for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
   1846 		uint64_t delta;
   1847 
   1848 		delta = td->this_io_blocks[ddir] - td->stat_io_blocks[ddir];
   1849 		if (!delta)
   1850 			continue; /* No entries for interval */
   1851 
   1852 		if (spent)
   1853 			iops = (delta * 1000) / spent;
   1854 		else
   1855 			iops = 0;
   1856 
   1857 		add_stat_sample(&ts->iops_stat[ddir], iops);
   1858 
   1859 		if (td->iops_log)
   1860 			add_log_sample(td, td->iops_log, iops, ddir, bs);
   1861 
   1862 		td->stat_io_blocks[ddir] = td->this_io_blocks[ddir];
   1863 	}
   1864 
   1865 	fio_gettime(&td->iops_sample_time, NULL);
   1866 }
   1867 
   1868 void stat_init(void)
   1869 {
   1870 	stat_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
   1871 }
   1872 
   1873 void stat_exit(void)
   1874 {
   1875 	/*
   1876 	 * When we have the mutex, we know out-of-band access to it
   1877 	 * have ended.
   1878 	 */
   1879 	fio_mutex_down(stat_mutex);
   1880 	fio_mutex_remove(stat_mutex);
   1881 }
   1882