Skip to content

Commit d6bc71f

Browse files
Ensuring we produce a valid JSON in case of empty string and -nan (#273)
* Ensuring we produce a valid JSON in case of empty string and -nan * Ensuring latency tracing is capped both on smallest and largest latency tracking value. recording min/max outside of hdr_histogram to avoid caps. increased per second rotated histogram precision * Added the latency test (command taking longer than 1 second) to CI * Cleaned up test_valid_json_using_debug_command * Ensuring that the per second metrics are numeric non negative
1 parent 0c0c440 commit d6bc71f

File tree

8 files changed

+205
-82
lines changed

8 files changed

+205
-82
lines changed

JSON_handler.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include <stdlib.h>
2424
#include <string.h>
25-
25+
#include <cmath> // For std::isnan
2626
#include "JSON_handler.h"
2727

2828

@@ -71,7 +71,39 @@ void json_handler::write_obj(const char * objectname, const char * format, ...)
7171
fprintf(m_json_file, "\"%s\": ", objectname);
7272
va_list argptr;
7373
va_start(argptr, format);
74-
vfprintf(m_json_file, format, argptr);
74+
// Check if format includes "%s", indicating a string is expected
75+
if (strstr(format, "%s") != nullptr) {
76+
// Use a temporary va_list to check the string argument without advancing the original
77+
va_list tmp_argptr;
78+
va_copy(tmp_argptr, argptr);
79+
const char *str_arg = va_arg(tmp_argptr, const char*);
80+
va_end(tmp_argptr);
81+
82+
if (str_arg == nullptr) {
83+
// Handle NULL strings by writing "null" to the JSON file
84+
fprintf(m_json_file, "null");
85+
} else {
86+
// Print the valid string argument
87+
vfprintf(m_json_file, format, argptr);
88+
}
89+
}
90+
// Check if the format expects a floating-point number
91+
else if (strstr(format, "f") != nullptr || strstr(format, "e") != nullptr || strstr(format, "g") != nullptr) {
92+
va_list tmp_argptr;
93+
va_copy(tmp_argptr, argptr);
94+
double value = va_arg(tmp_argptr, double);
95+
va_end(tmp_argptr);
96+
97+
if (std::isnan(value)) {
98+
fprintf(m_json_file, "null");
99+
} else {
100+
vfprintf(m_json_file, format, argptr);
101+
}
102+
}
103+
else {
104+
// For other format specifiers, proceed as usual
105+
vfprintf(m_json_file, format, argptr);
106+
}
75107
va_end(argptr);
76108
beutify();
77109
fprintf(m_json_file, ",");

deps/hdr_histogram/hdr_histogram.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,12 @@ size_t hdr_get_memory_size(struct hdr_histogram *h)
448448
/* ## ## ## ## ## ## ## ## ## ## ## */
449449
/* ####### ## ######## ## ## ## ######## ###### */
450450

451+
bool hdr_record_value_capped(struct hdr_histogram* h, int64_t value)
452+
{
453+
int64_t capped_value = (value > h->highest_trackable_value) ? h->highest_trackable_value : value;
454+
capped_value = (capped_value < h->lowest_trackable_value) ? h->lowest_trackable_value : capped_value;
455+
return hdr_record_value(h, capped_value);
456+
}
451457

452458
bool hdr_record_value(struct hdr_histogram* h, int64_t value)
453459
{

deps/hdr_histogram/hdr_histogram.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ size_t hdr_get_memory_size(struct hdr_histogram* h);
110110
*/
111111
bool hdr_record_value(struct hdr_histogram* h, int64_t value);
112112

113+
/**
114+
* Records a value in the histogram, rounding the value to the specified precision
115+
* (based on the significant figure set during histogram creation). This function
116+
* will cap the recorded value at the histogram's highest_trackable_value if the input
117+
* exceeds this threshold, and at the lowest_trackable_value if it falls below.
118+
*
119+
* @param h Pointer to the histogram structure
120+
* @param value Value to add to the histogram
121+
* @return false if the value cannot be recorded due to an error, true otherwise
122+
*/
123+
bool hdr_record_value_capped(struct hdr_histogram* h, int64_t value);
124+
113125
/**
114126
* Records a value in the histogram, will round this value of to a precision at or better
115127
* than the significant_figure specified at construction time.

run_stats.cpp

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ void run_stats::update_get_op(struct timeval* ts, unsigned int bytes_rx, unsigne
185185
m_cur_stats.m_get_cmd.update_op(bytes_rx, bytes_tx, latency, hits, misses);
186186
m_cur_stats.m_total_cmd.update_op(bytes_rx, bytes_tx, latency, hits, misses);
187187
m_totals.update_op(bytes_rx, bytes_tx, latency);
188-
hdr_record_value(m_get_latency_histogram,latency);
189-
hdr_record_value(inst_m_get_latency_histogram,latency);
190-
hdr_record_value(m_totals_latency_histogram,latency);
191-
hdr_record_value(inst_m_totals_latency_histogram,latency);
188+
hdr_record_value_capped(m_get_latency_histogram,latency);
189+
hdr_record_value_capped(inst_m_get_latency_histogram,latency);
190+
hdr_record_value_capped(m_totals_latency_histogram,latency);
191+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
192192
}
193193

194194
void run_stats::update_set_op(struct timeval* ts, unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency)
@@ -198,10 +198,10 @@ void run_stats::update_set_op(struct timeval* ts, unsigned int bytes_rx, unsigne
198198
m_cur_stats.m_set_cmd.update_op(bytes_rx, bytes_tx, latency);
199199
m_cur_stats.m_total_cmd.update_op(bytes_rx, bytes_tx, latency);
200200
m_totals.update_op(bytes_rx, bytes_tx, latency);
201-
hdr_record_value(m_set_latency_histogram,latency);
202-
hdr_record_value(inst_m_set_latency_histogram,latency);
203-
hdr_record_value(m_totals_latency_histogram,latency);
204-
hdr_record_value(inst_m_totals_latency_histogram,latency);
201+
hdr_record_value_capped(m_set_latency_histogram,latency);
202+
hdr_record_value_capped(inst_m_set_latency_histogram,latency);
203+
hdr_record_value_capped(m_totals_latency_histogram,latency);
204+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
205205
}
206206

207207
void run_stats::update_moved_get_op(struct timeval* ts, unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency)
@@ -211,10 +211,10 @@ void run_stats::update_moved_get_op(struct timeval* ts, unsigned int bytes_rx, u
211211
m_cur_stats.m_get_cmd.update_moved_op(bytes_rx, bytes_tx, latency);
212212
m_cur_stats.m_total_cmd.update_op(bytes_rx, bytes_tx, latency);
213213
m_totals.update_op(bytes_rx, bytes_tx, latency);
214-
hdr_record_value(m_get_latency_histogram,latency);
215-
hdr_record_value(inst_m_get_latency_histogram,latency);
216-
hdr_record_value(m_totals_latency_histogram,latency);
217-
hdr_record_value(inst_m_totals_latency_histogram,latency);
214+
hdr_record_value_capped(m_get_latency_histogram,latency);
215+
hdr_record_value_capped(inst_m_get_latency_histogram,latency);
216+
hdr_record_value_capped(m_totals_latency_histogram,latency);
217+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
218218
}
219219

220220
void run_stats::update_moved_set_op(struct timeval* ts, unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency)
@@ -224,10 +224,10 @@ void run_stats::update_moved_set_op(struct timeval* ts, unsigned int bytes_rx, u
224224
m_cur_stats.m_set_cmd.update_moved_op(bytes_rx, bytes_tx, latency);
225225
m_cur_stats.m_total_cmd.update_moved_op(bytes_rx, bytes_tx, latency);
226226
m_totals.update_op(bytes_rx, bytes_tx, latency);
227-
hdr_record_value(m_set_latency_histogram,latency);
228-
hdr_record_value(inst_m_set_latency_histogram,latency);
229-
hdr_record_value(m_totals_latency_histogram,latency);
230-
hdr_record_value(inst_m_totals_latency_histogram,latency);
227+
hdr_record_value_capped(m_set_latency_histogram,latency);
228+
hdr_record_value_capped(inst_m_set_latency_histogram,latency);
229+
hdr_record_value_capped(m_totals_latency_histogram,latency);
230+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
231231
}
232232

233233
void run_stats::update_moved_arbitrary_op(struct timeval *ts, unsigned int bytes_rx, unsigned int bytes_tx,
@@ -239,9 +239,9 @@ void run_stats::update_moved_arbitrary_op(struct timeval *ts, unsigned int bytes
239239
m_totals.update_op(bytes_rx, bytes_tx, latency);
240240

241241
struct hdr_histogram* hist = m_ar_commands_latency_histograms.at(request_index);
242-
hdr_record_value(hist,latency);
243-
hdr_record_value(m_totals_latency_histogram,latency);
244-
hdr_record_value(inst_m_totals_latency_histogram,latency);
242+
hdr_record_value_capped(hist,latency);
243+
hdr_record_value_capped(m_totals_latency_histogram,latency);
244+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
245245
}
246246

247247
void run_stats::update_ask_get_op(struct timeval* ts, unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency)
@@ -251,10 +251,10 @@ void run_stats::update_ask_get_op(struct timeval* ts, unsigned int bytes_rx, uns
251251
m_cur_stats.m_get_cmd.update_ask_op(bytes_rx, bytes_tx, latency);
252252
m_cur_stats.m_total_cmd.update_ask_op(bytes_rx, bytes_tx, latency);
253253
m_totals.update_op(bytes_rx, bytes_tx, latency);
254-
hdr_record_value(m_get_latency_histogram,latency);
255-
hdr_record_value(inst_m_get_latency_histogram,latency);
256-
hdr_record_value(m_totals_latency_histogram,latency);
257-
hdr_record_value(inst_m_totals_latency_histogram,latency);
254+
hdr_record_value_capped(m_get_latency_histogram,latency);
255+
hdr_record_value_capped(inst_m_get_latency_histogram,latency);
256+
hdr_record_value_capped(m_totals_latency_histogram,latency);
257+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
258258
}
259259

260260
void run_stats::update_ask_set_op(struct timeval* ts, unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency)
@@ -264,10 +264,10 @@ void run_stats::update_ask_set_op(struct timeval* ts, unsigned int bytes_rx, uns
264264
m_cur_stats.m_set_cmd.update_ask_op(bytes_rx, bytes_tx, latency);
265265
m_cur_stats.m_total_cmd.update_ask_op(bytes_rx, bytes_tx, latency);
266266
m_totals.update_op(bytes_rx, bytes_tx, latency);
267-
hdr_record_value(m_set_latency_histogram,latency);
268-
hdr_record_value(inst_m_set_latency_histogram,latency);
269-
hdr_record_value(m_totals_latency_histogram,latency);
270-
hdr_record_value(inst_m_totals_latency_histogram,latency);
267+
hdr_record_value_capped(m_set_latency_histogram,latency);
268+
hdr_record_value_capped(inst_m_set_latency_histogram,latency);
269+
hdr_record_value_capped(m_totals_latency_histogram,latency);
270+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
271271
}
272272

273273
void run_stats::update_ask_arbitrary_op(struct timeval *ts, unsigned int bytes_rx, unsigned int bytes_tx,
@@ -279,9 +279,9 @@ void run_stats::update_ask_arbitrary_op(struct timeval *ts, unsigned int bytes_r
279279
m_totals.update_op(bytes_rx, bytes_tx, latency);
280280

281281
struct hdr_histogram* hist = m_ar_commands_latency_histograms.at(request_index);
282-
hdr_record_value(hist,latency);
283-
hdr_record_value(m_totals_latency_histogram,latency);
284-
hdr_record_value(inst_m_totals_latency_histogram,latency);
282+
hdr_record_value_capped(hist,latency);
283+
hdr_record_value_capped(m_totals_latency_histogram,latency);
284+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
285285
}
286286

287287
void run_stats::update_wait_op(struct timeval *ts, unsigned int latency)
@@ -291,10 +291,10 @@ void run_stats::update_wait_op(struct timeval *ts, unsigned int latency)
291291
m_cur_stats.m_wait_cmd.update_op(0,0, latency);
292292
m_cur_stats.m_total_cmd.update_op(0,0, latency);
293293
m_totals.update_op(0,0, latency);
294-
hdr_record_value(m_wait_latency_histogram,latency);
295-
hdr_record_value(inst_m_wait_latency_histogram,latency);
296-
hdr_record_value(m_totals_latency_histogram,latency);
297-
hdr_record_value(inst_m_totals_latency_histogram,latency);
294+
hdr_record_value_capped(m_wait_latency_histogram,latency);
295+
hdr_record_value_capped(inst_m_wait_latency_histogram,latency);
296+
hdr_record_value_capped(m_totals_latency_histogram,latency);
297+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
298298
}
299299

300300
void run_stats::update_arbitrary_op(struct timeval *ts, unsigned int bytes_rx, unsigned int bytes_tx,
@@ -307,10 +307,10 @@ void run_stats::update_arbitrary_op(struct timeval *ts, unsigned int bytes_rx, u
307307

308308
struct hdr_histogram* hist = m_ar_commands_latency_histograms.at(request_index);
309309
struct hdr_histogram* inst_hist = inst_m_ar_commands_latency_histograms.at(request_index);
310-
hdr_record_value(hist,latency);
311-
hdr_record_value(inst_hist,latency);
312-
hdr_record_value(m_totals_latency_histogram,latency);
313-
hdr_record_value(inst_m_totals_latency_histogram,latency);
310+
hdr_record_value_capped(hist,latency);
311+
hdr_record_value_capped(inst_hist,latency);
312+
hdr_record_value_capped(m_totals_latency_histogram,latency);
313+
hdr_record_value_capped(inst_m_totals_latency_histogram,latency);
314314
}
315315

316316
unsigned int run_stats::get_duration(void)
@@ -879,16 +879,17 @@ void run_stats::summarize(totals& result) const
879879
result.m_ask_sec = (double) (totals.m_set_cmd.m_ask + totals.m_get_cmd.m_ask) / test_duration_usec * 1000000;
880880
}
881881

882-
void result_print_to_json(json_handler * jsonhandler, const char * type, double ops,
882+
void result_print_to_json(json_handler * jsonhandler, const char * type, double ops_sec,
883883
double hits, double miss, double moved, double ask, double kbs, double kbs_rx, double kbs_tx,
884+
double latency, long m_total_latency, long ops,
884885
std::vector<float> quantile_list, struct hdr_histogram* latency_histogram,
885886
std::vector<unsigned int> timestamps,
886887
std::vector<one_sec_cmd_stats> timeserie_stats )
887888
{
888889
if (jsonhandler != NULL){ // Added for double verification in case someone accidently send NULL.
889890
jsonhandler->open_nesting(type);
890-
jsonhandler->write_obj("Count","%lld", hdr_total_count(latency_histogram));
891-
jsonhandler->write_obj("Ops/sec","%.2f", ops);
891+
jsonhandler->write_obj("Count","%lld", ops);
892+
jsonhandler->write_obj("Ops/sec","%.2f", ops_sec);
892893
jsonhandler->write_obj("Hits/sec","%.2f", hits);
893894
jsonhandler->write_obj("Misses/sec","%.2f", miss);
894895

@@ -899,12 +900,13 @@ void result_print_to_json(json_handler * jsonhandler, const char * type, double
899900
jsonhandler->write_obj("ASK/sec","%.2f", ask);
900901

901902
const bool has_samples = hdr_total_count(latency_histogram)>0;
902-
const double avg_latency = has_samples ? hdr_mean(latency_histogram)/ (double) LATENCY_HDR_RESULTS_MULTIPLIER : 0.0;
903-
const double min_latency = has_samples ? hdr_min(latency_histogram)/ (double) LATENCY_HDR_RESULTS_MULTIPLIER : 0.0;
904-
const double max_latency = has_samples ? hdr_max(latency_histogram)/ (double) LATENCY_HDR_RESULTS_MULTIPLIER : 0.0;
903+
const double avg_latency = latency;
904+
const double min_latency = has_samples ? (hdr_min(latency_histogram) * 1.0)/ (double) LATENCY_HDR_RESULTS_MULTIPLIER : 0.0;
905+
const double max_latency = has_samples ? (hdr_max(latency_histogram) * 1.0)/ (double) LATENCY_HDR_RESULTS_MULTIPLIER : 0.0;
905906
// to be retrocompatible
906907
jsonhandler->write_obj("Latency","%.3f", avg_latency);
907908
jsonhandler->write_obj("Average Latency","%.3f", avg_latency);
909+
jsonhandler->write_obj("Accumulated Latency","%lld", m_total_latency / LATENCY_HDR_RESULTS_MULTIPLIER);
908910
jsonhandler->write_obj("Min Latency","%.3f", min_latency);
909911
jsonhandler->write_obj("Max Latency","%.3f", max_latency);
910912
// preserve KB/sec for backwards compatibility
@@ -925,6 +927,7 @@ void result_print_to_json(json_handler * jsonhandler, const char * type, double
925927
jsonhandler->write_obj("Count","%lld", cmd_stats.m_ops);
926928
if (sec_has_samples){
927929
jsonhandler->write_obj("Average Latency","%.3f", cmd_stats.m_avg_latency);
930+
jsonhandler->write_obj("Accumulated Latency","%lld", cmd_stats.m_total_latency / LATENCY_HDR_RESULTS_MULTIPLIER);
928931
jsonhandler->write_obj("Min Latency","%.3f", cmd_stats.m_min_latency);
929932
jsonhandler->write_obj("Max Latency","%.3f", cmd_stats.m_max_latency);
930933
for (std::size_t i = 0; i < quantile_list.size(); i++){
@@ -1240,6 +1243,9 @@ void run_stats::print_json(json_handler *jsonhandler, arbitrary_command_list& co
12401243
m_totals.m_ar_commands[i].m_bytes_sec,
12411244
m_totals.m_ar_commands[i].m_bytes_sec_rx,
12421245
m_totals.m_ar_commands[i].m_bytes_sec_tx,
1246+
m_totals.m_ar_commands[i].m_latency,
1247+
m_totals.m_ar_commands[i].m_total_latency,
1248+
m_totals.m_ar_commands[i].m_ops,
12431249
quantiles_list,
12441250
arbitrary_command_latency_histogram,
12451251
timestamps,
@@ -1258,6 +1264,9 @@ void run_stats::print_json(json_handler *jsonhandler, arbitrary_command_list& co
12581264
m_totals.m_set_cmd.m_bytes_sec,
12591265
m_totals.m_set_cmd.m_bytes_sec_rx,
12601266
m_totals.m_set_cmd.m_bytes_sec_tx,
1267+
m_totals.m_set_cmd.m_latency,
1268+
m_totals.m_set_cmd.m_total_latency,
1269+
m_totals.m_set_cmd.m_ops,
12611270
quantiles_list,
12621271
m_set_latency_histogram,
12631272
timestamps,
@@ -1271,6 +1280,9 @@ void run_stats::print_json(json_handler *jsonhandler, arbitrary_command_list& co
12711280
m_totals.m_get_cmd.m_bytes_sec,
12721281
m_totals.m_get_cmd.m_bytes_sec_rx,
12731282
m_totals.m_get_cmd.m_bytes_sec_tx,
1283+
m_totals.m_get_cmd.m_latency,
1284+
m_totals.m_get_cmd.m_total_latency,
1285+
m_totals.m_get_cmd.m_ops,
12741286
quantiles_list,
12751287
m_get_latency_histogram,
12761288
timestamps,
@@ -1284,6 +1296,9 @@ void run_stats::print_json(json_handler *jsonhandler, arbitrary_command_list& co
12841296
0.0,
12851297
0.0,
12861298
0.0,
1299+
0.0,
1300+
0.0,
1301+
m_totals.m_wait_cmd.m_ops,
12871302
quantiles_list,
12881303
m_wait_latency_histogram,
12891304
timestamps,
@@ -1299,6 +1314,9 @@ void run_stats::print_json(json_handler *jsonhandler, arbitrary_command_list& co
12991314
m_totals.m_bytes_sec,
13001315
m_totals.m_bytes_sec_rx,
13011316
m_totals.m_bytes_sec_tx,
1317+
m_totals.m_latency,
1318+
m_totals.m_total_latency,
1319+
m_totals.m_ops,
13021320
quantiles_list,
13031321
m_totals.latency_histogram,
13041322
timestamps,

0 commit comments

Comments
 (0)