libnetdata.c 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "libnetdata.h"
  3. #ifdef __APPLE__
  4. #define INHERIT_NONE 0
  5. #endif /* __APPLE__ */
  6. #if defined(__FreeBSD__) || defined(__APPLE__)
  7. # define O_NOATIME 0
  8. # define MADV_DONTFORK INHERIT_NONE
  9. #endif /* __FreeBSD__ || __APPLE__*/
  10. struct rlimit rlimit_nofile = { .rlim_cur = 1024, .rlim_max = 1024 };
  11. #ifdef MADV_MERGEABLE
  12. int enable_ksm = 1;
  13. #else
  14. int enable_ksm = 0;
  15. #endif
  16. volatile sig_atomic_t netdata_exit = 0;
  17. const char *program_version = VERSION;
  18. #define MAX_JUDY_SIZE_TO_ARAL 24
  19. static bool judy_sizes_config[MAX_JUDY_SIZE_TO_ARAL + 1] = {
  20. [3] = true,
  21. [4] = true,
  22. [5] = true,
  23. [6] = true,
  24. [7] = true,
  25. [8] = true,
  26. [10] = true,
  27. [11] = true,
  28. [15] = true,
  29. [23] = true,
  30. };
  31. static ARAL *judy_sizes_aral[MAX_JUDY_SIZE_TO_ARAL + 1] = {};
  32. struct aral_statistics judy_sizes_aral_statistics = {};
  33. void aral_judy_init(void) {
  34. for(size_t Words = 0; Words <= MAX_JUDY_SIZE_TO_ARAL; Words++)
  35. if(judy_sizes_config[Words]) {
  36. char buf[30+1];
  37. snprintfz(buf, 30, "judy-%zu", Words * sizeof(Word_t));
  38. judy_sizes_aral[Words] = aral_create(
  39. buf,
  40. Words * sizeof(Word_t),
  41. 0,
  42. 65536,
  43. &judy_sizes_aral_statistics,
  44. NULL, NULL, false, false);
  45. }
  46. }
  47. size_t judy_aral_overhead(void) {
  48. return aral_overhead_from_stats(&judy_sizes_aral_statistics);
  49. }
  50. size_t judy_aral_structures(void) {
  51. return aral_structures_from_stats(&judy_sizes_aral_statistics);
  52. }
  53. static ARAL *judy_size_aral(Word_t Words) {
  54. if(Words <= MAX_JUDY_SIZE_TO_ARAL && judy_sizes_aral[Words])
  55. return judy_sizes_aral[Words];
  56. return NULL;
  57. }
  58. inline Word_t JudyMalloc(Word_t Words) {
  59. Word_t Addr;
  60. ARAL *ar = judy_size_aral(Words);
  61. if(ar)
  62. Addr = (Word_t) aral_mallocz(ar);
  63. else
  64. Addr = (Word_t) mallocz(Words * sizeof(Word_t));
  65. return(Addr);
  66. }
  67. inline void JudyFree(void * PWord, Word_t Words) {
  68. ARAL *ar = judy_size_aral(Words);
  69. if(ar)
  70. aral_freez(ar, PWord);
  71. else
  72. freez(PWord);
  73. }
  74. Word_t JudyMallocVirtual(Word_t Words) {
  75. return JudyMalloc(Words);
  76. }
  77. void JudyFreeVirtual(void * PWord, Word_t Words) {
  78. JudyFree(PWord, Words);
  79. }
  80. // ----------------------------------------------------------------------------
  81. // memory allocation functions that handle failures
  82. // although netdata does not use memory allocations too often (netdata tries to
  83. // maintain its memory footprint stable during runtime, i.e. all buffers are
  84. // allocated during initialization and are adapted to current use throughout
  85. // its lifetime), these can be used to override the default system allocation
  86. // routines.
  87. #ifdef NETDATA_TRACE_ALLOCATIONS
  88. #warning NETDATA_TRACE_ALLOCATIONS ENABLED
  89. #include "Judy.h"
  90. #if defined(HAVE_DLSYM) && defined(ENABLE_DLSYM)
  91. #include <dlfcn.h>
  92. typedef void (*libc_function_t)(void);
  93. static void *malloc_first_run(size_t size);
  94. static void *(*libc_malloc)(size_t) = malloc_first_run;
  95. static void *calloc_first_run(size_t n, size_t size);
  96. static void *(*libc_calloc)(size_t, size_t) = calloc_first_run;
  97. static void *realloc_first_run(void *ptr, size_t size);
  98. static void *(*libc_realloc)(void *, size_t) = realloc_first_run;
  99. static void free_first_run(void *ptr);
  100. static void (*libc_free)(void *) = free_first_run;
  101. static char *strdup_first_run(const char *s);
  102. static char *(*libc_strdup)(const char *) = strdup_first_run;
  103. static size_t malloc_usable_size_first_run(void *ptr);
  104. #ifdef HAVE_MALLOC_USABLE_SIZE
  105. static size_t (*libc_malloc_usable_size)(void *) = malloc_usable_size_first_run;
  106. #else
  107. static size_t (*libc_malloc_usable_size)(void *) = NULL;
  108. #endif
  109. static void link_system_library_function(libc_function_t *func_pptr, const char *name, bool required) {
  110. *func_pptr = dlsym(RTLD_NEXT, name);
  111. if(!*func_pptr && required) {
  112. fprintf(stderr, "FATAL: Cannot find system's %s() function.\n", name);
  113. abort();
  114. }
  115. }
  116. static void *malloc_first_run(size_t size) {
  117. link_system_library_function((libc_function_t *) &libc_malloc, "malloc", true);
  118. return libc_malloc(size);
  119. }
  120. static void *calloc_first_run(size_t n, size_t size) {
  121. link_system_library_function((libc_function_t *) &libc_calloc, "calloc", true);
  122. return libc_calloc(n, size);
  123. }
  124. static void *realloc_first_run(void *ptr, size_t size) {
  125. link_system_library_function((libc_function_t *) &libc_realloc, "realloc", true);
  126. return libc_realloc(ptr, size);
  127. }
  128. static void free_first_run(void *ptr) {
  129. link_system_library_function((libc_function_t *) &libc_free, "free", true);
  130. libc_free(ptr);
  131. }
  132. static char *strdup_first_run(const char *s) {
  133. link_system_library_function((libc_function_t *) &libc_strdup, "strdup", true);
  134. return libc_strdup(s);
  135. }
  136. static size_t malloc_usable_size_first_run(void *ptr) {
  137. link_system_library_function((libc_function_t *) &libc_malloc_usable_size, "malloc_usable_size", false);
  138. if(libc_malloc_usable_size)
  139. return libc_malloc_usable_size(ptr);
  140. else
  141. return 0;
  142. }
  143. void *malloc(size_t size) {
  144. return mallocz(size);
  145. }
  146. void *calloc(size_t n, size_t size) {
  147. return callocz(n, size);
  148. }
  149. void *realloc(void *ptr, size_t size) {
  150. return reallocz(ptr, size);
  151. }
  152. void *reallocarray(void *ptr, size_t n, size_t size) {
  153. return reallocz(ptr, n * size);
  154. }
  155. void free(void *ptr) {
  156. freez(ptr);
  157. }
  158. char *strdup(const char *s) {
  159. return strdupz(s);
  160. }
  161. size_t malloc_usable_size(void *ptr) {
  162. return mallocz_usable_size(ptr);
  163. }
  164. #else // !HAVE_DLSYM
  165. static void *(*libc_malloc)(size_t) = malloc;
  166. static void *(*libc_calloc)(size_t, size_t) = calloc;
  167. static void *(*libc_realloc)(void *, size_t) = realloc;
  168. static void (*libc_free)(void *) = free;
  169. #ifdef HAVE_MALLOC_USABLE_SIZE
  170. static size_t (*libc_malloc_usable_size)(void *) = malloc_usable_size;
  171. #else
  172. static size_t (*libc_malloc_usable_size)(void *) = NULL;
  173. #endif
  174. #endif // HAVE_DLSYM
  175. void posix_memfree(void *ptr) {
  176. libc_free(ptr);
  177. }
  178. struct malloc_header_signature {
  179. uint32_t magic;
  180. uint32_t size;
  181. struct malloc_trace *trace;
  182. };
  183. struct malloc_header {
  184. struct malloc_header_signature signature;
  185. uint8_t padding[(sizeof(struct malloc_header_signature) % MALLOC_ALIGNMENT) ? MALLOC_ALIGNMENT - (sizeof(struct malloc_header_signature) % MALLOC_ALIGNMENT) : 0];
  186. uint8_t data[];
  187. };
  188. static size_t malloc_header_size = sizeof(struct malloc_header);
  189. int malloc_trace_compare(void *A, void *B) {
  190. struct malloc_trace *a = A;
  191. struct malloc_trace *b = B;
  192. return strcmp(a->function, b->function);
  193. }
  194. static avl_tree_lock malloc_trace_index = {
  195. .avl_tree = {
  196. .root = NULL,
  197. .compar = malloc_trace_compare},
  198. .rwlock = AVL_LOCK_INITIALIZER
  199. };
  200. int malloc_trace_walkthrough(int (*callback)(void *item, void *data), void *data) {
  201. return avl_traverse_lock(&malloc_trace_index, callback, data);
  202. }
  203. NEVERNULL WARNUNUSED
  204. static struct malloc_trace *malloc_trace_find_or_create(const char *file, const char *function, size_t line) {
  205. struct malloc_trace tmp = {
  206. .line = line,
  207. .function = function,
  208. .file = file,
  209. };
  210. struct malloc_trace *t = (struct malloc_trace *)avl_search_lock(&malloc_trace_index, (avl_t *)&tmp);
  211. if(!t) {
  212. t = libc_calloc(1, sizeof(struct malloc_trace));
  213. if(!t) fatal("No memory");
  214. t->line = line;
  215. t->function = function;
  216. t->file = file;
  217. struct malloc_trace *t2 = (struct malloc_trace *)avl_insert_lock(&malloc_trace_index, (avl_t *)t);
  218. if(t2 != t)
  219. free(t);
  220. t = t2;
  221. }
  222. if(!t)
  223. fatal("Cannot insert to AVL");
  224. return t;
  225. }
  226. void malloc_trace_mmap(size_t size) {
  227. struct malloc_trace *p = malloc_trace_find_or_create("unknown", "netdata_mmap", 1);
  228. size_t_atomic_count(add, p->mmap_calls, 1);
  229. size_t_atomic_count(add, p->allocations, 1);
  230. size_t_atomic_bytes(add, p->bytes, size);
  231. }
  232. void malloc_trace_munmap(size_t size) {
  233. struct malloc_trace *p = malloc_trace_find_or_create("unknown", "netdata_mmap", 1);
  234. size_t_atomic_count(add, p->munmap_calls, 1);
  235. size_t_atomic_count(sub, p->allocations, 1);
  236. size_t_atomic_bytes(sub, p->bytes, size);
  237. }
  238. void *mallocz_int(size_t size, const char *file, const char *function, size_t line) {
  239. struct malloc_trace *p = malloc_trace_find_or_create(file, function, line);
  240. size_t_atomic_count(add, p->malloc_calls, 1);
  241. size_t_atomic_count(add, p->allocations, 1);
  242. size_t_atomic_bytes(add, p->bytes, size);
  243. struct malloc_header *t = (struct malloc_header *)libc_malloc(malloc_header_size + size);
  244. if (unlikely(!t)) fatal("mallocz() cannot allocate %zu bytes of memory (%zu with header).", size, malloc_header_size + size);
  245. t->signature.magic = 0x0BADCAFE;
  246. t->signature.trace = p;
  247. t->signature.size = size;
  248. #ifdef NETDATA_INTERNAL_CHECKS
  249. for(ssize_t i = 0; i < (ssize_t)sizeof(t->padding) ;i++) // signed to avoid compiler warning when zero-padded
  250. t->padding[i] = 0xFF;
  251. #endif
  252. return (void *)&t->data;
  253. }
  254. void *callocz_int(size_t nmemb, size_t size, const char *file, const char *function, size_t line) {
  255. struct malloc_trace *p = malloc_trace_find_or_create(file, function, line);
  256. size = nmemb * size;
  257. size_t_atomic_count(add, p->calloc_calls, 1);
  258. size_t_atomic_count(add, p->allocations, 1);
  259. size_t_atomic_bytes(add, p->bytes, size);
  260. struct malloc_header *t = (struct malloc_header *)libc_calloc(1, malloc_header_size + size);
  261. if (unlikely(!t)) fatal("mallocz() cannot allocate %zu bytes of memory (%zu with header).", size, malloc_header_size + size);
  262. t->signature.magic = 0x0BADCAFE;
  263. t->signature.trace = p;
  264. t->signature.size = size;
  265. #ifdef NETDATA_INTERNAL_CHECKS
  266. for(ssize_t i = 0; i < (ssize_t)sizeof(t->padding) ;i++) // signed to avoid compiler warning when zero-padded
  267. t->padding[i] = 0xFF;
  268. #endif
  269. return &t->data;
  270. }
  271. char *strdupz_int(const char *s, const char *file, const char *function, size_t line) {
  272. struct malloc_trace *p = malloc_trace_find_or_create(file, function, line);
  273. size_t size = strlen(s) + 1;
  274. size_t_atomic_count(add, p->strdup_calls, 1);
  275. size_t_atomic_count(add, p->allocations, 1);
  276. size_t_atomic_bytes(add, p->bytes, size);
  277. struct malloc_header *t = (struct malloc_header *)libc_malloc(malloc_header_size + size);
  278. if (unlikely(!t)) fatal("strdupz() cannot allocate %zu bytes of memory (%zu with header).", size, malloc_header_size + size);
  279. t->signature.magic = 0x0BADCAFE;
  280. t->signature.trace = p;
  281. t->signature.size = size;
  282. #ifdef NETDATA_INTERNAL_CHECKS
  283. for(ssize_t i = 0; i < (ssize_t)sizeof(t->padding) ;i++) // signed to avoid compiler warning when zero-padded
  284. t->padding[i] = 0xFF;
  285. #endif
  286. memcpy(&t->data, s, size);
  287. return (char *)&t->data;
  288. }
  289. static struct malloc_header *malloc_get_header(void *ptr, const char *caller, const char *file, const char *function, size_t line) {
  290. uint8_t *ret = (uint8_t *)ptr - malloc_header_size;
  291. struct malloc_header *t = (struct malloc_header *)ret;
  292. if(t->signature.magic != 0x0BADCAFE) {
  293. netdata_log_error("pointer %p is not our pointer (called %s() from %zu@%s, %s()).", ptr, caller, line, file, function);
  294. return NULL;
  295. }
  296. return t;
  297. }
  298. void *reallocz_int(void *ptr, size_t size, const char *file, const char *function, size_t line) {
  299. if(!ptr) return mallocz_int(size, file, function, line);
  300. struct malloc_header *t = malloc_get_header(ptr, __FUNCTION__, file, function, line);
  301. if(!t)
  302. return libc_realloc(ptr, size);
  303. if(t->signature.size == size) return ptr;
  304. size_t_atomic_count(add, t->signature.trace->free_calls, 1);
  305. size_t_atomic_count(sub, t->signature.trace->allocations, 1);
  306. size_t_atomic_bytes(sub, t->signature.trace->bytes, t->signature.size);
  307. struct malloc_trace *p = malloc_trace_find_or_create(file, function, line);
  308. size_t_atomic_count(add, p->realloc_calls, 1);
  309. size_t_atomic_count(add, p->allocations, 1);
  310. size_t_atomic_bytes(add, p->bytes, size);
  311. t = (struct malloc_header *)libc_realloc(t, malloc_header_size + size);
  312. if (unlikely(!t)) fatal("reallocz() cannot allocate %zu bytes of memory (%zu with header).", size, malloc_header_size + size);
  313. t->signature.magic = 0x0BADCAFE;
  314. t->signature.trace = p;
  315. t->signature.size = size;
  316. #ifdef NETDATA_INTERNAL_CHECKS
  317. for(ssize_t i = 0; i < (ssize_t)sizeof(t->padding) ;i++) // signed to avoid compiler warning when zero-padded
  318. t->padding[i] = 0xFF;
  319. #endif
  320. return (void *)&t->data;
  321. }
  322. size_t mallocz_usable_size_int(void *ptr, const char *file, const char *function, size_t line) {
  323. if(unlikely(!ptr)) return 0;
  324. struct malloc_header *t = malloc_get_header(ptr, __FUNCTION__, file, function, line);
  325. if(!t) {
  326. if(libc_malloc_usable_size)
  327. return libc_malloc_usable_size(ptr);
  328. else
  329. return 0;
  330. }
  331. return t->signature.size;
  332. }
  333. void freez_int(void *ptr, const char *file, const char *function, size_t line) {
  334. if(unlikely(!ptr)) return;
  335. struct malloc_header *t = malloc_get_header(ptr, __FUNCTION__, file, function, line);
  336. if(!t) {
  337. libc_free(ptr);
  338. return;
  339. }
  340. size_t_atomic_count(add, t->signature.trace->free_calls, 1);
  341. size_t_atomic_count(sub, t->signature.trace->allocations, 1);
  342. size_t_atomic_bytes(sub, t->signature.trace->bytes, t->signature.size);
  343. #ifdef NETDATA_INTERNAL_CHECKS
  344. // it should crash if it is used after freeing it
  345. memset(t, 0, malloc_header_size + t->signature.size);
  346. #endif
  347. libc_free(t);
  348. }
  349. #else
  350. char *strdupz(const char *s) {
  351. char *t = strdup(s);
  352. if (unlikely(!t)) fatal("Cannot strdup() string '%s'", s);
  353. return t;
  354. }
  355. // If ptr is NULL, no operation is performed.
  356. void freez(void *ptr) {
  357. free(ptr);
  358. }
  359. void *mallocz(size_t size) {
  360. void *p = malloc(size);
  361. if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size);
  362. return p;
  363. }
  364. void *callocz(size_t nmemb, size_t size) {
  365. void *p = calloc(nmemb, size);
  366. if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size);
  367. return p;
  368. }
  369. void *reallocz(void *ptr, size_t size) {
  370. void *p = realloc(ptr, size);
  371. if (unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size);
  372. return p;
  373. }
  374. void posix_memfree(void *ptr) {
  375. free(ptr);
  376. }
  377. #endif
  378. // --------------------------------------------------------------------------------------------------------------------
  379. void json_escape_string(char *dst, const char *src, size_t size) {
  380. const char *t;
  381. char *d = dst, *e = &dst[size - 1];
  382. for(t = src; *t && d < e ;t++) {
  383. if(unlikely(*t == '\\' || *t == '"')) {
  384. if(unlikely(d + 1 >= e)) break;
  385. *d++ = '\\';
  386. }
  387. *d++ = *t;
  388. }
  389. *d = '\0';
  390. }
  391. void json_fix_string(char *s) {
  392. unsigned char c;
  393. while((c = (unsigned char)*s)) {
  394. if(unlikely(c == '\\'))
  395. *s++ = '/';
  396. else if(unlikely(c == '"'))
  397. *s++ = '\'';
  398. else if(unlikely(isspace(c) || iscntrl(c)))
  399. *s++ = ' ';
  400. else if(unlikely(!isprint(c) || c > 127))
  401. *s++ = '_';
  402. else
  403. s++;
  404. }
  405. }
  406. unsigned char netdata_map_chart_names[256] = {
  407. [0] = '\0', //
  408. [1] = '_', //
  409. [2] = '_', //
  410. [3] = '_', //
  411. [4] = '_', //
  412. [5] = '_', //
  413. [6] = '_', //
  414. [7] = '_', //
  415. [8] = '_', //
  416. [9] = '_', //
  417. [10] = '_', //
  418. [11] = '_', //
  419. [12] = '_', //
  420. [13] = '_', //
  421. [14] = '_', //
  422. [15] = '_', //
  423. [16] = '_', //
  424. [17] = '_', //
  425. [18] = '_', //
  426. [19] = '_', //
  427. [20] = '_', //
  428. [21] = '_', //
  429. [22] = '_', //
  430. [23] = '_', //
  431. [24] = '_', //
  432. [25] = '_', //
  433. [26] = '_', //
  434. [27] = '_', //
  435. [28] = '_', //
  436. [29] = '_', //
  437. [30] = '_', //
  438. [31] = '_', //
  439. [32] = '_', //
  440. [33] = '_', // !
  441. [34] = '_', // "
  442. [35] = '_', // #
  443. [36] = '_', // $
  444. [37] = '_', // %
  445. [38] = '_', // &
  446. [39] = '_', // '
  447. [40] = '_', // (
  448. [41] = '_', // )
  449. [42] = '_', // *
  450. [43] = '_', // +
  451. [44] = '.', // ,
  452. [45] = '-', // -
  453. [46] = '.', // .
  454. [47] = '/', // /
  455. [48] = '0', // 0
  456. [49] = '1', // 1
  457. [50] = '2', // 2
  458. [51] = '3', // 3
  459. [52] = '4', // 4
  460. [53] = '5', // 5
  461. [54] = '6', // 6
  462. [55] = '7', // 7
  463. [56] = '8', // 8
  464. [57] = '9', // 9
  465. [58] = '_', // :
  466. [59] = '_', // ;
  467. [60] = '_', // <
  468. [61] = '_', // =
  469. [62] = '_', // >
  470. [63] = '_', // ?
  471. [64] = '_', // @
  472. [65] = 'a', // A
  473. [66] = 'b', // B
  474. [67] = 'c', // C
  475. [68] = 'd', // D
  476. [69] = 'e', // E
  477. [70] = 'f', // F
  478. [71] = 'g', // G
  479. [72] = 'h', // H
  480. [73] = 'i', // I
  481. [74] = 'j', // J
  482. [75] = 'k', // K
  483. [76] = 'l', // L
  484. [77] = 'm', // M
  485. [78] = 'n', // N
  486. [79] = 'o', // O
  487. [80] = 'p', // P
  488. [81] = 'q', // Q
  489. [82] = 'r', // R
  490. [83] = 's', // S
  491. [84] = 't', // T
  492. [85] = 'u', // U
  493. [86] = 'v', // V
  494. [87] = 'w', // W
  495. [88] = 'x', // X
  496. [89] = 'y', // Y
  497. [90] = 'z', // Z
  498. [91] = '_', // [
  499. [92] = '/', // backslash
  500. [93] = '_', // ]
  501. [94] = '_', // ^
  502. [95] = '_', // _
  503. [96] = '_', // `
  504. [97] = 'a', // a
  505. [98] = 'b', // b
  506. [99] = 'c', // c
  507. [100] = 'd', // d
  508. [101] = 'e', // e
  509. [102] = 'f', // f
  510. [103] = 'g', // g
  511. [104] = 'h', // h
  512. [105] = 'i', // i
  513. [106] = 'j', // j
  514. [107] = 'k', // k
  515. [108] = 'l', // l
  516. [109] = 'm', // m
  517. [110] = 'n', // n
  518. [111] = 'o', // o
  519. [112] = 'p', // p
  520. [113] = 'q', // q
  521. [114] = 'r', // r
  522. [115] = 's', // s
  523. [116] = 't', // t
  524. [117] = 'u', // u
  525. [118] = 'v', // v
  526. [119] = 'w', // w
  527. [120] = 'x', // x
  528. [121] = 'y', // y
  529. [122] = 'z', // z
  530. [123] = '_', // {
  531. [124] = '_', // |
  532. [125] = '_', // }
  533. [126] = '_', // ~
  534. [127] = '_', //
  535. [128] = '_', //
  536. [129] = '_', //
  537. [130] = '_', //
  538. [131] = '_', //
  539. [132] = '_', //
  540. [133] = '_', //
  541. [134] = '_', //
  542. [135] = '_', //
  543. [136] = '_', //
  544. [137] = '_', //
  545. [138] = '_', //
  546. [139] = '_', //
  547. [140] = '_', //
  548. [141] = '_', //
  549. [142] = '_', //
  550. [143] = '_', //
  551. [144] = '_', //
  552. [145] = '_', //
  553. [146] = '_', //
  554. [147] = '_', //
  555. [148] = '_', //
  556. [149] = '_', //
  557. [150] = '_', //
  558. [151] = '_', //
  559. [152] = '_', //
  560. [153] = '_', //
  561. [154] = '_', //
  562. [155] = '_', //
  563. [156] = '_', //
  564. [157] = '_', //
  565. [158] = '_', //
  566. [159] = '_', //
  567. [160] = '_', //
  568. [161] = '_', //
  569. [162] = '_', //
  570. [163] = '_', //
  571. [164] = '_', //
  572. [165] = '_', //
  573. [166] = '_', //
  574. [167] = '_', //
  575. [168] = '_', //
  576. [169] = '_', //
  577. [170] = '_', //
  578. [171] = '_', //
  579. [172] = '_', //
  580. [173] = '_', //
  581. [174] = '_', //
  582. [175] = '_', //
  583. [176] = '_', //
  584. [177] = '_', //
  585. [178] = '_', //
  586. [179] = '_', //
  587. [180] = '_', //
  588. [181] = '_', //
  589. [182] = '_', //
  590. [183] = '_', //
  591. [184] = '_', //
  592. [185] = '_', //
  593. [186] = '_', //
  594. [187] = '_', //
  595. [188] = '_', //
  596. [189] = '_', //
  597. [190] = '_', //
  598. [191] = '_', //
  599. [192] = '_', //
  600. [193] = '_', //
  601. [194] = '_', //
  602. [195] = '_', //
  603. [196] = '_', //
  604. [197] = '_', //
  605. [198] = '_', //
  606. [199] = '_', //
  607. [200] = '_', //
  608. [201] = '_', //
  609. [202] = '_', //
  610. [203] = '_', //
  611. [204] = '_', //
  612. [205] = '_', //
  613. [206] = '_', //
  614. [207] = '_', //
  615. [208] = '_', //
  616. [209] = '_', //
  617. [210] = '_', //
  618. [211] = '_', //
  619. [212] = '_', //
  620. [213] = '_', //
  621. [214] = '_', //
  622. [215] = '_', //
  623. [216] = '_', //
  624. [217] = '_', //
  625. [218] = '_', //
  626. [219] = '_', //
  627. [220] = '_', //
  628. [221] = '_', //
  629. [222] = '_', //
  630. [223] = '_', //
  631. [224] = '_', //
  632. [225] = '_', //
  633. [226] = '_', //
  634. [227] = '_', //
  635. [228] = '_', //
  636. [229] = '_', //
  637. [230] = '_', //
  638. [231] = '_', //
  639. [232] = '_', //
  640. [233] = '_', //
  641. [234] = '_', //
  642. [235] = '_', //
  643. [236] = '_', //
  644. [237] = '_', //
  645. [238] = '_', //
  646. [239] = '_', //
  647. [240] = '_', //
  648. [241] = '_', //
  649. [242] = '_', //
  650. [243] = '_', //
  651. [244] = '_', //
  652. [245] = '_', //
  653. [246] = '_', //
  654. [247] = '_', //
  655. [248] = '_', //
  656. [249] = '_', //
  657. [250] = '_', //
  658. [251] = '_', //
  659. [252] = '_', //
  660. [253] = '_', //
  661. [254] = '_', //
  662. [255] = '_' //
  663. };
  664. // make sure the supplied string
  665. // is good for a netdata chart/dimension ID/NAME
  666. void netdata_fix_chart_name(char *s) {
  667. while ((*s = netdata_map_chart_names[(unsigned char) *s])) s++;
  668. }
  669. unsigned char netdata_map_chart_ids[256] = {
  670. [0] = '\0', //
  671. [1] = '_', //
  672. [2] = '_', //
  673. [3] = '_', //
  674. [4] = '_', //
  675. [5] = '_', //
  676. [6] = '_', //
  677. [7] = '_', //
  678. [8] = '_', //
  679. [9] = '_', //
  680. [10] = '_', //
  681. [11] = '_', //
  682. [12] = '_', //
  683. [13] = '_', //
  684. [14] = '_', //
  685. [15] = '_', //
  686. [16] = '_', //
  687. [17] = '_', //
  688. [18] = '_', //
  689. [19] = '_', //
  690. [20] = '_', //
  691. [21] = '_', //
  692. [22] = '_', //
  693. [23] = '_', //
  694. [24] = '_', //
  695. [25] = '_', //
  696. [26] = '_', //
  697. [27] = '_', //
  698. [28] = '_', //
  699. [29] = '_', //
  700. [30] = '_', //
  701. [31] = '_', //
  702. [32] = '_', //
  703. [33] = '_', // !
  704. [34] = '_', // "
  705. [35] = '_', // #
  706. [36] = '_', // $
  707. [37] = '_', // %
  708. [38] = '_', // &
  709. [39] = '_', // '
  710. [40] = '_', // (
  711. [41] = '_', // )
  712. [42] = '_', // *
  713. [43] = '_', // +
  714. [44] = '.', // ,
  715. [45] = '-', // -
  716. [46] = '.', // .
  717. [47] = '_', // /
  718. [48] = '0', // 0
  719. [49] = '1', // 1
  720. [50] = '2', // 2
  721. [51] = '3', // 3
  722. [52] = '4', // 4
  723. [53] = '5', // 5
  724. [54] = '6', // 6
  725. [55] = '7', // 7
  726. [56] = '8', // 8
  727. [57] = '9', // 9
  728. [58] = '_', // :
  729. [59] = '_', // ;
  730. [60] = '_', // <
  731. [61] = '_', // =
  732. [62] = '_', // >
  733. [63] = '_', // ?
  734. [64] = '_', // @
  735. [65] = 'a', // A
  736. [66] = 'b', // B
  737. [67] = 'c', // C
  738. [68] = 'd', // D
  739. [69] = 'e', // E
  740. [70] = 'f', // F
  741. [71] = 'g', // G
  742. [72] = 'h', // H
  743. [73] = 'i', // I
  744. [74] = 'j', // J
  745. [75] = 'k', // K
  746. [76] = 'l', // L
  747. [77] = 'm', // M
  748. [78] = 'n', // N
  749. [79] = 'o', // O
  750. [80] = 'p', // P
  751. [81] = 'q', // Q
  752. [82] = 'r', // R
  753. [83] = 's', // S
  754. [84] = 't', // T
  755. [85] = 'u', // U
  756. [86] = 'v', // V
  757. [87] = 'w', // W
  758. [88] = 'x', // X
  759. [89] = 'y', // Y
  760. [90] = 'z', // Z
  761. [91] = '_', // [
  762. [92] = '_', // backslash
  763. [93] = '_', // ]
  764. [94] = '_', // ^
  765. [95] = '_', // _
  766. [96] = '_', // `
  767. [97] = 'a', // a
  768. [98] = 'b', // b
  769. [99] = 'c', // c
  770. [100] = 'd', // d
  771. [101] = 'e', // e
  772. [102] = 'f', // f
  773. [103] = 'g', // g
  774. [104] = 'h', // h
  775. [105] = 'i', // i
  776. [106] = 'j', // j
  777. [107] = 'k', // k
  778. [108] = 'l', // l
  779. [109] = 'm', // m
  780. [110] = 'n', // n
  781. [111] = 'o', // o
  782. [112] = 'p', // p
  783. [113] = 'q', // q
  784. [114] = 'r', // r
  785. [115] = 's', // s
  786. [116] = 't', // t
  787. [117] = 'u', // u
  788. [118] = 'v', // v
  789. [119] = 'w', // w
  790. [120] = 'x', // x
  791. [121] = 'y', // y
  792. [122] = 'z', // z
  793. [123] = '_', // {
  794. [124] = '_', // |
  795. [125] = '_', // }
  796. [126] = '_', // ~
  797. [127] = '_', //
  798. [128] = '_', //
  799. [129] = '_', //
  800. [130] = '_', //
  801. [131] = '_', //
  802. [132] = '_', //
  803. [133] = '_', //
  804. [134] = '_', //
  805. [135] = '_', //
  806. [136] = '_', //
  807. [137] = '_', //
  808. [138] = '_', //
  809. [139] = '_', //
  810. [140] = '_', //
  811. [141] = '_', //
  812. [142] = '_', //
  813. [143] = '_', //
  814. [144] = '_', //
  815. [145] = '_', //
  816. [146] = '_', //
  817. [147] = '_', //
  818. [148] = '_', //
  819. [149] = '_', //
  820. [150] = '_', //
  821. [151] = '_', //
  822. [152] = '_', //
  823. [153] = '_', //
  824. [154] = '_', //
  825. [155] = '_', //
  826. [156] = '_', //
  827. [157] = '_', //
  828. [158] = '_', //
  829. [159] = '_', //
  830. [160] = '_', //
  831. [161] = '_', //
  832. [162] = '_', //
  833. [163] = '_', //
  834. [164] = '_', //
  835. [165] = '_', //
  836. [166] = '_', //
  837. [167] = '_', //
  838. [168] = '_', //
  839. [169] = '_', //
  840. [170] = '_', //
  841. [171] = '_', //
  842. [172] = '_', //
  843. [173] = '_', //
  844. [174] = '_', //
  845. [175] = '_', //
  846. [176] = '_', //
  847. [177] = '_', //
  848. [178] = '_', //
  849. [179] = '_', //
  850. [180] = '_', //
  851. [181] = '_', //
  852. [182] = '_', //
  853. [183] = '_', //
  854. [184] = '_', //
  855. [185] = '_', //
  856. [186] = '_', //
  857. [187] = '_', //
  858. [188] = '_', //
  859. [189] = '_', //
  860. [190] = '_', //
  861. [191] = '_', //
  862. [192] = '_', //
  863. [193] = '_', //
  864. [194] = '_', //
  865. [195] = '_', //
  866. [196] = '_', //
  867. [197] = '_', //
  868. [198] = '_', //
  869. [199] = '_', //
  870. [200] = '_', //
  871. [201] = '_', //
  872. [202] = '_', //
  873. [203] = '_', //
  874. [204] = '_', //
  875. [205] = '_', //
  876. [206] = '_', //
  877. [207] = '_', //
  878. [208] = '_', //
  879. [209] = '_', //
  880. [210] = '_', //
  881. [211] = '_', //
  882. [212] = '_', //
  883. [213] = '_', //
  884. [214] = '_', //
  885. [215] = '_', //
  886. [216] = '_', //
  887. [217] = '_', //
  888. [218] = '_', //
  889. [219] = '_', //
  890. [220] = '_', //
  891. [221] = '_', //
  892. [222] = '_', //
  893. [223] = '_', //
  894. [224] = '_', //
  895. [225] = '_', //
  896. [226] = '_', //
  897. [227] = '_', //
  898. [228] = '_', //
  899. [229] = '_', //
  900. [230] = '_', //
  901. [231] = '_', //
  902. [232] = '_', //
  903. [233] = '_', //
  904. [234] = '_', //
  905. [235] = '_', //
  906. [236] = '_', //
  907. [237] = '_', //
  908. [238] = '_', //
  909. [239] = '_', //
  910. [240] = '_', //
  911. [241] = '_', //
  912. [242] = '_', //
  913. [243] = '_', //
  914. [244] = '_', //
  915. [245] = '_', //
  916. [246] = '_', //
  917. [247] = '_', //
  918. [248] = '_', //
  919. [249] = '_', //
  920. [250] = '_', //
  921. [251] = '_', //
  922. [252] = '_', //
  923. [253] = '_', //
  924. [254] = '_', //
  925. [255] = '_' //
  926. };
  927. // make sure the supplied string
  928. // is good for a netdata chart/dimension ID/NAME
  929. void netdata_fix_chart_id(char *s) {
  930. while ((*s = netdata_map_chart_ids[(unsigned char) *s])) s++;
  931. }
  932. static int memory_file_open(const char *filename, size_t size) {
  933. // netdata_log_info("memory_file_open('%s', %zu", filename, size);
  934. int fd = open(filename, O_RDWR | O_CREAT | O_NOATIME, 0664);
  935. if (fd != -1) {
  936. if (lseek(fd, size, SEEK_SET) == (off_t) size) {
  937. if (write(fd, "", 1) == 1) {
  938. if (ftruncate(fd, size))
  939. netdata_log_error("Cannot truncate file '%s' to size %zu. Will use the larger file.", filename, size);
  940. }
  941. else
  942. netdata_log_error("Cannot write to file '%s' at position %zu.", filename, size);
  943. }
  944. else
  945. netdata_log_error("Cannot seek file '%s' to size %zu.", filename, size);
  946. }
  947. else
  948. netdata_log_error("Cannot create/open file '%s'.", filename);
  949. return fd;
  950. }
  951. inline int madvise_sequential(void *mem, size_t len) {
  952. static int logger = 1;
  953. int ret = madvise(mem, len, MADV_SEQUENTIAL);
  954. if (ret != 0 && logger-- > 0)
  955. netdata_log_error("madvise(MADV_SEQUENTIAL) failed.");
  956. return ret;
  957. }
  958. inline int madvise_random(void *mem, size_t len) {
  959. static int logger = 1;
  960. int ret = madvise(mem, len, MADV_RANDOM);
  961. if (ret != 0 && logger-- > 0)
  962. netdata_log_error("madvise(MADV_RANDOM) failed.");
  963. return ret;
  964. }
  965. inline int madvise_dontfork(void *mem, size_t len) {
  966. static int logger = 1;
  967. int ret = madvise(mem, len, MADV_DONTFORK);
  968. if (ret != 0 && logger-- > 0)
  969. netdata_log_error("madvise(MADV_DONTFORK) failed.");
  970. return ret;
  971. }
  972. inline int madvise_willneed(void *mem, size_t len) {
  973. static int logger = 1;
  974. int ret = madvise(mem, len, MADV_WILLNEED);
  975. if (ret != 0 && logger-- > 0)
  976. netdata_log_error("madvise(MADV_WILLNEED) failed.");
  977. return ret;
  978. }
  979. inline int madvise_dontneed(void *mem, size_t len) {
  980. static int logger = 1;
  981. int ret = madvise(mem, len, MADV_DONTNEED);
  982. if (ret != 0 && logger-- > 0)
  983. netdata_log_error("madvise(MADV_DONTNEED) failed.");
  984. return ret;
  985. }
  986. inline int madvise_dontdump(void *mem __maybe_unused, size_t len __maybe_unused) {
  987. #if __linux__
  988. static int logger = 1;
  989. int ret = madvise(mem, len, MADV_DONTDUMP);
  990. if (ret != 0 && logger-- > 0)
  991. netdata_log_error("madvise(MADV_DONTDUMP) failed.");
  992. return ret;
  993. #else
  994. return 0;
  995. #endif
  996. }
  997. inline int madvise_mergeable(void *mem __maybe_unused, size_t len __maybe_unused) {
  998. #ifdef MADV_MERGEABLE
  999. static int logger = 1;
  1000. int ret = madvise(mem, len, MADV_MERGEABLE);
  1001. if (ret != 0 && logger-- > 0)
  1002. netdata_log_error("madvise(MADV_MERGEABLE) failed.");
  1003. return ret;
  1004. #else
  1005. return 0;
  1006. #endif
  1007. }
  1008. void *netdata_mmap(const char *filename, size_t size, int flags, int ksm, bool read_only, int *open_fd)
  1009. {
  1010. // netdata_log_info("netdata_mmap('%s', %zu", filename, size);
  1011. // MAP_SHARED is used in memory mode map
  1012. // MAP_PRIVATE is used in memory mode ram and save
  1013. if(unlikely(!(flags & MAP_SHARED) && !(flags & MAP_PRIVATE)))
  1014. fatal("Neither MAP_SHARED or MAP_PRIVATE were given to netdata_mmap()");
  1015. if(unlikely((flags & MAP_SHARED) && (flags & MAP_PRIVATE)))
  1016. fatal("Both MAP_SHARED and MAP_PRIVATE were given to netdata_mmap()");
  1017. if(unlikely((flags & MAP_SHARED) && (!filename || !*filename)))
  1018. fatal("MAP_SHARED requested, without a filename to netdata_mmap()");
  1019. // don't enable ksm is the global setting is disabled
  1020. if(unlikely(!enable_ksm)) ksm = 0;
  1021. // KSM only merges anonymous (private) pages, never pagecache (file) pages
  1022. // but MAP_PRIVATE without MAP_ANONYMOUS it fails too, so we need it always
  1023. if((flags & MAP_PRIVATE)) flags |= MAP_ANONYMOUS;
  1024. int fd = -1;
  1025. void *mem = MAP_FAILED;
  1026. if(filename && *filename) {
  1027. // open/create the file to be used
  1028. fd = memory_file_open(filename, size);
  1029. if(fd == -1) goto cleanup;
  1030. }
  1031. int fd_for_mmap = fd;
  1032. if(fd != -1 && (flags & MAP_PRIVATE)) {
  1033. // this is MAP_PRIVATE allocation
  1034. // no need for mmap() to use our fd
  1035. // we will copy the file into the memory allocated
  1036. fd_for_mmap = -1;
  1037. }
  1038. mem = mmap(NULL, size, read_only ? PROT_READ : PROT_READ | PROT_WRITE, flags, fd_for_mmap, 0);
  1039. if (mem != MAP_FAILED) {
  1040. #ifdef NETDATA_TRACE_ALLOCATIONS
  1041. malloc_trace_mmap(size);
  1042. #endif
  1043. // if we have a file open, but we didn't give it to mmap(),
  1044. // we have to read the file into the memory block we allocated
  1045. if(fd != -1 && fd_for_mmap == -1) {
  1046. if (lseek(fd, 0, SEEK_SET) == 0) {
  1047. if (read(fd, mem, size) != (ssize_t) size)
  1048. netdata_log_info("Cannot read from file '%s'", filename);
  1049. }
  1050. else netdata_log_info("Cannot seek to beginning of file '%s'.", filename);
  1051. }
  1052. // madvise_sequential(mem, size);
  1053. madvise_dontfork(mem, size);
  1054. madvise_dontdump(mem, size);
  1055. // if(flags & MAP_SHARED) madvise_willneed(mem, size);
  1056. if(ksm) madvise_mergeable(mem, size);
  1057. }
  1058. cleanup:
  1059. if(fd != -1) {
  1060. if (open_fd)
  1061. *open_fd = fd;
  1062. else
  1063. close(fd);
  1064. }
  1065. if(mem == MAP_FAILED) return NULL;
  1066. errno = 0;
  1067. return mem;
  1068. }
  1069. int netdata_munmap(void *ptr, size_t size) {
  1070. #ifdef NETDATA_TRACE_ALLOCATIONS
  1071. malloc_trace_munmap(size);
  1072. #endif
  1073. return munmap(ptr, size);
  1074. }
  1075. int memory_file_save(const char *filename, void *mem, size_t size) {
  1076. char tmpfilename[FILENAME_MAX + 1];
  1077. snprintfz(tmpfilename, FILENAME_MAX, "%s.%ld.tmp", filename, (long) getpid());
  1078. int fd = open(tmpfilename, O_RDWR | O_CREAT | O_NOATIME, 0664);
  1079. if (fd < 0) {
  1080. netdata_log_error("Cannot create/open file '%s'.", filename);
  1081. return -1;
  1082. }
  1083. if (write(fd, mem, size) != (ssize_t) size) {
  1084. netdata_log_error("Cannot write to file '%s' %ld bytes.", filename, (long) size);
  1085. close(fd);
  1086. return -1;
  1087. }
  1088. close(fd);
  1089. if (rename(tmpfilename, filename)) {
  1090. netdata_log_error("Cannot rename '%s' to '%s'", tmpfilename, filename);
  1091. return -1;
  1092. }
  1093. return 0;
  1094. }
  1095. int fd_is_valid(int fd) {
  1096. return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
  1097. }
  1098. char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
  1099. char *s = fgets(buf, (int)buf_size, fp);
  1100. if (!s) return NULL;
  1101. char *t = s;
  1102. if (*t != '\0') {
  1103. // find the string end
  1104. while (*++t != '\0');
  1105. // trim trailing spaces/newlines/tabs
  1106. while (--t > s && *t == '\n')
  1107. *t = '\0';
  1108. }
  1109. if (len)
  1110. *len = t - s + 1;
  1111. return s;
  1112. }
  1113. int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
  1114. if(unlikely(!n)) return 0;
  1115. int size = vsnprintf(dst, n, fmt, args);
  1116. dst[n - 1] = '\0';
  1117. if (unlikely((size_t) size > n)) size = (int)n;
  1118. return size;
  1119. }
  1120. int snprintfz(char *dst, size_t n, const char *fmt, ...) {
  1121. va_list args;
  1122. va_start(args, fmt);
  1123. int ret = vsnprintfz(dst, n, fmt, args);
  1124. va_end(args);
  1125. return ret;
  1126. }
  1127. /*
  1128. // poor man cycle counting
  1129. static unsigned long tsc;
  1130. void begin_tsc(void) {
  1131. unsigned long a, d;
  1132. asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx");
  1133. tsc = ((unsigned long)d << 32) | (unsigned long)a;
  1134. }
  1135. unsigned long end_tsc(void) {
  1136. unsigned long a, d;
  1137. asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx");
  1138. return (((unsigned long)d << 32) | (unsigned long)a) - tsc;
  1139. }
  1140. */
  1141. int recursively_delete_dir(const char *path, const char *reason) {
  1142. DIR *dir = opendir(path);
  1143. if(!dir) {
  1144. netdata_log_error("Cannot read %s directory to be deleted '%s'", reason?reason:"", path);
  1145. return -1;
  1146. }
  1147. int ret = 0;
  1148. struct dirent *de = NULL;
  1149. while((de = readdir(dir))) {
  1150. if(de->d_type == DT_DIR
  1151. && (
  1152. (de->d_name[0] == '.' && de->d_name[1] == '\0')
  1153. || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
  1154. ))
  1155. continue;
  1156. char fullpath[FILENAME_MAX + 1];
  1157. snprintfz(fullpath, FILENAME_MAX, "%s/%s", path, de->d_name);
  1158. if(de->d_type == DT_DIR) {
  1159. int r = recursively_delete_dir(fullpath, reason);
  1160. if(r > 0) ret += r;
  1161. continue;
  1162. }
  1163. netdata_log_info("Deleting %s file '%s'", reason?reason:"", fullpath);
  1164. if(unlikely(unlink(fullpath) == -1))
  1165. netdata_log_error("Cannot delete %s file '%s'", reason?reason:"", fullpath);
  1166. else
  1167. ret++;
  1168. }
  1169. netdata_log_info("Deleting empty directory '%s'", path);
  1170. if(unlikely(rmdir(path) == -1))
  1171. netdata_log_error("Cannot delete empty directory '%s'", path);
  1172. else
  1173. ret++;
  1174. closedir(dir);
  1175. return ret;
  1176. }
  1177. static int is_virtual_filesystem(const char *path, char **reason) {
  1178. #if defined(__APPLE__) || defined(__FreeBSD__)
  1179. (void)path;
  1180. (void)reason;
  1181. #else
  1182. struct statfs stat;
  1183. // stat.f_fsid.__val[0] is a file system id
  1184. // stat.f_fsid.__val[1] is the inode
  1185. // so their combination uniquely identifies the file/dir
  1186. if (statfs(path, &stat) == -1) {
  1187. if(reason) *reason = "failed to statfs()";
  1188. return -1;
  1189. }
  1190. if(stat.f_fsid.__val[0] != 0 || stat.f_fsid.__val[1] != 0) {
  1191. errno = EINVAL;
  1192. if(reason) *reason = "is not a virtual file system";
  1193. return -1;
  1194. }
  1195. #endif
  1196. return 0;
  1197. }
  1198. int verify_netdata_host_prefix() {
  1199. if(!netdata_configured_host_prefix)
  1200. netdata_configured_host_prefix = "";
  1201. if(!*netdata_configured_host_prefix)
  1202. return 0;
  1203. char buffer[FILENAME_MAX + 1];
  1204. char *path = netdata_configured_host_prefix;
  1205. char *reason = "unknown reason";
  1206. errno = 0;
  1207. struct stat sb;
  1208. if (stat(path, &sb) == -1) {
  1209. reason = "failed to stat()";
  1210. goto failed;
  1211. }
  1212. if((sb.st_mode & S_IFMT) != S_IFDIR) {
  1213. errno = EINVAL;
  1214. reason = "is not a directory";
  1215. goto failed;
  1216. }
  1217. path = buffer;
  1218. snprintfz(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
  1219. if(is_virtual_filesystem(path, &reason) == -1)
  1220. goto failed;
  1221. snprintfz(path, FILENAME_MAX, "%s/sys", netdata_configured_host_prefix);
  1222. if(is_virtual_filesystem(path, &reason) == -1)
  1223. goto failed;
  1224. if(netdata_configured_host_prefix && *netdata_configured_host_prefix)
  1225. netdata_log_info("Using host prefix directory '%s'", netdata_configured_host_prefix);
  1226. return 0;
  1227. failed:
  1228. netdata_log_error("Ignoring host prefix '%s': path '%s' %s", netdata_configured_host_prefix, path, reason);
  1229. netdata_configured_host_prefix = "";
  1230. return -1;
  1231. }
  1232. char *strdupz_path_subpath(const char *path, const char *subpath) {
  1233. if(unlikely(!path || !*path)) path = ".";
  1234. if(unlikely(!subpath)) subpath = "";
  1235. // skip trailing slashes in path
  1236. size_t len = strlen(path);
  1237. while(len > 0 && path[len - 1] == '/') len--;
  1238. // skip leading slashes in subpath
  1239. while(subpath[0] == '/') subpath++;
  1240. // if the last character in path is / and (there is a subpath or path is now empty)
  1241. // keep the trailing slash in path and remove the additional slash
  1242. char *slash = "/";
  1243. if(path[len] == '/' && (*subpath || len == 0)) {
  1244. slash = "";
  1245. len++;
  1246. }
  1247. else if(!*subpath) {
  1248. // there is no subpath
  1249. // no need for trailing slash
  1250. slash = "";
  1251. }
  1252. char buffer[FILENAME_MAX + 1];
  1253. snprintfz(buffer, FILENAME_MAX, "%.*s%s%s", (int)len, path, slash, subpath);
  1254. return strdupz(buffer);
  1255. }
  1256. int path_is_dir(const char *path, const char *subpath) {
  1257. char *s = strdupz_path_subpath(path, subpath);
  1258. size_t max_links = 100;
  1259. int is_dir = 0;
  1260. struct stat statbuf;
  1261. while(max_links-- && stat(s, &statbuf) == 0) {
  1262. if((statbuf.st_mode & S_IFMT) == S_IFDIR) {
  1263. is_dir = 1;
  1264. break;
  1265. }
  1266. else if((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  1267. char buffer[FILENAME_MAX + 1];
  1268. ssize_t l = readlink(s, buffer, FILENAME_MAX);
  1269. if(l > 0) {
  1270. buffer[l] = '\0';
  1271. freez(s);
  1272. s = strdupz(buffer);
  1273. continue;
  1274. }
  1275. else {
  1276. is_dir = 0;
  1277. break;
  1278. }
  1279. }
  1280. else {
  1281. is_dir = 0;
  1282. break;
  1283. }
  1284. }
  1285. freez(s);
  1286. return is_dir;
  1287. }
  1288. int path_is_file(const char *path, const char *subpath) {
  1289. char *s = strdupz_path_subpath(path, subpath);
  1290. size_t max_links = 100;
  1291. int is_file = 0;
  1292. struct stat statbuf;
  1293. while(max_links-- && stat(s, &statbuf) == 0) {
  1294. if((statbuf.st_mode & S_IFMT) == S_IFREG) {
  1295. is_file = 1;
  1296. break;
  1297. }
  1298. else if((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  1299. char buffer[FILENAME_MAX + 1];
  1300. ssize_t l = readlink(s, buffer, FILENAME_MAX);
  1301. if(l > 0) {
  1302. buffer[l] = '\0';
  1303. freez(s);
  1304. s = strdupz(buffer);
  1305. continue;
  1306. }
  1307. else {
  1308. is_file = 0;
  1309. break;
  1310. }
  1311. }
  1312. else {
  1313. is_file = 0;
  1314. break;
  1315. }
  1316. }
  1317. freez(s);
  1318. return is_file;
  1319. }
  1320. void recursive_config_double_dir_load(const char *user_path, const char *stock_path, const char *subpath, int (*callback)(const char *filename, void *data), void *data, size_t depth) {
  1321. if(depth > 3) {
  1322. netdata_log_error("CONFIG: Max directory depth reached while reading user path '%s', stock path '%s', subpath '%s'", user_path, stock_path, subpath);
  1323. return;
  1324. }
  1325. char *udir = strdupz_path_subpath(user_path, subpath);
  1326. char *sdir = strdupz_path_subpath(stock_path, subpath);
  1327. netdata_log_debug(D_HEALTH, "CONFIG traversing user-config directory '%s', stock config directory '%s'", udir, sdir);
  1328. DIR *dir = opendir(udir);
  1329. if (!dir) {
  1330. netdata_log_error("CONFIG cannot open user-config directory '%s'.", udir);
  1331. }
  1332. else {
  1333. struct dirent *de = NULL;
  1334. while((de = readdir(dir))) {
  1335. if(de->d_type == DT_DIR || de->d_type == DT_LNK) {
  1336. if( !de->d_name[0] ||
  1337. (de->d_name[0] == '.' && de->d_name[1] == '\0') ||
  1338. (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
  1339. ) {
  1340. netdata_log_debug(D_HEALTH, "CONFIG ignoring user-config directory '%s/%s'", udir, de->d_name);
  1341. continue;
  1342. }
  1343. if(path_is_dir(udir, de->d_name)) {
  1344. recursive_config_double_dir_load(udir, sdir, de->d_name, callback, data, depth + 1);
  1345. continue;
  1346. }
  1347. }
  1348. if(de->d_type == DT_UNKNOWN || de->d_type == DT_REG || de->d_type == DT_LNK) {
  1349. size_t len = strlen(de->d_name);
  1350. if(path_is_file(udir, de->d_name) &&
  1351. len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
  1352. char *filename = strdupz_path_subpath(udir, de->d_name);
  1353. netdata_log_debug(D_HEALTH, "CONFIG calling callback for user file '%s'", filename);
  1354. callback(filename, data);
  1355. freez(filename);
  1356. continue;
  1357. }
  1358. }
  1359. netdata_log_debug(D_HEALTH, "CONFIG ignoring user-config file '%s/%s' of type %d", udir, de->d_name, (int)de->d_type);
  1360. }
  1361. closedir(dir);
  1362. }
  1363. netdata_log_debug(D_HEALTH, "CONFIG traversing stock config directory '%s', user config directory '%s'", sdir, udir);
  1364. dir = opendir(sdir);
  1365. if (!dir) {
  1366. netdata_log_error("CONFIG cannot open stock config directory '%s'.", sdir);
  1367. }
  1368. else {
  1369. if (strcmp(udir, sdir)) {
  1370. struct dirent *de = NULL;
  1371. while((de = readdir(dir))) {
  1372. if(de->d_type == DT_DIR || de->d_type == DT_LNK) {
  1373. if( !de->d_name[0] ||
  1374. (de->d_name[0] == '.' && de->d_name[1] == '\0') ||
  1375. (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
  1376. ) {
  1377. netdata_log_debug(D_HEALTH, "CONFIG ignoring stock config directory '%s/%s'", sdir, de->d_name);
  1378. continue;
  1379. }
  1380. if(path_is_dir(sdir, de->d_name)) {
  1381. // we recurse in stock subdirectory, only when there is no corresponding
  1382. // user subdirectory - to avoid reading the files twice
  1383. if(!path_is_dir(udir, de->d_name))
  1384. recursive_config_double_dir_load(udir, sdir, de->d_name, callback, data, depth + 1);
  1385. continue;
  1386. }
  1387. }
  1388. if(de->d_type == DT_UNKNOWN || de->d_type == DT_REG || de->d_type == DT_LNK) {
  1389. size_t len = strlen(de->d_name);
  1390. if(path_is_file(sdir, de->d_name) && !path_is_file(udir, de->d_name) &&
  1391. len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
  1392. char *filename = strdupz_path_subpath(sdir, de->d_name);
  1393. netdata_log_debug(D_HEALTH, "CONFIG calling callback for stock file '%s'", filename);
  1394. callback(filename, data);
  1395. freez(filename);
  1396. continue;
  1397. }
  1398. }
  1399. netdata_log_debug(D_HEALTH, "CONFIG ignoring stock-config file '%s/%s' of type %d", udir, de->d_name, (int)de->d_type);
  1400. }
  1401. }
  1402. closedir(dir);
  1403. }
  1404. netdata_log_debug(D_HEALTH, "CONFIG done traversing user-config directory '%s', stock config directory '%s'", udir, sdir);
  1405. freez(udir);
  1406. freez(sdir);
  1407. }
  1408. // Returns the number of bytes read from the file if file_size is not NULL.
  1409. // The actual buffer has an extra byte set to zero (not included in the count).
  1410. char *read_by_filename(char *filename, long *file_size)
  1411. {
  1412. FILE *f = fopen(filename, "r");
  1413. if (!f)
  1414. return NULL;
  1415. if (fseek(f, 0, SEEK_END) < 0) {
  1416. fclose(f);
  1417. return NULL;
  1418. }
  1419. long size = ftell(f);
  1420. if (size <= 0 || fseek(f, 0, SEEK_END) < 0) {
  1421. fclose(f);
  1422. return NULL;
  1423. }
  1424. char *contents = callocz(size + 1, 1);
  1425. if (!contents) {
  1426. fclose(f);
  1427. return NULL;
  1428. }
  1429. if (fseek(f, 0, SEEK_SET) < 0) {
  1430. fclose(f);
  1431. freez(contents);
  1432. return NULL;
  1433. }
  1434. size_t res = fread(contents, 1, size, f);
  1435. if ( res != (size_t)size) {
  1436. freez(contents);
  1437. fclose(f);
  1438. return NULL;
  1439. }
  1440. fclose(f);
  1441. if (file_size)
  1442. *file_size = size;
  1443. return contents;
  1444. }
  1445. char *find_and_replace(const char *src, const char *find, const char *replace, const char *where)
  1446. {
  1447. size_t size = strlen(src) + 1;
  1448. size_t find_len = strlen(find);
  1449. size_t repl_len = strlen(replace);
  1450. char *value, *dst;
  1451. if (likely(where))
  1452. size += (repl_len - find_len);
  1453. value = mallocz(size);
  1454. dst = value;
  1455. if (likely(where)) {
  1456. size_t count = where - src;
  1457. memmove(dst, src, count);
  1458. src += count;
  1459. dst += count;
  1460. memmove(dst, replace, repl_len);
  1461. src += find_len;
  1462. dst += repl_len;
  1463. }
  1464. strcpy(dst, src);
  1465. return value;
  1466. }
  1467. inline int pluginsd_isspace(char c) {
  1468. switch(c) {
  1469. case ' ':
  1470. case '\t':
  1471. case '\r':
  1472. case '\n':
  1473. case '=':
  1474. return 1;
  1475. default:
  1476. return 0;
  1477. }
  1478. }
  1479. inline int config_isspace(char c) {
  1480. switch (c) {
  1481. case ' ':
  1482. case '\t':
  1483. case '\r':
  1484. case '\n':
  1485. case ',':
  1486. return 1;
  1487. default:
  1488. return 0;
  1489. }
  1490. }
  1491. inline int group_by_label_isspace(char c) {
  1492. if(c == ',' || c == '|')
  1493. return 1;
  1494. return 0;
  1495. }
  1496. bool isspace_map_pluginsd[256] = {};
  1497. bool isspace_map_config[256] = {};
  1498. bool isspace_map_group_by_label[256] = {};
  1499. __attribute__((constructor)) void initialize_is_space_arrays(void) {
  1500. for(int c = 0; c < 256 ; c++) {
  1501. isspace_map_pluginsd[c] = pluginsd_isspace((char) c);
  1502. isspace_map_config[c] = config_isspace((char) c);
  1503. isspace_map_group_by_label[c] = group_by_label_isspace((char) c);
  1504. }
  1505. }
  1506. bool run_command_and_copy_output_to_stdout(const char *command, int max_line_length) {
  1507. pid_t pid;
  1508. FILE *fp = netdata_popen(command, &pid, NULL);
  1509. if(fp) {
  1510. char buffer[max_line_length + 1];
  1511. while (fgets(buffer, max_line_length, fp))
  1512. fprintf(stdout, "%s", buffer);
  1513. }
  1514. else {
  1515. netdata_log_error("Failed to execute command '%s'.", command);
  1516. return false;
  1517. }
  1518. netdata_pclose(NULL, fp, pid);
  1519. return true;
  1520. }
  1521. void for_each_open_fd(OPEN_FD_ACTION action, OPEN_FD_EXCLUDE excluded_fds){
  1522. int fd;
  1523. switch(action){
  1524. case OPEN_FD_ACTION_CLOSE:
  1525. if(!(excluded_fds & OPEN_FD_EXCLUDE_STDIN)) (void)close(STDIN_FILENO);
  1526. if(!(excluded_fds & OPEN_FD_EXCLUDE_STDOUT)) (void)close(STDOUT_FILENO);
  1527. if(!(excluded_fds & OPEN_FD_EXCLUDE_STDERR)) (void)close(STDERR_FILENO);
  1528. #if defined(HAVE_CLOSE_RANGE)
  1529. if(close_range(STDERR_FILENO + 1, ~0U, 0) == 0) return;
  1530. netdata_log_error("close_range() failed, will try to close fds one by one");
  1531. #endif
  1532. break;
  1533. case OPEN_FD_ACTION_FD_CLOEXEC:
  1534. if(!(excluded_fds & OPEN_FD_EXCLUDE_STDIN)) (void)fcntl(STDIN_FILENO, F_SETFD, FD_CLOEXEC);
  1535. if(!(excluded_fds & OPEN_FD_EXCLUDE_STDOUT)) (void)fcntl(STDOUT_FILENO, F_SETFD, FD_CLOEXEC);
  1536. if(!(excluded_fds & OPEN_FD_EXCLUDE_STDERR)) (void)fcntl(STDERR_FILENO, F_SETFD, FD_CLOEXEC);
  1537. #if defined(HAVE_CLOSE_RANGE) && defined(CLOSE_RANGE_CLOEXEC) // Linux >= 5.11, FreeBSD >= 13.1
  1538. if(close_range(STDERR_FILENO + 1, ~0U, CLOSE_RANGE_CLOEXEC) == 0) return;
  1539. netdata_log_error("close_range() failed, will try to mark fds for closing one by one");
  1540. #endif
  1541. break;
  1542. default:
  1543. break; // do nothing
  1544. }
  1545. DIR *dir = opendir("/proc/self/fd");
  1546. if (dir == NULL) {
  1547. struct rlimit rl;
  1548. int open_max = -1;
  1549. if(getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY) open_max = rl.rlim_max;
  1550. #ifdef _SC_OPEN_MAX
  1551. else open_max = sysconf(_SC_OPEN_MAX);
  1552. #endif
  1553. if (open_max == -1) open_max = 65535; // 65535 arbitrary default if everything else fails
  1554. for (fd = STDERR_FILENO + 1; fd < open_max; fd++) {
  1555. switch(action){
  1556. case OPEN_FD_ACTION_CLOSE:
  1557. if(fd_is_valid(fd)) (void)close(fd);
  1558. break;
  1559. case OPEN_FD_ACTION_FD_CLOEXEC:
  1560. (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
  1561. break;
  1562. default:
  1563. break; // do nothing
  1564. }
  1565. }
  1566. } else {
  1567. struct dirent *entry;
  1568. while ((entry = readdir(dir)) != NULL) {
  1569. fd = str2i(entry->d_name);
  1570. if(unlikely((fd == STDIN_FILENO ) || (fd == STDOUT_FILENO) || (fd == STDERR_FILENO) )) continue;
  1571. switch(action){
  1572. case OPEN_FD_ACTION_CLOSE:
  1573. if(fd_is_valid(fd)) (void)close(fd);
  1574. break;
  1575. case OPEN_FD_ACTION_FD_CLOEXEC:
  1576. (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
  1577. break;
  1578. default:
  1579. break; // do nothing
  1580. }
  1581. }
  1582. closedir(dir);
  1583. }
  1584. }
  1585. struct timing_steps {
  1586. const char *name;
  1587. usec_t time;
  1588. size_t count;
  1589. } timing_steps[TIMING_STEP_MAX + 1] = {
  1590. [TIMING_STEP_INTERNAL] = { .name = "internal", .time = 0, },
  1591. [TIMING_STEP_BEGIN2_PREPARE] = { .name = "BEGIN2 prepare", .time = 0, },
  1592. [TIMING_STEP_BEGIN2_FIND_CHART] = { .name = "BEGIN2 find chart", .time = 0, },
  1593. [TIMING_STEP_BEGIN2_PARSE] = { .name = "BEGIN2 parse", .time = 0, },
  1594. [TIMING_STEP_BEGIN2_ML] = { .name = "BEGIN2 ml", .time = 0, },
  1595. [TIMING_STEP_BEGIN2_PROPAGATE] = { .name = "BEGIN2 propagate", .time = 0, },
  1596. [TIMING_STEP_BEGIN2_STORE] = { .name = "BEGIN2 store", .time = 0, },
  1597. [TIMING_STEP_SET2_PREPARE] = { .name = "SET2 prepare", .time = 0, },
  1598. [TIMING_STEP_SET2_LOOKUP_DIMENSION] = { .name = "SET2 find dimension", .time = 0, },
  1599. [TIMING_STEP_SET2_PARSE] = { .name = "SET2 parse", .time = 0, },
  1600. [TIMING_STEP_SET2_ML] = { .name = "SET2 ml", .time = 0, },
  1601. [TIMING_STEP_SET2_PROPAGATE] = { .name = "SET2 propagate", .time = 0, },
  1602. [TIMING_STEP_RRDSET_STORE_METRIC] = { .name = "SET2 rrdset store", .time = 0, },
  1603. [TIMING_STEP_DBENGINE_FIRST_CHECK] = { .name = "db 1st check", .time = 0, },
  1604. [TIMING_STEP_DBENGINE_CHECK_DATA] = { .name = "db check data", .time = 0, },
  1605. [TIMING_STEP_DBENGINE_PACK] = { .name = "db pack", .time = 0, },
  1606. [TIMING_STEP_DBENGINE_PAGE_FIN] = { .name = "db page fin", .time = 0, },
  1607. [TIMING_STEP_DBENGINE_MRG_UPDATE] = { .name = "db mrg update", .time = 0, },
  1608. [TIMING_STEP_DBENGINE_PAGE_ALLOC] = { .name = "db page alloc", .time = 0, },
  1609. [TIMING_STEP_DBENGINE_CREATE_NEW_PAGE] = { .name = "db new page", .time = 0, },
  1610. [TIMING_STEP_DBENGINE_FLUSH_PAGE] = { .name = "db page flush", .time = 0, },
  1611. [TIMING_STEP_SET2_STORE] = { .name = "SET2 store", .time = 0, },
  1612. [TIMING_STEP_END2_PREPARE] = { .name = "END2 prepare", .time = 0, },
  1613. [TIMING_STEP_END2_PUSH_V1] = { .name = "END2 push v1", .time = 0, },
  1614. [TIMING_STEP_END2_ML] = { .name = "END2 ml", .time = 0, },
  1615. [TIMING_STEP_END2_RRDSET] = { .name = "END2 rrdset", .time = 0, },
  1616. [TIMING_STEP_END2_PROPAGATE] = { .name = "END2 propagate", .time = 0, },
  1617. [TIMING_STEP_END2_STORE] = { .name = "END2 store", .time = 0, },
  1618. // terminator
  1619. [TIMING_STEP_MAX] = { .name = NULL, .time = 0, },
  1620. };
  1621. void timing_action(TIMING_ACTION action, TIMING_STEP step) {
  1622. static __thread usec_t last_action_time = 0;
  1623. static struct timing_steps timings2[TIMING_STEP_MAX + 1] = {};
  1624. switch(action) {
  1625. case TIMING_ACTION_INIT:
  1626. last_action_time = now_monotonic_usec();
  1627. break;
  1628. case TIMING_ACTION_STEP: {
  1629. if(!last_action_time)
  1630. return;
  1631. usec_t now = now_monotonic_usec();
  1632. __atomic_add_fetch(&timing_steps[step].time, now - last_action_time, __ATOMIC_RELAXED);
  1633. __atomic_add_fetch(&timing_steps[step].count, 1, __ATOMIC_RELAXED);
  1634. last_action_time = now;
  1635. break;
  1636. }
  1637. case TIMING_ACTION_FINISH: {
  1638. if(!last_action_time)
  1639. return;
  1640. usec_t expected = __atomic_load_n(&timing_steps[TIMING_STEP_INTERNAL].time, __ATOMIC_RELAXED);
  1641. if(last_action_time - expected < 10 * USEC_PER_SEC) {
  1642. last_action_time = 0;
  1643. return;
  1644. }
  1645. if(!__atomic_compare_exchange_n(&timing_steps[TIMING_STEP_INTERNAL].time, &expected, last_action_time, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
  1646. last_action_time = 0;
  1647. return;
  1648. }
  1649. struct timing_steps timings3[TIMING_STEP_MAX + 1];
  1650. memcpy(timings3, timing_steps, sizeof(timings3));
  1651. size_t total_reqs = 0;
  1652. usec_t total_usec = 0;
  1653. for(size_t t = 1; t < TIMING_STEP_MAX ; t++) {
  1654. total_usec += timings3[t].time - timings2[t].time;
  1655. total_reqs += timings3[t].count - timings2[t].count;
  1656. }
  1657. BUFFER *wb = buffer_create(1024, NULL);
  1658. for(size_t t = 1; t < TIMING_STEP_MAX ; t++) {
  1659. size_t requests = timings3[t].count - timings2[t].count;
  1660. if(!requests) continue;
  1661. buffer_sprintf(wb, "TIMINGS REPORT: [%3zu. %-20s]: # %10zu, t %11.2f ms (%6.2f %%), avg %6.2f usec/run\n",
  1662. t,
  1663. timing_steps[t].name ? timing_steps[t].name : "x",
  1664. requests,
  1665. (double) (timings3[t].time - timings2[t].time) / (double)USEC_PER_MS,
  1666. (double) (timings3[t].time - timings2[t].time) * 100.0 / (double) total_usec,
  1667. (double) (timings3[t].time - timings2[t].time) / (double)requests
  1668. );
  1669. }
  1670. netdata_log_info("TIMINGS REPORT:\n%sTIMINGS REPORT: total # %10zu, t %11.2f ms",
  1671. buffer_tostring(wb), total_reqs, (double)total_usec / USEC_PER_MS);
  1672. memcpy(timings2, timings3, sizeof(timings2));
  1673. last_action_time = 0;
  1674. buffer_free(wb);
  1675. }
  1676. }
  1677. }
  1678. int hash256_string(const unsigned char *string, size_t size, char *hash) {
  1679. EVP_MD_CTX *ctx;
  1680. ctx = EVP_MD_CTX_create();
  1681. if (!ctx)
  1682. return 0;
  1683. if (!EVP_DigestInit(ctx, EVP_sha256())) {
  1684. EVP_MD_CTX_destroy(ctx);
  1685. return 0;
  1686. }
  1687. if (!EVP_DigestUpdate(ctx, string, size)) {
  1688. EVP_MD_CTX_destroy(ctx);
  1689. return 0;
  1690. }
  1691. if (!EVP_DigestFinal(ctx, (unsigned char *)hash, NULL)) {
  1692. EVP_MD_CTX_destroy(ctx);
  1693. return 0;
  1694. }
  1695. EVP_MD_CTX_destroy(ctx);
  1696. return 1;
  1697. }