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 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 *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" : 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 *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" : 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[32];
    508 
    509 	if (!ddir_rw_sum(ts->io_bytes) && !ddir_rw_sum(ts->total_io_u))
    510 		return;
    511 
    512 	time(&time_p);
    513 	os_ctime_r((const time_t *) &time_p, time_buf, sizeof(time_buf));
    514 
    515 	if (!ts->error) {
    516 		log_info("%s: (groupid=%d, jobs=%d): err=%2d: pid=%d: %s",
    517 					ts->name, ts->groupid, ts->members,
    518 					ts->error, (int) ts->pid, time_buf);
    519 	} else {
    520 		log_info("%s: (groupid=%d, jobs=%d): err=%2d (%s): pid=%d: %s",
    521 					ts->name, ts->groupid, ts->members,
    522 					ts->error, ts->verror, (int) ts->pid,
    523 					time_buf);
    524 	}
    525 
    526 	if (strlen(ts->description))
    527 		log_info("  Description  : [%s]\n", ts->description);
    528 
    529 	if (ts->io_bytes[DDIR_READ])
    530 		show_ddir_status(rs, ts, DDIR_READ);
    531 	if (ts->io_bytes[DDIR_WRITE])
    532 		show_ddir_status(rs, ts, DDIR_WRITE);
    533 	if (ts->io_bytes[DDIR_TRIM])
    534 		show_ddir_status(rs, ts, DDIR_TRIM);
    535 
    536 	show_latencies(ts);
    537 
    538 	runtime = ts->total_run_time;
    539 	if (runtime) {
    540 		double runt = (double) runtime;
    541 
    542 		usr_cpu = (double) ts->usr_time * 100 / runt;
    543 		sys_cpu = (double) ts->sys_time * 100 / runt;
    544 	} else {
    545 		usr_cpu = 0;
    546 		sys_cpu = 0;
    547 	}
    548 
    549 	log_info("  cpu          : usr=%3.2f%%, sys=%3.2f%%, ctx=%llu,"
    550 		 " majf=%llu, minf=%llu\n", usr_cpu, sys_cpu,
    551 			(unsigned long long) ts->ctx,
    552 			(unsigned long long) ts->majf,
    553 			(unsigned long long) ts->minf);
    554 
    555 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    556 	log_info("  IO depths    : 1=%3.1f%%, 2=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%,"
    557 		 " 16=%3.1f%%, 32=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
    558 					io_u_dist[1], io_u_dist[2],
    559 					io_u_dist[3], io_u_dist[4],
    560 					io_u_dist[5], io_u_dist[6]);
    561 
    562 	stat_calc_dist(ts->io_u_submit, ts->total_submit, io_u_dist);
    563 	log_info("     submit    : 0=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%, 16=%3.1f%%,"
    564 		 " 32=%3.1f%%, 64=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
    565 					io_u_dist[1], io_u_dist[2],
    566 					io_u_dist[3], io_u_dist[4],
    567 					io_u_dist[5], io_u_dist[6]);
    568 	stat_calc_dist(ts->io_u_complete, ts->total_complete, io_u_dist);
    569 	log_info("     complete  : 0=%3.1f%%, 4=%3.1f%%, 8=%3.1f%%, 16=%3.1f%%,"
    570 		 " 32=%3.1f%%, 64=%3.1f%%, >=64=%3.1f%%\n", io_u_dist[0],
    571 					io_u_dist[1], io_u_dist[2],
    572 					io_u_dist[3], io_u_dist[4],
    573 					io_u_dist[5], io_u_dist[6]);
    574 	log_info("     issued    : total=r=%llu/w=%llu/d=%llu,"
    575 				 " short=r=%llu/w=%llu/d=%llu,"
    576 				 " drop=r=%llu/w=%llu/d=%llu\n",
    577 					(unsigned long long) ts->total_io_u[0],
    578 					(unsigned long long) ts->total_io_u[1],
    579 					(unsigned long long) ts->total_io_u[2],
    580 					(unsigned long long) ts->short_io_u[0],
    581 					(unsigned long long) ts->short_io_u[1],
    582 					(unsigned long long) ts->short_io_u[2],
    583 					(unsigned long long) ts->drop_io_u[0],
    584 					(unsigned long long) ts->drop_io_u[1],
    585 					(unsigned long long) ts->drop_io_u[2]);
    586 	if (ts->continue_on_error) {
    587 		log_info("     errors    : total=%llu, first_error=%d/<%s>\n",
    588 					(unsigned long long)ts->total_err_count,
    589 					ts->first_error,
    590 					strerror(ts->first_error));
    591 	}
    592 	if (ts->latency_depth) {
    593 		log_info("     latency   : target=%llu, window=%llu, percentile=%.2f%%, depth=%u\n",
    594 					(unsigned long long)ts->latency_target,
    595 					(unsigned long long)ts->latency_window,
    596 					ts->latency_percentile.u.f,
    597 					ts->latency_depth);
    598 	}
    599 }
    600 
    601 static void show_ddir_status_terse(struct thread_stat *ts,
    602 				   struct group_run_stats *rs, int ddir)
    603 {
    604 	unsigned long min, max;
    605 	unsigned long long bw, iops;
    606 	unsigned int *ovals = NULL;
    607 	double mean, dev;
    608 	unsigned int len, minv, maxv;
    609 	int i;
    610 
    611 	assert(ddir_rw(ddir));
    612 
    613 	iops = bw = 0;
    614 	if (ts->runtime[ddir]) {
    615 		uint64_t runt = ts->runtime[ddir];
    616 
    617 		bw = ((1000 * ts->io_bytes[ddir]) / runt) / 1024;
    618 		iops = (1000 * (uint64_t) ts->total_io_u[ddir]) / runt;
    619 	}
    620 
    621 	log_info(";%llu;%llu;%llu;%llu",
    622 		(unsigned long long) ts->io_bytes[ddir] >> 10, bw, iops,
    623 					(unsigned long long) ts->runtime[ddir]);
    624 
    625 	if (calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev))
    626 		log_info(";%lu;%lu;%f;%f", min, max, mean, dev);
    627 	else
    628 		log_info(";%lu;%lu;%f;%f", 0UL, 0UL, 0.0, 0.0);
    629 
    630 	if (calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev))
    631 		log_info(";%lu;%lu;%f;%f", min, max, mean, dev);
    632 	else
    633 		log_info(";%lu;%lu;%f;%f", 0UL, 0UL, 0.0, 0.0);
    634 
    635 	if (ts->clat_percentiles) {
    636 		len = calc_clat_percentiles(ts->io_u_plat[ddir],
    637 					ts->clat_stat[ddir].samples,
    638 					ts->percentile_list, &ovals, &maxv,
    639 					&minv);
    640 	} else
    641 		len = 0;
    642 
    643 	for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
    644 		if (i >= len) {
    645 			log_info(";0%%=0");
    646 			continue;
    647 		}
    648 		log_info(";%f%%=%u", ts->percentile_list[i].u.f, ovals[i]);
    649 	}
    650 
    651 	if (calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev))
    652 		log_info(";%lu;%lu;%f;%f", min, max, mean, dev);
    653 	else
    654 		log_info(";%lu;%lu;%f;%f", 0UL, 0UL, 0.0, 0.0);
    655 
    656 	if (ovals)
    657 		free(ovals);
    658 
    659 	if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
    660 		double p_of_agg = 100.0;
    661 
    662 		if (rs->agg[ddir]) {
    663 			p_of_agg = mean * 100 / (double) rs->agg[ddir];
    664 			if (p_of_agg > 100.0)
    665 				p_of_agg = 100.0;
    666 		}
    667 
    668 		log_info(";%lu;%lu;%f%%;%f;%f", min, max, p_of_agg, mean, dev);
    669 	} else
    670 		log_info(";%lu;%lu;%f%%;%f;%f", 0UL, 0UL, 0.0, 0.0, 0.0);
    671 }
    672 
    673 static void add_ddir_status_json(struct thread_stat *ts,
    674 		struct group_run_stats *rs, int ddir, struct json_object *parent)
    675 {
    676 	unsigned long min, max;
    677 	unsigned long long bw;
    678 	unsigned int *ovals = NULL;
    679 	double mean, dev, iops;
    680 	unsigned int len, minv, maxv;
    681 	int i;
    682 	const char *ddirname[] = {"read", "write", "trim"};
    683 	struct json_object *dir_object, *tmp_object, *percentile_object;
    684 	char buf[120];
    685 	double p_of_agg = 100.0;
    686 
    687 	assert(ddir_rw(ddir));
    688 
    689 	if (ts->unified_rw_rep && ddir != DDIR_READ)
    690 		return;
    691 
    692 	dir_object = json_create_object();
    693 	json_object_add_value_object(parent,
    694 		ts->unified_rw_rep ? "mixed" : ddirname[ddir], dir_object);
    695 
    696 	bw = 0;
    697 	iops = 0.0;
    698 	if (ts->runtime[ddir]) {
    699 		uint64_t runt = ts->runtime[ddir];
    700 
    701 		bw = ((1000 * ts->io_bytes[ddir]) / runt) / 1024;
    702 		iops = (1000.0 * (uint64_t) ts->total_io_u[ddir]) / runt;
    703 	}
    704 
    705 	json_object_add_value_int(dir_object, "io_bytes", ts->io_bytes[ddir] >> 10);
    706 	json_object_add_value_int(dir_object, "bw", bw);
    707 	json_object_add_value_float(dir_object, "iops", iops);
    708 	json_object_add_value_int(dir_object, "runtime", ts->runtime[ddir]);
    709 	json_object_add_value_int(dir_object, "total_ios", ts->total_io_u[ddir]);
    710 	json_object_add_value_int(dir_object, "short_ios", ts->short_io_u[ddir]);
    711 	json_object_add_value_int(dir_object, "drop_ios", ts->drop_io_u[ddir]);
    712 
    713 	if (!calc_lat(&ts->slat_stat[ddir], &min, &max, &mean, &dev)) {
    714 		min = max = 0;
    715 		mean = dev = 0.0;
    716 	}
    717 	tmp_object = json_create_object();
    718 	json_object_add_value_object(dir_object, "slat", tmp_object);
    719 	json_object_add_value_int(tmp_object, "min", min);
    720 	json_object_add_value_int(tmp_object, "max", max);
    721 	json_object_add_value_float(tmp_object, "mean", mean);
    722 	json_object_add_value_float(tmp_object, "stddev", dev);
    723 
    724 	if (!calc_lat(&ts->clat_stat[ddir], &min, &max, &mean, &dev)) {
    725 		min = max = 0;
    726 		mean = dev = 0.0;
    727 	}
    728 	tmp_object = json_create_object();
    729 	json_object_add_value_object(dir_object, "clat", tmp_object);
    730 	json_object_add_value_int(tmp_object, "min", min);
    731 	json_object_add_value_int(tmp_object, "max", max);
    732 	json_object_add_value_float(tmp_object, "mean", mean);
    733 	json_object_add_value_float(tmp_object, "stddev", dev);
    734 
    735 	if (ts->clat_percentiles) {
    736 		len = calc_clat_percentiles(ts->io_u_plat[ddir],
    737 					ts->clat_stat[ddir].samples,
    738 					ts->percentile_list, &ovals, &maxv,
    739 					&minv);
    740 	} else
    741 		len = 0;
    742 
    743 	percentile_object = json_create_object();
    744 	json_object_add_value_object(tmp_object, "percentile", percentile_object);
    745 	for (i = 0; i < FIO_IO_U_LIST_MAX_LEN; i++) {
    746 		if (i >= len) {
    747 			json_object_add_value_int(percentile_object, "0.00", 0);
    748 			continue;
    749 		}
    750 		snprintf(buf, sizeof(buf), "%f", ts->percentile_list[i].u.f);
    751 		json_object_add_value_int(percentile_object, (const char *)buf, ovals[i]);
    752 	}
    753 
    754 	if (!calc_lat(&ts->lat_stat[ddir], &min, &max, &mean, &dev)) {
    755 		min = max = 0;
    756 		mean = dev = 0.0;
    757 	}
    758 	tmp_object = json_create_object();
    759 	json_object_add_value_object(dir_object, "lat", tmp_object);
    760 	json_object_add_value_int(tmp_object, "min", min);
    761 	json_object_add_value_int(tmp_object, "max", max);
    762 	json_object_add_value_float(tmp_object, "mean", mean);
    763 	json_object_add_value_float(tmp_object, "stddev", dev);
    764 	if (ovals)
    765 		free(ovals);
    766 
    767 	if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
    768 		if (rs->agg[ddir]) {
    769 			p_of_agg = mean * 100 / (double) rs->agg[ddir];
    770 			if (p_of_agg > 100.0)
    771 				p_of_agg = 100.0;
    772 		}
    773 	} else {
    774 		min = max = 0;
    775 		p_of_agg = mean = dev = 0.0;
    776 	}
    777 	json_object_add_value_int(dir_object, "bw_min", min);
    778 	json_object_add_value_int(dir_object, "bw_max", max);
    779 	json_object_add_value_float(dir_object, "bw_agg", p_of_agg);
    780 	json_object_add_value_float(dir_object, "bw_mean", mean);
    781 	json_object_add_value_float(dir_object, "bw_dev", dev);
    782 }
    783 
    784 static void show_thread_status_terse_v2(struct thread_stat *ts,
    785 					struct group_run_stats *rs)
    786 {
    787 	double io_u_dist[FIO_IO_U_MAP_NR];
    788 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    789 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    790 	double usr_cpu, sys_cpu;
    791 	int i;
    792 
    793 	/* General Info */
    794 	log_info("2;%s;%d;%d", ts->name, ts->groupid, ts->error);
    795 	/* Log Read Status */
    796 	show_ddir_status_terse(ts, rs, DDIR_READ);
    797 	/* Log Write Status */
    798 	show_ddir_status_terse(ts, rs, DDIR_WRITE);
    799 	/* Log Trim Status */
    800 	show_ddir_status_terse(ts, rs, DDIR_TRIM);
    801 
    802 	/* CPU Usage */
    803 	if (ts->total_run_time) {
    804 		double runt = (double) ts->total_run_time;
    805 
    806 		usr_cpu = (double) ts->usr_time * 100 / runt;
    807 		sys_cpu = (double) ts->sys_time * 100 / runt;
    808 	} else {
    809 		usr_cpu = 0;
    810 		sys_cpu = 0;
    811 	}
    812 
    813 	log_info(";%f%%;%f%%;%llu;%llu;%llu", usr_cpu, sys_cpu,
    814 						(unsigned long long) ts->ctx,
    815 						(unsigned long long) ts->majf,
    816 						(unsigned long long) ts->minf);
    817 
    818 	/* Calc % distribution of IO depths, usecond, msecond latency */
    819 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    820 	stat_calc_lat_u(ts, io_u_lat_u);
    821 	stat_calc_lat_m(ts, io_u_lat_m);
    822 
    823 	/* Only show fixed 7 I/O depth levels*/
    824 	log_info(";%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%",
    825 			io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3],
    826 			io_u_dist[4], io_u_dist[5], io_u_dist[6]);
    827 
    828 	/* Microsecond latency */
    829 	for (i = 0; i < FIO_IO_U_LAT_U_NR; i++)
    830 		log_info(";%3.2f%%", io_u_lat_u[i]);
    831 	/* Millisecond latency */
    832 	for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
    833 		log_info(";%3.2f%%", io_u_lat_m[i]);
    834 	/* Additional output if continue_on_error set - default off*/
    835 	if (ts->continue_on_error)
    836 		log_info(";%llu;%d", (unsigned long long) ts->total_err_count, ts->first_error);
    837 	log_info("\n");
    838 
    839 	/* Additional output if description is set */
    840 	if (strlen(ts->description))
    841 		log_info(";%s", ts->description);
    842 
    843 	log_info("\n");
    844 }
    845 
    846 static void show_thread_status_terse_v3_v4(struct thread_stat *ts,
    847 					   struct group_run_stats *rs, int ver)
    848 {
    849 	double io_u_dist[FIO_IO_U_MAP_NR];
    850 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    851 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    852 	double usr_cpu, sys_cpu;
    853 	int i;
    854 
    855 	/* General Info */
    856 	log_info("%d;%s;%s;%d;%d", ver, fio_version_string,
    857 					ts->name, ts->groupid, ts->error);
    858 	/* Log Read Status */
    859 	show_ddir_status_terse(ts, rs, DDIR_READ);
    860 	/* Log Write Status */
    861 	show_ddir_status_terse(ts, rs, DDIR_WRITE);
    862 	/* Log Trim Status */
    863 	if (ver == 4)
    864 		show_ddir_status_terse(ts, rs, DDIR_TRIM);
    865 
    866 	/* CPU Usage */
    867 	if (ts->total_run_time) {
    868 		double runt = (double) ts->total_run_time;
    869 
    870 		usr_cpu = (double) ts->usr_time * 100 / runt;
    871 		sys_cpu = (double) ts->sys_time * 100 / runt;
    872 	} else {
    873 		usr_cpu = 0;
    874 		sys_cpu = 0;
    875 	}
    876 
    877 	log_info(";%f%%;%f%%;%llu;%llu;%llu", usr_cpu, sys_cpu,
    878 						(unsigned long long) ts->ctx,
    879 						(unsigned long long) ts->majf,
    880 						(unsigned long long) ts->minf);
    881 
    882 	/* Calc % distribution of IO depths, usecond, msecond latency */
    883 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    884 	stat_calc_lat_u(ts, io_u_lat_u);
    885 	stat_calc_lat_m(ts, io_u_lat_m);
    886 
    887 	/* Only show fixed 7 I/O depth levels*/
    888 	log_info(";%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%",
    889 			io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3],
    890 			io_u_dist[4], io_u_dist[5], io_u_dist[6]);
    891 
    892 	/* Microsecond latency */
    893 	for (i = 0; i < FIO_IO_U_LAT_U_NR; i++)
    894 		log_info(";%3.2f%%", io_u_lat_u[i]);
    895 	/* Millisecond latency */
    896 	for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
    897 		log_info(";%3.2f%%", io_u_lat_m[i]);
    898 
    899 	/* disk util stats, if any */
    900 	show_disk_util(1, NULL);
    901 
    902 	/* Additional output if continue_on_error set - default off*/
    903 	if (ts->continue_on_error)
    904 		log_info(";%llu;%d", (unsigned long long) ts->total_err_count, ts->first_error);
    905 
    906 	/* Additional output if description is set */
    907 	if (strlen(ts->description))
    908 		log_info(";%s", ts->description);
    909 
    910 	log_info("\n");
    911 }
    912 
    913 static struct json_object *show_thread_status_json(struct thread_stat *ts,
    914 				    struct group_run_stats *rs)
    915 {
    916 	struct json_object *root, *tmp;
    917 	double io_u_dist[FIO_IO_U_MAP_NR];
    918 	double io_u_lat_u[FIO_IO_U_LAT_U_NR];
    919 	double io_u_lat_m[FIO_IO_U_LAT_M_NR];
    920 	double usr_cpu, sys_cpu;
    921 	int i;
    922 
    923 	root = json_create_object();
    924 	json_object_add_value_string(root, "jobname", ts->name);
    925 	json_object_add_value_int(root, "groupid", ts->groupid);
    926 	json_object_add_value_int(root, "error", ts->error);
    927 
    928 	add_ddir_status_json(ts, rs, DDIR_READ, root);
    929 	add_ddir_status_json(ts, rs, DDIR_WRITE, root);
    930 	add_ddir_status_json(ts, rs, DDIR_TRIM, root);
    931 
    932 	/* CPU Usage */
    933 	if (ts->total_run_time) {
    934 		double runt = (double) ts->total_run_time;
    935 
    936 		usr_cpu = (double) ts->usr_time * 100 / runt;
    937 		sys_cpu = (double) ts->sys_time * 100 / runt;
    938 	} else {
    939 		usr_cpu = 0;
    940 		sys_cpu = 0;
    941 	}
    942 	json_object_add_value_float(root, "usr_cpu", usr_cpu);
    943 	json_object_add_value_float(root, "sys_cpu", sys_cpu);
    944 	json_object_add_value_int(root, "ctx", ts->ctx);
    945 	json_object_add_value_int(root, "majf", ts->majf);
    946 	json_object_add_value_int(root, "minf", ts->minf);
    947 
    948 
    949 	/* Calc % distribution of IO depths, usecond, msecond latency */
    950 	stat_calc_dist(ts->io_u_map, ddir_rw_sum(ts->total_io_u), io_u_dist);
    951 	stat_calc_lat_u(ts, io_u_lat_u);
    952 	stat_calc_lat_m(ts, io_u_lat_m);
    953 
    954 	tmp = json_create_object();
    955 	json_object_add_value_object(root, "iodepth_level", tmp);
    956 	/* Only show fixed 7 I/O depth levels*/
    957 	for (i = 0; i < 7; i++) {
    958 		char name[20];
    959 		if (i < 6)
    960 			snprintf(name, 20, "%d", 1 << i);
    961 		else
    962 			snprintf(name, 20, ">=%d", 1 << i);
    963 		json_object_add_value_float(tmp, (const char *)name, io_u_dist[i]);
    964 	}
    965 
    966 	tmp = json_create_object();
    967 	json_object_add_value_object(root, "latency_us", tmp);
    968 	/* Microsecond latency */
    969 	for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) {
    970 		const char *ranges[] = { "2", "4", "10", "20", "50", "100",
    971 				 "250", "500", "750", "1000", };
    972 		json_object_add_value_float(tmp, ranges[i], io_u_lat_u[i]);
    973 	}
    974 	/* Millisecond latency */
    975 	tmp = json_create_object();
    976 	json_object_add_value_object(root, "latency_ms", tmp);
    977 	for (i = 0; i < FIO_IO_U_LAT_M_NR; i++) {
    978 		const char *ranges[] = { "2", "4", "10", "20", "50", "100",
    979 				 "250", "500", "750", "1000", "2000",
    980 				 ">=2000", };
    981 		json_object_add_value_float(tmp, ranges[i], io_u_lat_m[i]);
    982 	}
    983 
    984 	/* Additional output if continue_on_error set - default off*/
    985 	if (ts->continue_on_error) {
    986 		json_object_add_value_int(root, "total_err", ts->total_err_count);
    987 		json_object_add_value_int(root, "first_error", ts->first_error);
    988 	}
    989 
    990 	if (ts->latency_depth) {
    991 		json_object_add_value_int(root, "latency_depth", ts->latency_depth);
    992 		json_object_add_value_int(root, "latency_target", ts->latency_target);
    993 		json_object_add_value_float(root, "latency_percentile", ts->latency_percentile.u.f);
    994 		json_object_add_value_int(root, "latency_window", ts->latency_window);
    995 	}
    996 
    997 	/* Additional output if description is set */
    998 	if (strlen(ts->description))
    999 		json_object_add_value_string(root, "desc", ts->description);
   1000 
   1001 	return root;
   1002 }
   1003 
   1004 static void show_thread_status_terse(struct thread_stat *ts,
   1005 				     struct group_run_stats *rs)
   1006 {
   1007 	if (terse_version == 2)
   1008 		show_thread_status_terse_v2(ts, rs);
   1009 	else if (terse_version == 3 || terse_version == 4)
   1010 		show_thread_status_terse_v3_v4(ts, rs, terse_version);
   1011 	else
   1012 		log_err("fio: bad terse version!? %d\n", terse_version);
   1013 }
   1014 
   1015 struct json_object *show_thread_status(struct thread_stat *ts,
   1016 				       struct group_run_stats *rs)
   1017 {
   1018 	if (output_format == FIO_OUTPUT_TERSE)
   1019 		show_thread_status_terse(ts, rs);
   1020 	else if (output_format == FIO_OUTPUT_JSON)
   1021 		return show_thread_status_json(ts, rs);
   1022 	else
   1023 		show_thread_status_normal(ts, rs);
   1024 	return NULL;
   1025 }
   1026 
   1027 static void sum_stat(struct io_stat *dst, struct io_stat *src, int nr)
   1028 {
   1029 	double mean, S;
   1030 
   1031 	if (src->samples == 0)
   1032 		return;
   1033 
   1034 	dst->min_val = min(dst->min_val, src->min_val);
   1035 	dst->max_val = max(dst->max_val, src->max_val);
   1036 
   1037 	/*
   1038 	 * Compute new mean and S after the merge
   1039 	 * <http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
   1040 	 *  #Parallel_algorithm>
   1041 	 */
   1042 	if (nr == 1) {
   1043 		mean = src->mean.u.f;
   1044 		S = src->S.u.f;
   1045 	} else {
   1046 		double delta = src->mean.u.f - dst->mean.u.f;
   1047 
   1048 		mean = ((src->mean.u.f * src->samples) +
   1049 			(dst->mean.u.f * dst->samples)) /
   1050 			(dst->samples + src->samples);
   1051 
   1052 		S =  src->S.u.f + dst->S.u.f + pow(delta, 2.0) *
   1053 			(dst->samples * src->samples) /
   1054 			(dst->samples + src->samples);
   1055 	}
   1056 
   1057 	dst->samples += src->samples;
   1058 	dst->mean.u.f = mean;
   1059 	dst->S.u.f = S;
   1060 }
   1061 
   1062 void sum_group_stats(struct group_run_stats *dst, struct group_run_stats *src)
   1063 {
   1064 	int i;
   1065 
   1066 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
   1067 		if (dst->max_run[i] < src->max_run[i])
   1068 			dst->max_run[i] = src->max_run[i];
   1069 		if (dst->min_run[i] && dst->min_run[i] > src->min_run[i])
   1070 			dst->min_run[i] = src->min_run[i];
   1071 		if (dst->max_bw[i] < src->max_bw[i])
   1072 			dst->max_bw[i] = src->max_bw[i];
   1073 		if (dst->min_bw[i] && dst->min_bw[i] > src->min_bw[i])
   1074 			dst->min_bw[i] = src->min_bw[i];
   1075 
   1076 		dst->io_kb[i] += src->io_kb[i];
   1077 		dst->agg[i] += src->agg[i];
   1078 	}
   1079 
   1080 	if (!dst->kb_base)
   1081 		dst->kb_base = src->kb_base;
   1082 	if (!dst->unit_base)
   1083 		dst->unit_base = src->unit_base;
   1084 }
   1085 
   1086 void sum_thread_stats(struct thread_stat *dst, struct thread_stat *src, int nr)
   1087 {
   1088 	int l, k;
   1089 
   1090 	for (l = 0; l < DDIR_RWDIR_CNT; l++) {
   1091 		if (!dst->unified_rw_rep) {
   1092 			sum_stat(&dst->clat_stat[l], &src->clat_stat[l], nr);
   1093 			sum_stat(&dst->slat_stat[l], &src->slat_stat[l], nr);
   1094 			sum_stat(&dst->lat_stat[l], &src->lat_stat[l], nr);
   1095 			sum_stat(&dst->bw_stat[l], &src->bw_stat[l], nr);
   1096 
   1097 			dst->io_bytes[l] += src->io_bytes[l];
   1098 
   1099 			if (dst->runtime[l] < src->runtime[l])
   1100 				dst->runtime[l] = src->runtime[l];
   1101 		} else {
   1102 			sum_stat(&dst->clat_stat[0], &src->clat_stat[l], nr);
   1103 			sum_stat(&dst->slat_stat[0], &src->slat_stat[l], nr);
   1104 			sum_stat(&dst->lat_stat[0], &src->lat_stat[l], nr);
   1105 			sum_stat(&dst->bw_stat[0], &src->bw_stat[l], nr);
   1106 
   1107 			dst->io_bytes[0] += src->io_bytes[l];
   1108 
   1109 			if (dst->runtime[0] < src->runtime[l])
   1110 				dst->runtime[0] = src->runtime[l];
   1111 		}
   1112 	}
   1113 
   1114 	dst->usr_time += src->usr_time;
   1115 	dst->sys_time += src->sys_time;
   1116 	dst->ctx += src->ctx;
   1117 	dst->majf += src->majf;
   1118 	dst->minf += src->minf;
   1119 
   1120 	for (k = 0; k < FIO_IO_U_MAP_NR; k++)
   1121 		dst->io_u_map[k] += src->io_u_map[k];
   1122 	for (k = 0; k < FIO_IO_U_MAP_NR; k++)
   1123 		dst->io_u_submit[k] += src->io_u_submit[k];
   1124 	for (k = 0; k < FIO_IO_U_MAP_NR; k++)
   1125 		dst->io_u_complete[k] += src->io_u_complete[k];
   1126 	for (k = 0; k < FIO_IO_U_LAT_U_NR; k++)
   1127 		dst->io_u_lat_u[k] += src->io_u_lat_u[k];
   1128 	for (k = 0; k < FIO_IO_U_LAT_M_NR; k++)
   1129 		dst->io_u_lat_m[k] += src->io_u_lat_m[k];
   1130 
   1131 	for (k = 0; k < DDIR_RWDIR_CNT; k++) {
   1132 		if (!dst->unified_rw_rep) {
   1133 			dst->total_io_u[k] += src->total_io_u[k];
   1134 			dst->short_io_u[k] += src->short_io_u[k];
   1135 			dst->drop_io_u[k] += src->drop_io_u[k];
   1136 		} else {
   1137 			dst->total_io_u[0] += src->total_io_u[k];
   1138 			dst->short_io_u[0] += src->short_io_u[k];
   1139 			dst->drop_io_u[0] += src->drop_io_u[k];
   1140 		}
   1141 	}
   1142 
   1143 	for (k = 0; k < DDIR_RWDIR_CNT; k++) {
   1144 		int m;
   1145 
   1146 		for (m = 0; m < FIO_IO_U_PLAT_NR; m++) {
   1147 			/* HACK to prevent bus error in arm GCC 4.9 */
   1148 			dst->io_u_plat[k][m]+=1;
   1149 			if (!dst->unified_rw_rep)
   1150 				dst->io_u_plat[k][m] += src->io_u_plat[k][m];
   1151 			else
   1152 				dst->io_u_plat[0][m] += src->io_u_plat[k][m];
   1153 			/* HACK to prevent bus error in arm GCC 4.9 */
   1154 			dst->io_u_plat[k][m]-=1;
   1155 		}
   1156 	}
   1157 
   1158 	dst->total_run_time += src->total_run_time;
   1159 	dst->total_submit += src->total_submit;
   1160 	dst->total_complete += src->total_complete;
   1161 }
   1162 
   1163 void init_group_run_stat(struct group_run_stats *gs)
   1164 {
   1165 	int i;
   1166 	memset(gs, 0, sizeof(*gs));
   1167 
   1168 	for (i = 0; i < DDIR_RWDIR_CNT; i++)
   1169 		gs->min_bw[i] = gs->min_run[i] = ~0UL;
   1170 }
   1171 
   1172 void init_thread_stat(struct thread_stat *ts)
   1173 {
   1174 	int j;
   1175 
   1176 	memset(ts, 0, sizeof(*ts));
   1177 
   1178 	for (j = 0; j < DDIR_RWDIR_CNT; j++) {
   1179 		ts->lat_stat[j].min_val = -1UL;
   1180 		ts->clat_stat[j].min_val = -1UL;
   1181 		ts->slat_stat[j].min_val = -1UL;
   1182 		ts->bw_stat[j].min_val = -1UL;
   1183 	}
   1184 	ts->groupid = -1;
   1185 }
   1186 
   1187 void __show_run_stats(void)
   1188 {
   1189 	struct group_run_stats *runstats, *rs;
   1190 	struct thread_data *td;
   1191 	struct thread_stat *threadstats, *ts;
   1192 	int i, j, nr_ts, last_ts, idx;
   1193 	int kb_base_warned = 0;
   1194 	int unit_base_warned = 0;
   1195 	struct json_object *root = NULL;
   1196 	struct json_array *array = NULL;
   1197 	runstats = malloc(sizeof(struct group_run_stats) * (groupid + 1));
   1198 
   1199 	for (i = 0; i < groupid + 1; i++)
   1200 		init_group_run_stat(&runstats[i]);
   1201 
   1202 	/*
   1203 	 * find out how many threads stats we need. if group reporting isn't
   1204 	 * enabled, it's one-per-td.
   1205 	 */
   1206 	nr_ts = 0;
   1207 	last_ts = -1;
   1208 	for_each_td(td, i) {
   1209 		if (!td->o.group_reporting) {
   1210 			nr_ts++;
   1211 			continue;
   1212 		}
   1213 		if (last_ts == td->groupid)
   1214 			continue;
   1215 
   1216 		last_ts = td->groupid;
   1217 		nr_ts++;
   1218 	}
   1219 
   1220 	threadstats = malloc(nr_ts * sizeof(struct thread_stat));
   1221 
   1222 	for (i = 0; i < nr_ts; i++)
   1223 		init_thread_stat(&threadstats[i]);
   1224 
   1225 	j = 0;
   1226 	last_ts = -1;
   1227 	idx = 0;
   1228 	for_each_td(td, i) {
   1229 		if (idx && (!td->o.group_reporting ||
   1230 		    (td->o.group_reporting && last_ts != td->groupid))) {
   1231 			idx = 0;
   1232 			j++;
   1233 		}
   1234 
   1235 		last_ts = td->groupid;
   1236 
   1237 		ts = &threadstats[j];
   1238 
   1239 		ts->clat_percentiles = td->o.clat_percentiles;
   1240 		ts->percentile_precision = td->o.percentile_precision;
   1241 		memcpy(ts->percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list));
   1242 
   1243 		idx++;
   1244 		ts->members++;
   1245 
   1246 		if (ts->groupid == -1) {
   1247 			/*
   1248 			 * These are per-group shared already
   1249 			 */
   1250 			strncpy(ts->name, td->o.name, FIO_JOBNAME_SIZE - 1);
   1251 			if (td->o.description)
   1252 				strncpy(ts->description, td->o.description,
   1253 						FIO_JOBDESC_SIZE - 1);
   1254 			else
   1255 				memset(ts->description, 0, FIO_JOBDESC_SIZE);
   1256 
   1257 			/*
   1258 			 * If multiple entries in this group, this is
   1259 			 * the first member.
   1260 			 */
   1261 			ts->thread_number = td->thread_number;
   1262 			ts->groupid = td->groupid;
   1263 
   1264 			/*
   1265 			 * first pid in group, not very useful...
   1266 			 */
   1267 			ts->pid = td->pid;
   1268 
   1269 			ts->kb_base = td->o.kb_base;
   1270 			ts->unit_base = td->o.unit_base;
   1271 			ts->unified_rw_rep = td->o.unified_rw_rep;
   1272 		} else if (ts->kb_base != td->o.kb_base && !kb_base_warned) {
   1273 			log_info("fio: kb_base differs for jobs in group, using"
   1274 				 " %u as the base\n", ts->kb_base);
   1275 			kb_base_warned = 1;
   1276 		} else if (ts->unit_base != td->o.unit_base && !unit_base_warned) {
   1277 			log_info("fio: unit_base differs for jobs in group, using"
   1278 				 " %u as the base\n", ts->unit_base);
   1279 			unit_base_warned = 1;
   1280 		}
   1281 
   1282 		ts->continue_on_error = td->o.continue_on_error;
   1283 		ts->total_err_count += td->total_err_count;
   1284 		ts->first_error = td->first_error;
   1285 		if (!ts->error) {
   1286 			if (!td->error && td->o.continue_on_error &&
   1287 			    td->first_error) {
   1288 				ts->error = td->first_error;
   1289 				ts->verror[sizeof(ts->verror) - 1] = '\0';
   1290 				strncpy(ts->verror, td->verror, sizeof(ts->verror) - 1);
   1291 			} else  if (td->error) {
   1292 				ts->error = td->error;
   1293 				ts->verror[sizeof(ts->verror) - 1] = '\0';
   1294 				strncpy(ts->verror, td->verror, sizeof(ts->verror) - 1);
   1295 			}
   1296 		}
   1297 
   1298 		ts->latency_depth = td->latency_qd;
   1299 		ts->latency_target = td->o.latency_target;
   1300 		ts->latency_percentile = td->o.latency_percentile;
   1301 		ts->latency_window = td->o.latency_window;
   1302 
   1303 		sum_thread_stats(ts, &td->ts, idx);
   1304 	}
   1305 
   1306 	for (i = 0; i < nr_ts; i++) {
   1307 		unsigned long long bw;
   1308 
   1309 		ts = &threadstats[i];
   1310 		rs = &runstats[ts->groupid];
   1311 		rs->kb_base = ts->kb_base;
   1312 		rs->unit_base = ts->unit_base;
   1313 		rs->unified_rw_rep += ts->unified_rw_rep;
   1314 
   1315 		for (j = 0; j < DDIR_RWDIR_CNT; j++) {
   1316 			if (!ts->runtime[j])
   1317 				continue;
   1318 			if (ts->runtime[j] < rs->min_run[j] || !rs->min_run[j])
   1319 				rs->min_run[j] = ts->runtime[j];
   1320 			if (ts->runtime[j] > rs->max_run[j])
   1321 				rs->max_run[j] = ts->runtime[j];
   1322 
   1323 			bw = 0;
   1324 			if (ts->runtime[j]) {
   1325 				unsigned long runt = ts->runtime[j];
   1326 				unsigned long long kb;
   1327 
   1328 				kb = ts->io_bytes[j] / rs->kb_base;
   1329 				bw = kb * 1000 / runt;
   1330 			}
   1331 			if (bw < rs->min_bw[j])
   1332 				rs->min_bw[j] = bw;
   1333 			if (bw > rs->max_bw[j])
   1334 				rs->max_bw[j] = bw;
   1335 
   1336 			rs->io_kb[j] += ts->io_bytes[j] / rs->kb_base;
   1337 		}
   1338 	}
   1339 
   1340 	for (i = 0; i < groupid + 1; i++) {
   1341 		int ddir;
   1342 
   1343 		rs = &runstats[i];
   1344 
   1345 		for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
   1346 			if (rs->max_run[ddir])
   1347 				rs->agg[ddir] = (rs->io_kb[ddir] * 1000) /
   1348 						rs->max_run[ddir];
   1349 		}
   1350 	}
   1351 
   1352 	/*
   1353 	 * don't overwrite last signal output
   1354 	 */
   1355 	if (output_format == FIO_OUTPUT_NORMAL)
   1356 		log_info("\n");
   1357 	else if (output_format == FIO_OUTPUT_JSON) {
   1358 		char time_buf[32];
   1359 		time_t time_p;
   1360 
   1361 		time(&time_p);
   1362 		os_ctime_r((const time_t *) &time_p, time_buf,
   1363 				sizeof(time_buf));
   1364 		time_buf[strlen(time_buf) - 1] = '\0';
   1365 
   1366 		root = json_create_object();
   1367 		json_object_add_value_string(root, "fio version", fio_version_string);
   1368 		json_object_add_value_int(root, "timestamp", time_p);
   1369 		json_object_add_value_string(root, "time", time_buf);
   1370 		array = json_create_array();
   1371 		json_object_add_value_array(root, "jobs", array);
   1372 	}
   1373 
   1374 	for (i = 0; i < nr_ts; i++) {
   1375 		ts = &threadstats[i];
   1376 		rs = &runstats[ts->groupid];
   1377 
   1378 		if (is_backend)
   1379 			fio_server_send_ts(ts, rs);
   1380 		else if (output_format == FIO_OUTPUT_TERSE)
   1381 			show_thread_status_terse(ts, rs);
   1382 		else if (output_format == FIO_OUTPUT_JSON) {
   1383 			struct json_object *tmp = show_thread_status_json(ts, rs);
   1384 			json_array_add_value_object(array, tmp);
   1385 		} else
   1386 			show_thread_status_normal(ts, rs);
   1387 	}
   1388 	if (output_format == FIO_OUTPUT_JSON) {
   1389 		/* disk util stats, if any */
   1390 		show_disk_util(1, root);
   1391 
   1392 		show_idle_prof_stats(FIO_OUTPUT_JSON, root);
   1393 
   1394 		json_print_object(root);
   1395 		log_info("\n");
   1396 		json_free_object(root);
   1397 	}
   1398 
   1399 	for (i = 0; i < groupid + 1; i++) {
   1400 		rs = &runstats[i];
   1401 
   1402 		rs->groupid = i;
   1403 		if (is_backend)
   1404 			fio_server_send_gs(rs);
   1405 		else if (output_format == FIO_OUTPUT_NORMAL)
   1406 			show_group_stats(rs);
   1407 	}
   1408 
   1409 	if (is_backend)
   1410 		fio_server_send_du();
   1411 	else if (output_format == FIO_OUTPUT_NORMAL) {
   1412 		show_disk_util(0, NULL);
   1413 		show_idle_prof_stats(FIO_OUTPUT_NORMAL, NULL);
   1414 	}
   1415 
   1416 	if ( !(output_format == FIO_OUTPUT_TERSE) && append_terse_output) {
   1417 		log_info("\nAdditional Terse Output:\n");
   1418 
   1419 		for (i = 0; i < nr_ts; i++) {
   1420 			ts = &threadstats[i];
   1421 			rs = &runstats[ts->groupid];
   1422 			show_thread_status_terse(ts, rs);
   1423 		}
   1424 	}
   1425 
   1426 	log_info_flush();
   1427 	free(runstats);
   1428 	free(threadstats);
   1429 }
   1430 
   1431 void show_run_stats(void)
   1432 {
   1433 	fio_mutex_down(stat_mutex);
   1434 	__show_run_stats();
   1435 	fio_mutex_up(stat_mutex);
   1436 }
   1437 
   1438 void __show_running_run_stats(void)
   1439 {
   1440 	struct thread_data *td;
   1441 	unsigned long long *rt;
   1442 	struct timeval tv;
   1443 	int i;
   1444 
   1445 	fio_mutex_down(stat_mutex);
   1446 
   1447 	rt = malloc(thread_number * sizeof(unsigned long long));
   1448 	fio_gettime(&tv, NULL);
   1449 
   1450 	for_each_td(td, i) {
   1451 		rt[i] = mtime_since(&td->start, &tv);
   1452 		if (td_read(td) && td->io_bytes[DDIR_READ])
   1453 			td->ts.runtime[DDIR_READ] += rt[i];
   1454 		if (td_write(td) && td->io_bytes[DDIR_WRITE])
   1455 			td->ts.runtime[DDIR_WRITE] += rt[i];
   1456 		if (td_trim(td) && td->io_bytes[DDIR_TRIM])
   1457 			td->ts.runtime[DDIR_TRIM] += rt[i];
   1458 
   1459 		td->update_rusage = 1;
   1460 		td->ts.io_bytes[DDIR_READ] = td->io_bytes[DDIR_READ];
   1461 		td->ts.io_bytes[DDIR_WRITE] = td->io_bytes[DDIR_WRITE];
   1462 		td->ts.io_bytes[DDIR_TRIM] = td->io_bytes[DDIR_TRIM];
   1463 		td->ts.total_run_time = mtime_since(&td->epoch, &tv);
   1464 	}
   1465 
   1466 	for_each_td(td, i) {
   1467 		if (td->runstate >= TD_EXITED)
   1468 			continue;
   1469 		if (td->rusage_sem) {
   1470 			td->update_rusage = 1;
   1471 			fio_mutex_down(td->rusage_sem);
   1472 		}
   1473 		td->update_rusage = 0;
   1474 	}
   1475 
   1476 	__show_run_stats();
   1477 
   1478 	for_each_td(td, i) {
   1479 		if (td_read(td) && td->io_bytes[DDIR_READ])
   1480 			td->ts.runtime[DDIR_READ] -= rt[i];
   1481 		if (td_write(td) && td->io_bytes[DDIR_WRITE])
   1482 			td->ts.runtime[DDIR_WRITE] -= rt[i];
   1483 		if (td_trim(td) && td->io_bytes[DDIR_TRIM])
   1484 			td->ts.runtime[DDIR_TRIM] -= rt[i];
   1485 	}
   1486 
   1487 	free(rt);
   1488 	fio_mutex_up(stat_mutex);
   1489 }
   1490 
   1491 static int status_interval_init;
   1492 static struct timeval status_time;
   1493 static int status_file_disabled;
   1494 
   1495 #define FIO_STATUS_FILE		"fio-dump-status"
   1496 
   1497 static int check_status_file(void)
   1498 {
   1499 	struct stat sb;
   1500 	const char *temp_dir;
   1501 	char fio_status_file_path[PATH_MAX];
   1502 
   1503 	if (status_file_disabled)
   1504 		return 0;
   1505 
   1506 	temp_dir = getenv("TMPDIR");
   1507 	if (temp_dir == NULL) {
   1508 		temp_dir = getenv("TEMP");
   1509 		if (temp_dir && strlen(temp_dir) >= PATH_MAX)
   1510 			temp_dir = NULL;
   1511 	}
   1512 	if (temp_dir == NULL)
   1513 		temp_dir = "/tmp";
   1514 
   1515 	snprintf(fio_status_file_path, sizeof(fio_status_file_path), "%s/%s", temp_dir, FIO_STATUS_FILE);
   1516 
   1517 	if (stat(fio_status_file_path, &sb))
   1518 		return 0;
   1519 
   1520 	if (unlink(fio_status_file_path) < 0) {
   1521 		log_err("fio: failed to unlink %s: %s\n", fio_status_file_path,
   1522 							strerror(errno));
   1523 		log_err("fio: disabling status file updates\n");
   1524 		status_file_disabled = 1;
   1525 	}
   1526 
   1527 	return 1;
   1528 }
   1529 
   1530 void check_for_running_stats(void)
   1531 {
   1532 	if (status_interval) {
   1533 		if (!status_interval_init) {
   1534 			fio_gettime(&status_time, NULL);
   1535 			status_interval_init = 1;
   1536 		} else if (mtime_since_now(&status_time) >= status_interval) {
   1537 			show_running_run_stats();
   1538 			fio_gettime(&status_time, NULL);
   1539 			return;
   1540 		}
   1541 	}
   1542 	if (check_status_file()) {
   1543 		show_running_run_stats();
   1544 		return;
   1545 	}
   1546 }
   1547 
   1548 static inline void add_stat_sample(struct io_stat *is, unsigned long data)
   1549 {
   1550 	double val = data;
   1551 	double delta;
   1552 
   1553 	if (data > is->max_val)
   1554 		is->max_val = data;
   1555 	if (data < is->min_val)
   1556 		is->min_val = data;
   1557 
   1558 	delta = val - is->mean.u.f;
   1559 	if (delta) {
   1560 		is->mean.u.f += delta / (is->samples + 1.0);
   1561 		is->S.u.f += delta * (val - is->mean.u.f);
   1562 	}
   1563 
   1564 	is->samples++;
   1565 }
   1566 
   1567 static void __add_log_sample(struct io_log *iolog, unsigned long val,
   1568 			     enum fio_ddir ddir, unsigned int bs,
   1569 			     unsigned long t, uint64_t offset)
   1570 {
   1571 	uint64_t nr_samples = iolog->nr_samples;
   1572 	struct io_sample *s;
   1573 
   1574 	if (iolog->disabled)
   1575 		return;
   1576 
   1577 	if (!iolog->nr_samples)
   1578 		iolog->avg_last = t;
   1579 
   1580 	if (iolog->nr_samples == iolog->max_samples) {
   1581 		size_t new_size;
   1582 		void *new_log;
   1583 
   1584 		new_size = 2 * iolog->max_samples * log_entry_sz(iolog);
   1585 
   1586 		if (iolog->log_gz && (new_size > iolog->log_gz)) {
   1587 			if (iolog_flush(iolog, 0)) {
   1588 				log_err("fio: failed flushing iolog! Will stop logging.\n");
   1589 				iolog->disabled = 1;
   1590 				return;
   1591 			}
   1592 			nr_samples = iolog->nr_samples;
   1593 		} else {
   1594 			new_log = realloc(iolog->log, new_size);
   1595 			if (!new_log) {
   1596 				log_err("fio: failed extending iolog! Will stop logging.\n");
   1597 				iolog->disabled = 1;
   1598 				return;
   1599 			}
   1600 			iolog->log = new_log;
   1601 			iolog->max_samples <<= 1;
   1602 		}
   1603 	}
   1604 
   1605 	s = get_sample(iolog, nr_samples);
   1606 
   1607 	s->val = val;
   1608 	s->time = t;
   1609 	io_sample_set_ddir(iolog, s, ddir);
   1610 	s->bs = bs;
   1611 
   1612 	if (iolog->log_offset) {
   1613 		struct io_sample_offset *so = (void *) s;
   1614 
   1615 		so->offset = offset;
   1616 	}
   1617 
   1618 	iolog->nr_samples++;
   1619 }
   1620 
   1621 static inline void reset_io_stat(struct io_stat *ios)
   1622 {
   1623 	ios->max_val = ios->min_val = ios->samples = 0;
   1624 	ios->mean.u.f = ios->S.u.f = 0;
   1625 }
   1626 
   1627 void reset_io_stats(struct thread_data *td)
   1628 {
   1629 	struct thread_stat *ts = &td->ts;
   1630 	int i, j;
   1631 
   1632 	for (i = 0; i < DDIR_RWDIR_CNT; i++) {
   1633 		reset_io_stat(&ts->clat_stat[i]);
   1634 		reset_io_stat(&ts->slat_stat[i]);
   1635 		reset_io_stat(&ts->lat_stat[i]);
   1636 		reset_io_stat(&ts->bw_stat[i]);
   1637 		reset_io_stat(&ts->iops_stat[i]);
   1638 
   1639 		ts->io_bytes[i] = 0;
   1640 		ts->runtime[i] = 0;
   1641 
   1642 		for (j = 0; j < FIO_IO_U_PLAT_NR; j++)
   1643 			ts->io_u_plat[i][j] = 0;
   1644 	}
   1645 
   1646 	for (i = 0; i < FIO_IO_U_MAP_NR; i++) {
   1647 		ts->io_u_map[i] = 0;
   1648 		ts->io_u_submit[i] = 0;
   1649 		ts->io_u_complete[i] = 0;
   1650 		ts->io_u_lat_u[i] = 0;
   1651 		ts->io_u_lat_m[i] = 0;
   1652 		ts->total_submit = 0;
   1653 		ts->total_complete = 0;
   1654 	}
   1655 
   1656 	for (i = 0; i < 3; i++) {
   1657 		ts->total_io_u[i] = 0;
   1658 		ts->short_io_u[i] = 0;
   1659 		ts->drop_io_u[i] = 0;
   1660 	}
   1661 }
   1662 
   1663 static void _add_stat_to_log(struct io_log *iolog, unsigned long elapsed)
   1664 {
   1665 	/*
   1666 	 * Note an entry in the log. Use the mean from the logged samples,
   1667 	 * making sure to properly round up. Only write a log entry if we
   1668 	 * had actual samples done.
   1669 	 */
   1670 	if (iolog->avg_window[DDIR_READ].samples) {
   1671 		unsigned long mr;
   1672 
   1673 		mr = iolog->avg_window[DDIR_READ].mean.u.f + 0.50;
   1674 		__add_log_sample(iolog, mr, DDIR_READ, 0, elapsed, 0);
   1675 	}
   1676 	if (iolog->avg_window[DDIR_WRITE].samples) {
   1677 		unsigned long mw;
   1678 
   1679 		mw = iolog->avg_window[DDIR_WRITE].mean.u.f + 0.50;
   1680 		__add_log_sample(iolog, mw, DDIR_WRITE, 0, elapsed, 0);
   1681 	}
   1682 	if (iolog->avg_window[DDIR_TRIM].samples) {
   1683 		unsigned long mw;
   1684 
   1685 		mw = iolog->avg_window[DDIR_TRIM].mean.u.f + 0.50;
   1686 		__add_log_sample(iolog, mw, DDIR_TRIM, 0, elapsed, 0);
   1687 	}
   1688 
   1689 	reset_io_stat(&iolog->avg_window[DDIR_READ]);
   1690 	reset_io_stat(&iolog->avg_window[DDIR_WRITE]);
   1691 	reset_io_stat(&iolog->avg_window[DDIR_TRIM]);
   1692 }
   1693 
   1694 static void add_log_sample(struct thread_data *td, struct io_log *iolog,
   1695 			   unsigned long val, enum fio_ddir ddir,
   1696 			   unsigned int bs, uint64_t offset)
   1697 {
   1698 	unsigned long elapsed, this_window;
   1699 
   1700 	if (!ddir_rw(ddir))
   1701 		return;
   1702 
   1703 	elapsed = mtime_since_now(&td->epoch);
   1704 
   1705 	/*
   1706 	 * If no time averaging, just add the log sample.
   1707 	 */
   1708 	if (!iolog->avg_msec) {
   1709 		__add_log_sample(iolog, val, ddir, bs, elapsed, offset);
   1710 		return;
   1711 	}
   1712 
   1713 	/*
   1714 	 * Add the sample. If the time period has passed, then
   1715 	 * add that entry to the log and clear.
   1716 	 */
   1717 	add_stat_sample(&iolog->avg_window[ddir], val);
   1718 
   1719 	/*
   1720 	 * If period hasn't passed, adding the above sample is all we
   1721 	 * need to do.
   1722 	 */
   1723 	this_window = elapsed - iolog->avg_last;
   1724 	if (this_window < iolog->avg_msec)
   1725 		return;
   1726 
   1727 	_add_stat_to_log(iolog, elapsed);
   1728 
   1729 	iolog->avg_last = elapsed;
   1730 }
   1731 
   1732 void finalize_logs(struct thread_data *td)
   1733 {
   1734 	unsigned long elapsed;
   1735 
   1736 	elapsed = mtime_since_now(&td->epoch);
   1737 
   1738 	if (td->clat_log)
   1739 		_add_stat_to_log(td->clat_log, elapsed);
   1740 	if (td->slat_log)
   1741 		_add_stat_to_log(td->slat_log, elapsed);
   1742 	if (td->lat_log)
   1743 		_add_stat_to_log(td->lat_log, elapsed);
   1744 	if (td->bw_log)
   1745 		_add_stat_to_log(td->bw_log, elapsed);
   1746 	if (td->iops_log)
   1747 		_add_stat_to_log(td->iops_log, elapsed);
   1748 }
   1749 
   1750 void add_agg_sample(unsigned long val, enum fio_ddir ddir, unsigned int bs)
   1751 {
   1752 	struct io_log *iolog;
   1753 
   1754 	if (!ddir_rw(ddir))
   1755 		return;
   1756 
   1757 	iolog = agg_io_log[ddir];
   1758 	__add_log_sample(iolog, val, ddir, bs, mtime_since_genesis(), 0);
   1759 }
   1760 
   1761 static void add_clat_percentile_sample(struct thread_stat *ts,
   1762 				unsigned long usec, enum fio_ddir ddir)
   1763 {
   1764 	unsigned int idx = plat_val_to_idx(usec);
   1765 	assert(idx < FIO_IO_U_PLAT_NR);
   1766 
   1767 	ts->io_u_plat[ddir][idx]++;
   1768 }
   1769 
   1770 void add_clat_sample(struct thread_data *td, enum fio_ddir ddir,
   1771 		     unsigned long usec, unsigned int bs, uint64_t offset)
   1772 {
   1773 	struct thread_stat *ts = &td->ts;
   1774 
   1775 	if (!ddir_rw(ddir))
   1776 		return;
   1777 
   1778 	add_stat_sample(&ts->clat_stat[ddir], usec);
   1779 
   1780 	if (td->clat_log)
   1781 		add_log_sample(td, td->clat_log, usec, ddir, bs, offset);
   1782 
   1783 	if (ts->clat_percentiles)
   1784 		add_clat_percentile_sample(ts, usec, ddir);
   1785 }
   1786 
   1787 void add_slat_sample(struct thread_data *td, enum fio_ddir ddir,
   1788 		     unsigned long usec, unsigned int bs, uint64_t offset)
   1789 {
   1790 	struct thread_stat *ts = &td->ts;
   1791 
   1792 	if (!ddir_rw(ddir))
   1793 		return;
   1794 
   1795 	add_stat_sample(&ts->slat_stat[ddir], usec);
   1796 
   1797 	if (td->slat_log)
   1798 		add_log_sample(td, td->slat_log, usec, ddir, bs, offset);
   1799 }
   1800 
   1801 void add_lat_sample(struct thread_data *td, enum fio_ddir ddir,
   1802 		    unsigned long usec, unsigned int bs, uint64_t offset)
   1803 {
   1804 	struct thread_stat *ts = &td->ts;
   1805 
   1806 	if (!ddir_rw(ddir))
   1807 		return;
   1808 
   1809 	add_stat_sample(&ts->lat_stat[ddir], usec);
   1810 
   1811 	if (td->lat_log)
   1812 		add_log_sample(td, td->lat_log, usec, ddir, bs, offset);
   1813 }
   1814 
   1815 void add_bw_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs,
   1816 		   struct timeval *t)
   1817 {
   1818 	struct thread_stat *ts = &td->ts;
   1819 	unsigned long spent, rate;
   1820 
   1821 	if (!ddir_rw(ddir))
   1822 		return;
   1823 
   1824 	spent = mtime_since(&td->bw_sample_time, t);
   1825 	if (spent < td->o.bw_avg_time)
   1826 		return;
   1827 
   1828 	/*
   1829 	 * Compute both read and write rates for the interval.
   1830 	 */
   1831 	for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
   1832 		uint64_t delta;
   1833 
   1834 		delta = td->this_io_bytes[ddir] - td->stat_io_bytes[ddir];
   1835 		if (!delta)
   1836 			continue; /* No entries for interval */
   1837 
   1838 		if (spent)
   1839 			rate = delta * 1000 / spent / 1024;
   1840 		else
   1841 			rate = 0;
   1842 
   1843 		add_stat_sample(&ts->bw_stat[ddir], rate);
   1844 
   1845 		if (td->bw_log)
   1846 			add_log_sample(td, td->bw_log, rate, ddir, bs, 0);
   1847 
   1848 		td->stat_io_bytes[ddir] = td->this_io_bytes[ddir];
   1849 	}
   1850 
   1851 	fio_gettime(&td->bw_sample_time, NULL);
   1852 }
   1853 
   1854 void add_iops_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs,
   1855 		     struct timeval *t)
   1856 {
   1857 	struct thread_stat *ts = &td->ts;
   1858 	unsigned long spent, iops;
   1859 
   1860 	if (!ddir_rw(ddir))
   1861 		return;
   1862 
   1863 	spent = mtime_since(&td->iops_sample_time, t);
   1864 	if (spent < td->o.iops_avg_time)
   1865 		return;
   1866 
   1867 	/*
   1868 	 * Compute both read and write rates for the interval.
   1869 	 */
   1870 	for (ddir = DDIR_READ; ddir < DDIR_RWDIR_CNT; ddir++) {
   1871 		uint64_t delta;
   1872 
   1873 		delta = td->this_io_blocks[ddir] - td->stat_io_blocks[ddir];
   1874 		if (!delta)
   1875 			continue; /* No entries for interval */
   1876 
   1877 		if (spent)
   1878 			iops = (delta * 1000) / spent;
   1879 		else
   1880 			iops = 0;
   1881 
   1882 		add_stat_sample(&ts->iops_stat[ddir], iops);
   1883 
   1884 		if (td->iops_log)
   1885 			add_log_sample(td, td->iops_log, iops, ddir, bs, 0);
   1886 
   1887 		td->stat_io_blocks[ddir] = td->this_io_blocks[ddir];
   1888 	}
   1889 
   1890 	fio_gettime(&td->iops_sample_time, NULL);
   1891 }
   1892 
   1893 void stat_init(void)
   1894 {
   1895 	stat_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
   1896 }
   1897 
   1898 void stat_exit(void)
   1899 {
   1900 	/*
   1901 	 * When we have the mutex, we know out-of-band access to it
   1902 	 * have ended.
   1903 	 */
   1904 	fio_mutex_down(stat_mutex);
   1905 	fio_mutex_remove(stat_mutex);
   1906 }
   1907 
   1908 /*
   1909  * Called from signal handler. Wake up status thread.
   1910  */
   1911 void show_running_run_stats(void)
   1912 {
   1913 	helper_do_stat = 1;
   1914 	pthread_cond_signal(&helper_cond);
   1915 }
   1916