+static void show_thread_status_terse_v3_v4(struct thread_stat *ts,
+ struct group_run_stats *rs, int ver)
+{
+ double io_u_dist[FIO_IO_U_MAP_NR];
+ double io_u_lat_u[FIO_IO_U_LAT_U_NR];
+ double io_u_lat_m[FIO_IO_U_LAT_M_NR];
+ double usr_cpu, sys_cpu;
+ int i;
+
+ /* General Info */
+ log_info("%d;%s;%s;%d;%d", ver, fio_version_string,
+ ts->name, ts->groupid, ts->error);
+ /* Log Read Status */
+ show_ddir_status_terse(ts, rs, DDIR_READ);
+ /* Log Write Status */
+ show_ddir_status_terse(ts, rs, DDIR_WRITE);
+ /* Log Trim Status */
+ if (ver == 4)
+ show_ddir_status_terse(ts, rs, DDIR_TRIM);
+
+ /* CPU Usage */
+ if (ts->total_run_time) {
+ double runt = (double) ts->total_run_time;
+
+ usr_cpu = (double) ts->usr_time * 100 / runt;
+ sys_cpu = (double) ts->sys_time * 100 / runt;
+ } else {
+ usr_cpu = 0;
+ sys_cpu = 0;
+ }
+
+ log_info(";%f%%;%f%%;%lu;%lu;%lu", usr_cpu, sys_cpu, ts->ctx, ts->majf,
+ ts->minf);
+
+ /* Calc % distribution of IO depths, usecond, msecond latency */
+ stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
+ stat_calc_lat_u(ts, io_u_lat_u);
+ stat_calc_lat_m(ts, io_u_lat_m);
+
+ /* Only show fixed 7 I/O depth levels*/
+ log_info(";%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%;%3.1f%%",
+ io_u_dist[0], io_u_dist[1], io_u_dist[2], io_u_dist[3],
+ io_u_dist[4], io_u_dist[5], io_u_dist[6]);
+
+ /* Microsecond latency */
+ for (i = 0; i < FIO_IO_U_LAT_U_NR; i++)
+ log_info(";%3.2f%%", io_u_lat_u[i]);
+ /* Millisecond latency */
+ for (i = 0; i < FIO_IO_U_LAT_M_NR; i++)
+ log_info(";%3.2f%%", io_u_lat_m[i]);
+
+ /* disk util stats, if any */
+ show_disk_util(1, NULL);
+
+ /* Additional output if continue_on_error set - default off*/
+ if (ts->continue_on_error)
+ log_info(";%lu;%d", ts->total_err_count, ts->first_error);
+
+ /* Additional output if description is set */
+ if (strlen(ts->description))
+ log_info(";%s", ts->description);
+
+ log_info("\n");
+}
+
+static struct json_object *show_thread_status_json(struct thread_stat *ts,
+ struct group_run_stats *rs)
+{
+ struct json_object *root, *tmp;
+ double io_u_dist[FIO_IO_U_MAP_NR];
+ double io_u_lat_u[FIO_IO_U_LAT_U_NR];
+ double io_u_lat_m[FIO_IO_U_LAT_M_NR];
+ double usr_cpu, sys_cpu;
+ int i;
+
+ root = json_create_object();
+ json_object_add_value_string(root, "jobname", ts->name);
+ json_object_add_value_int(root, "groupid", ts->groupid);
+ json_object_add_value_int(root, "error", ts->error);
+
+ add_ddir_status_json(ts, rs, DDIR_READ, root);
+ add_ddir_status_json(ts, rs, DDIR_WRITE, root);
+ add_ddir_status_json(ts, rs, DDIR_TRIM, root);
+
+ /* CPU Usage */
+ if (ts->total_run_time) {
+ double runt = (double) ts->total_run_time;
+
+ usr_cpu = (double) ts->usr_time * 100 / runt;
+ sys_cpu = (double) ts->sys_time * 100 / runt;
+ } else {
+ usr_cpu = 0;
+ sys_cpu = 0;
+ }
+ json_object_add_value_float(root, "usr_cpu", usr_cpu);
+ json_object_add_value_float(root, "sys_cpu", sys_cpu);
+ json_object_add_value_int(root, "ctx", ts->ctx);
+ json_object_add_value_int(root, "majf", ts->majf);
+ json_object_add_value_int(root, "minf", ts->minf);
+
+
+ /* Calc % distribution of IO depths, usecond, msecond latency */
+ stat_calc_dist(ts->io_u_map, ts_total_io_u(ts), io_u_dist);
+ stat_calc_lat_u(ts, io_u_lat_u);
+ stat_calc_lat_m(ts, io_u_lat_m);
+
+ tmp = json_create_object();
+ json_object_add_value_object(root, "iodepth_level", tmp);
+ /* Only show fixed 7 I/O depth levels*/
+ for (i = 0; i < 7; i++) {
+ char name[20];
+ if (i < 6)
+ snprintf(name, 20, "%d", 1 << i);
+ else
+ snprintf(name, 20, ">=%d", 1 << i);
+ json_object_add_value_float(tmp, (const char *)name, io_u_dist[i]);
+ }
+
+ tmp = json_create_object();
+ json_object_add_value_object(root, "latency_us", tmp);
+ /* Microsecond latency */
+ for (i = 0; i < FIO_IO_U_LAT_U_NR; i++) {
+ const char *ranges[] = { "2", "4", "10", "20", "50", "100",
+ "250", "500", "750", "1000", };
+ json_object_add_value_float(tmp, ranges[i], io_u_lat_u[i]);
+ }
+ /* Millisecond latency */
+ tmp = json_create_object();
+ json_object_add_value_object(root, "latency_ms", tmp);
+ for (i = 0; i < FIO_IO_U_LAT_M_NR; i++) {
+ const char *ranges[] = { "2", "4", "10", "20", "50", "100",
+ "250", "500", "750", "1000", "2000",
+ ">=2000", };
+ json_object_add_value_float(tmp, ranges[i], io_u_lat_m[i]);
+ }
+
+ /* Additional output if continue_on_error set - default off*/
+ if (ts->continue_on_error) {
+ json_object_add_value_int(root, "total_err", ts->total_err_count);
+ json_object_add_value_int(root, "total_err", ts->first_error);
+ }
+
+ /* Additional output if description is set */
+ if (strlen(ts->description))
+ json_object_add_value_string(root, "desc", ts->description);
+
+ return root;
+}
+
+static void show_thread_status_terse(struct thread_stat *ts,
+ struct group_run_stats *rs)
+{
+ if (terse_version == 2)
+ show_thread_status_terse_v2(ts, rs);
+ else if (terse_version == 3 || terse_version == 4)
+ show_thread_status_terse_v3_v4(ts, rs, terse_version);
+ else
+ log_err("fio: bad terse version!? %d\n", terse_version);
+}
+