removed all printf from the json data generation; now it is twice as fast
Costa Tsaousis (ktsaou) committed
May 1, 2014 at 04:27 UTC
de9cfcd69c37adbea1a55540ec1799bd6d76b35b
1 file changed
+154
-23
netdata.c
+154
-23
@@ -679,15 +679,46 @@ const char *chart_type_name(int chart_type)
679
}
680
681
682
+// ----------------------------------------------------------------------------
683
+// FAST NUMBER TO STRING
684
+
685
+static void strreverse(char* begin, char* end)
686
+{
687
+ char aux;
688
+ while (end > begin)
689
+ aux = *end, *end-- = *begin, *begin++ = aux;
690
+}
691
+
692
+// fast number to string
693
+// returns length of string
694
+int itoa(int32_t value, char *str)
695
+{
696
+ char *wstr = str;
697
+
698
+ // Take care of sign
699
+ unsigned int uvalue = (value < 0) ? -value : value;
700
+
701
+ // Conversion. Number is reversed.
702
+ do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
703
+ if (value < 0) *wstr++ = '-';
704
+ *wstr='\0';
705
+
706
+ // Reverse string
707
+ strreverse(str,wstr-1);
708
+
709
+ return(wstr - str);
710
+}
711
+
712
+
713
// ----------------------------------------------------------------------------
714
// RRD STATS
715
716
#define RRD_STATS_NAME_MAX 1024
717
687
-//typedef long double calculated_number;
688
-//#define CALCULATED_NUMBER_FORMAT "%0.1Lf"
689
-typedef long long calculated_number;
690
-#define CALCULATED_NUMBER_FORMAT "%lld"
718
+typedef long double calculated_number;
719
+#define CALCULATED_NUMBER_FORMAT "%0.1Lf"
720
+//typedef long long calculated_number;
721
+//#define CALCULATED_NUMBER_FORMAT "%lld"
722
723
typedef long long collected_number;
724
#define COLLECTED_NUMBER_FORMAT "%lld"
@@ -696,6 +727,7 @@ typedef long long total_number;
727
#define TOTAL_NUMBER_FORMAT "%lld"
728
729
typedef int32_t storage_number;
730
+typedef uint32_t ustorage_number;
731
#define STORAGE_NUMBER_FORMAT "%d"
732
733
@@ -1243,6 +1275,105 @@ struct web_buffer {
1275
1276
#define web_buffer_printf(wb, args...) wb->bytes += snprintf(&wb->buffer[wb->bytes], (wb->size - wb->bytes), ##args)
1277
1278
+void web_buffer_strcpy(struct web_buffer *wb, const char *txt)
1279
+{
1280
+ char *buffer = wb->buffer;
1281
+ size_t bytes = wb->bytes, size = wb->size, i = 0;
1282
+
1283
+ while(txt[i] && bytes < size)
1284
+ buffer[bytes++] = txt[i++];
1285
+
1286
+ wb->bytes = bytes;
1287
+}
1288
+
1289
+void web_buffer_rrd_value(struct web_buffer *wb, storage_number value)
1290
+{
1291
+ if(wb->size - wb->bytes < 11) return;
1292
+
1293
+ char *str = &wb->buffer[wb->bytes];
1294
+ char *wstr = str;
1295
+
1296
+ // make sure it is unsigned
1297
+ ustorage_number uvalue = (value < 0) ? -value : value;
1298
+
1299
+ // print each digit
1300
+ do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
1301
+
1302
+ // if it is just one byte, add a zero
1303
+ if((wstr - str) == 1) *wstr++ = '0';
1304
+
1305
+ // put the sign back
1306
+ if (value < 0) *wstr++ = '-';
1307
+
1308
+ // reverse it
1309
+ strreverse(str, wstr-1);
1310
+
1311
+ // move the last digit
1312
+ wstr--;
1313
+ wstr[1] = wstr[0];
1314
+
1315
+ // put the dot
1316
+ wstr[0] = '.';
1317
+
1318
+ // terminate it
1319
+ wstr += 2;
1320
+ *wstr='\0';
1321
+
1322
+ // update the buffer length
1323
+ wb->bytes += (wstr - str);
1324
+}
1325
+
1326
+// generate a javascript date, the fastest possible way...
1327
+void web_buffer_jsdate(struct web_buffer *wb, int year, int month, int day, int hours, int minutes, int seconds, int milliseconds)
1328
+{
1329
+ // 10 20 30 = 35
1330
+ // 01234567890123456789012345678901234
1331
+ // Date(2014, 04, 01, 03, 28, 20, 065)
1332
+
1333
+ if(wb->size - wb->bytes < 36) return;
1334
+
1335
+ char *b = &wb->buffer[wb->bytes];
1336
+
1337
+ b[0]='D';
1338
+ b[1]='a';
1339
+ b[2]='t';
1340
+ b[3]='e';
1341
+ b[4]='(';
1342
+ b[5]= 48 + year / 1000; year -= (year / 1000) * 1000;
1343
+ b[6]= 48 + year / 100; year -= (year / 100) * 100;
1344
+ b[7]= 48 + year / 10;
1345
+ b[8]= 48 + year % 10;
1346
+ b[9]=',';
1347
+ b[10]=' ';
1348
+ b[11]= 48 + month / 10;
1349
+ b[12]= 48 + month % 10;
1350
+ b[13]=',';
1351
+ b[14]=' ';
1352
+ b[15]= 48 + day / 10;
1353
+ b[16]= 48 + day % 10;
1354
+ b[17]=',';
1355
+ b[18]=' ';
1356
+ b[19]= 48 + hours / 10;
1357
+ b[20]= 48 + hours % 10;
1358
+ b[21]=',';
1359
+ b[22]=' ';
1360
+ b[23]= 48 + minutes / 10;
1361
+ b[24]= 48 + minutes % 10;
1362
+ b[25]=',';
1363
+ b[26]=' ';
1364
+ b[27]= 48 + seconds / 10;
1365
+ b[28]= 48 + seconds % 10;
1366
+ b[29]=',';
1367
+ b[30]=' ';
1368
+ b[31]= 48 + milliseconds / 100; milliseconds -= (milliseconds / 100) * 100;
1369
+ b[32]= 48 + milliseconds / 10;
1370
+ b[33]= 48 + milliseconds % 10;
1371
+ b[34]=')';
1372
+ b[35]='\0';
1373
+
1374
+ wb->bytes += 35;
1375
+}
1376
+
1377
struct web_buffer *web_buffer_create(size_t size)
1378
{
1379
struct web_buffer *b;
@@ -1672,13 +1803,12 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1803
// the minimum line length we expect
1804
int line_size = 4096 + (dimensions * 200);
1805
1675
- char overflow_annotation[201];
1676
- int overflow_annotation_len = snprintf(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
1677
- overflow_annotation[200] = '\0';
1678
-
1679
- char normal_annotation[201];
1680
- int normal_annotation_len = snprintf(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1681
- normal_annotation[200] = '\0';
1806
+ char overflow_annotation[201]; snprintf(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
1807
+ char normal_annotation[201]; snprintf(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
1808
+ char pre_date[51]; snprintf(pre_date, 50, " {%sc%s:[{%sv%s:%s", kq, kq, kq, kq, sq);
1809
+ char post_date[21]; snprintf(post_date, 20, "%s}", sq);
1810
+ char pre_value[21]; snprintf(pre_value, 20, ",{%sv%s:", kq, kq);
1811
+ char post_value[21]; snprintf(post_value, 20, "}");
1812
1813
// to allow grouping on the same values, we need a pad
1814
long pad = before % group;
@@ -1734,10 +1864,11 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1864
if(!tm) { error("localtime() failed."); continue; }
1865
if(now.tv_sec > last_timestamp) last_timestamp = now.tv_sec;
1866
1737
- web_buffer_printf(wb, "%s {%sc%s:[{%sv%s:%sDate(%d, %d, %d, %d, %d, %d, %d)%s}", printed?"]},\n":"",
1738
- kq, kq, kq, kq, sq,
1739
- tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(now.tv_usec / 1000),
1740
- sq);
1867
+ if(printed) web_buffer_strcpy(wb, "]},\n");
1868
+ web_buffer_strcpy(wb, pre_date);
1869
+ web_buffer_jsdate(wb, tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(now.tv_usec / 1000));
1870
+ // web_buffer_printf(wb, "%d, %d, %d, %d, %d, %d, %d", tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(now.tv_usec / 1000));
1871
+ web_buffer_strcpy(wb, post_date);
1872
1873
print_this = 1;
1874
}
@@ -1768,19 +1899,19 @@ unsigned long rrd_stats_json(int type, RRD_STATS *st, struct web_buffer *wb, siz
1899
1900
if(annotate_reset) {
1901
annotation_count++;
1771
- strcpy(&wb->buffer[wb->bytes], overflow_annotation);
1772
- wb->bytes += overflow_annotation_len;
1902
+ web_buffer_strcpy(wb, overflow_annotation);
1903
annotate_reset = 0;
1904
}
1775
- else {
1776
- strcpy(&wb->buffer[wb->bytes], normal_annotation);
1777
- wb->bytes += normal_annotation_len;
1778
- }
1905
+ else
1906
+ web_buffer_strcpy(wb, normal_annotation);
1907
1908
for(c = 0 ; c < dimensions ; c++) {
1909
if(!print_hidden[c]) {
1782
- long double x = (long double)print_values[c] / 10.0;
1783
- web_buffer_printf(wb, ",{%sv%s:%0.1Lf}", kq, kq, x);
1910
+ web_buffer_strcpy(wb, pre_value);
1911
+ web_buffer_rrd_value(wb, print_values[c]);
1912
+ // long double x = (long double)print_values[c] / 10.0;
1913
+ // web_buffer_printf(wb, "%0.1Lf", x);
1914
+ web_buffer_strcpy(wb, post_value);
1915
}
1916
}
1917