if (!ddir_rw(ddir))
return;
- /* Only print PRIO latencies if some high priority samples were gathered */
- if (ts->clat_high_prio_stat[ddir].samples > 0) {
- const char *high, *low;
+ /* Only include per prio stats if there are >= 2 prios with samples */
+ if (get_nr_prios_with_samples(ts, ddir) >= 2) {
+ struct json_array *array = json_create_array();
+ const char *obj_name;
+ int i;
- if (ts->lat_percentiles) {
- high = "lat_high_prio";
- low = "lat_low_prio";
- } else {
- high = "clat_high_prio";
- low = "clat_low_prio";
- }
+ if (ts->lat_percentiles)
+ obj_name = "lat_ns";
+ else
+ obj_name = "clat_ns";
- tmp_object = add_ddir_lat_json(ts, ts->clat_percentiles | ts->lat_percentiles,
- &ts->clat_high_prio_stat[ddir], ts->io_u_plat_high_prio[ddir]);
- json_object_add_value_object(dir_object, high, tmp_object);
+ json_object_add_value_array(dir_object, "prios", array);
- tmp_object = add_ddir_lat_json(ts, ts->clat_percentiles | ts->lat_percentiles,
- &ts->clat_low_prio_stat[ddir], ts->io_u_plat_low_prio[ddir]);
- json_object_add_value_object(dir_object, low, tmp_object);
+ for (i = 0; i < ts->nr_clat_prio[ddir]; i++) {
+ if (ts->clat_prio[ddir][i].clat_stat.samples > 0) {
+ struct json_object *obj = json_create_object();
+ unsigned long long class, level;
+
+ class = ts->clat_prio[ddir][i].ioprio >> 13;
+ json_object_add_value_int(obj, "prioclass", class);
+ level = ts->clat_prio[ddir][i].ioprio & 7;
+ json_object_add_value_int(obj, "prio", level);
+
+ tmp_object = add_ddir_lat_json(ts,
+ ts->clat_percentiles | ts->lat_percentiles,
+ &ts->clat_prio[ddir][i].clat_stat,
+ ts->clat_prio[ddir][i].io_u_plat);
+ json_object_add_value_object(obj, obj_name, tmp_object);
+ json_array_add_value_object(array, obj);
+ }
+ }
}
if (calc_lat(&ts->bw_stat[ddir], &min, &max, &mean, &dev)) {
import argparse
import platform
import subprocess
+from collections import Counter
from pathlib import Path
def check_nocmdprio_lat(self, job):
"""
- Make sure no high/low priority latencies appear.
+ Make sure no per priority latencies appear.
job JSON object to check
"""
for ddir in ['read', 'write', 'trim']:
if ddir in job:
- if 'lat_high_prio' in job[ddir] or 'lat_low_prio' in job[ddir] or \
- 'clat_high_prio' in job[ddir] or 'clat_low_prio' in job[ddir]:
- print("Unexpected high/low priority latencies found in %s output" % ddir)
+ if 'prios' in job[ddir]:
+ print("Unexpected per priority latencies found in %s output" % ddir)
return False
if self.debug:
- print("No high/low priority latencies found")
+ print("No per priority latencies found")
return True
return retval
def check_prio_latencies(self, jsondata, clat=True, plus=False):
- """Check consistency of high/low priority latencies.
+ """Check consistency of per priority latencies.
clat True if we should check clat data; other check lat data
plus True if we have json+ format data where additional checks can
"""
if clat:
- high = 'clat_high_prio'
- low = 'clat_low_prio'
- combined = 'clat_ns'
+ obj = combined = 'clat_ns'
else:
- high = 'lat_high_prio'
- low = 'lat_low_prio'
- combined = 'lat_ns'
+ obj = combined = 'lat_ns'
- if not high in jsondata or not low in jsondata or not combined in jsondata:
- print("Error identifying high/low priority latencies")
+ if not 'prios' in jsondata or not combined in jsondata:
+ print("Error identifying per priority latencies")
return False
- if jsondata[high]['N'] + jsondata[low]['N'] != jsondata[combined]['N']:
- print("High %d + low %d != combined sample size %d" % \
- (jsondata[high]['N'], jsondata[low]['N'], jsondata[combined]['N']))
+ sum_sample_size = sum([x[obj]['N'] for x in jsondata['prios']])
+ if sum_sample_size != jsondata[combined]['N']:
+ print("Per prio sample size sum %d != combined sample size %d" %
+ (sum_sample_size, jsondata[combined]['N']))
return False
elif self.debug:
- print("High %d + low %d == combined sample size %d" % \
- (jsondata[high]['N'], jsondata[low]['N'], jsondata[combined]['N']))
+ print("Per prio sample size sum %d == combined sample size %d" %
+ (sum_sample_size, jsondata[combined]['N']))
- if min(jsondata[high]['min'], jsondata[low]['min']) != jsondata[combined]['min']:
- print("Min of high %d, low %d min latencies does not match min %d from combined data" % \
- (jsondata[high]['min'], jsondata[low]['min'], jsondata[combined]['min']))
+ min_val = min([x[obj]['min'] for x in jsondata['prios']])
+ if min_val != jsondata[combined]['min']:
+ print("Min per prio min latency %d does not match min %d from combined data" %
+ (min_val, jsondata[combined]['min']))
return False
elif self.debug:
- print("Min of high %d, low %d min latencies matches min %d from combined data" % \
- (jsondata[high]['min'], jsondata[low]['min'], jsondata[combined]['min']))
+ print("Min per prio min latency %d matches min %d from combined data" %
+ (min_val, jsondata[combined]['min']))
- if max(jsondata[high]['max'], jsondata[low]['max']) != jsondata[combined]['max']:
- print("Max of high %d, low %d max latencies does not match max %d from combined data" % \
- (jsondata[high]['max'], jsondata[low]['max'], jsondata[combined]['max']))
+ max_val = max([x[obj]['max'] for x in jsondata['prios']])
+ if max_val != jsondata[combined]['max']:
+ print("Max per prio max latency %d does not match max %d from combined data" %
+ (max_val, jsondata[combined]['max']))
return False
elif self.debug:
- print("Max of high %d, low %d max latencies matches max %d from combined data" % \
- (jsondata[high]['max'], jsondata[low]['max'], jsondata[combined]['max']))
+ print("Max per prio max latency %d matches max %d from combined data" %
+ (max_val, jsondata[combined]['max']))
- weighted_avg = (jsondata[high]['mean'] * jsondata[high]['N'] + \
- jsondata[low]['mean'] * jsondata[low]['N']) / jsondata[combined]['N']
+ weighted_vals = [x[obj]['mean'] * x[obj]['N'] for x in jsondata['prios']]
+ weighted_avg = sum(weighted_vals) / jsondata[combined]['N']
delta = abs(weighted_avg - jsondata[combined]['mean'])
if (delta / jsondata[combined]['mean']) > 0.0001:
- print("Difference between weighted average %f of high, low means "
+ print("Difference between merged per prio weighted average %f mean "
"and actual mean %f exceeds 0.01%%" % (weighted_avg, jsondata[combined]['mean']))
return False
elif self.debug:
- print("Weighted average %f of high, low means matches actual mean %f" % \
- (weighted_avg, jsondata[combined]['mean']))
+ print("Merged per prio weighted average %f mean matches actual mean %f" %
+ (weighted_avg, jsondata[combined]['mean']))
if plus:
- if not self.check_jsonplus(jsondata[high]):
- return False
- if not self.check_jsonplus(jsondata[low]):
- return False
+ for prio in jsondata['prios']:
+ if not self.check_jsonplus(prio[obj]):
+ return False
- bins = {**jsondata[high]['bins'], **jsondata[low]['bins']}
- for duration in bins.keys():
- if duration in jsondata[high]['bins'] and duration in jsondata[low]['bins']:
- bins[duration] = jsondata[high]['bins'][duration] + \
- jsondata[low]['bins'][duration]
+ counter = Counter()
+ for prio in jsondata['prios']:
+ counter.update(prio[obj]['bins'])
+
+ bins = dict(counter)
if len(bins) != len(jsondata[combined]['bins']):
- print("Number of combined high/low bins does not match number of overall bins")
+ print("Number of merged bins %d does not match number of overall bins %d" %
+ (len(bins), len(jsondata[combined]['bins'])))
return False
elif self.debug:
- print("Number of bins from merged high/low data matches number of overall bins")
+ print("Number of merged bins %d matches number of overall bins %d" %
+ (len(bins), len(jsondata[combined]['bins'])))
for duration in bins.keys():
if bins[duration] != jsondata[combined]['bins'][duration]:
- print("Merged high/low count does not match overall count for duration %d" \
- % duration)
+ print("Merged per prio count does not match overall count for duration %d" %
+ duration)
return False
- print("Merged high/low priority latency data match combined latency data")
+ print("Merged per priority latency data match combined latency data")
return True
def check(self):
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['read'], 0, slat=False)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['write'], 1, slat=False, clat=False)
print("Unexpected write data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['trim'], 2, slat=False, tlat=False)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['read'], 0, plus=True)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['write'], 1, slat=False, plus=True)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['read'], 0, slat=False, tlat=False, plus=True)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['read'], 0, clat=False, tlat=False, plus=True)
print("Unexpected data direction found in fio output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['mixed'], 0, plus=True, unified=True)
print("Error checking fsync latency data")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['write'], 1, slat=False, plus=True)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['read'], 0, plus=True)
print("Unexpected trim data found in output")
retval = False
if not self.check_nocmdprio_lat(job):
- print("Unexpected high/low priority latencies found")
+ print("Unexpected per priority latencies found")
retval = False
retval &= self.check_latencies(job['read'], 0, slat=False, clat=False, plus=True)