X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=src%2Fcommon.c;h=e46397c624be004daa578e0539563b90bd5985e8;hb=b0648742235b8ed4e1b16977286b8de07e7054cf;hp=3205b46bcd91ab4dd485f9b2a0fa6573f2adf140;hpb=736937b3926814f792373885a9a0a4519bae7787;p=netdata.git diff --git a/src/common.c b/src/common.c index 3205b46b..e46397c6 100644 --- a/src/common.c +++ b/src/common.c @@ -1,9 +1,28 @@ #include "common.h" -char *global_host_prefix = ""; +#ifdef __APPLE__ +#define INHERIT_NONE 0 +#endif /* __APPLE__ */ +#if defined(__FreeBSD__) || defined(__APPLE__) +# define O_NOATIME 0 +# define MADV_DONTFORK INHERIT_NONE +#endif /* __FreeBSD__ || __APPLE__*/ + +char *netdata_configured_hostname = NULL; +char *netdata_configured_config_dir = NULL; +char *netdata_configured_log_dir = NULL; +char *netdata_configured_plugins_dir = NULL; +char *netdata_configured_web_dir = NULL; +char *netdata_configured_cache_dir = NULL; +char *netdata_configured_varlib_dir = NULL; +char *netdata_configured_home_dir = NULL; +char *netdata_configured_host_prefix = NULL; + int enable_ksm = 1; volatile sig_atomic_t netdata_exit = 0; +const char *os_type = NETDATA_OS_TYPE; +const char *program_version = VERSION; // ---------------------------------------------------------------------------- // memory allocation functions that handle failures @@ -14,55 +33,200 @@ volatile sig_atomic_t netdata_exit = 0; // its lifetime), these can be used to override the default system allocation // routines. +#ifdef NETDATA_LOG_ALLOCATIONS +static struct memory_statistics { + volatile size_t malloc_calls_made; + volatile size_t calloc_calls_made; + volatile size_t realloc_calls_made; + volatile size_t strdup_calls_made; + volatile size_t free_calls_made; + volatile size_t memory_calls_made; + volatile size_t allocated_memory; + volatile size_t mmapped_memory; +} memory_statistics; + +static inline void print_allocations(const char *file, const char *function, const unsigned long line) { + static struct memory_statistics old = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + //if(unlikely(!(memory_statistics.memory_calls_made % 5))) { + fprintf(stderr, "(%04lu@%-10.10s:%-15.15s): Allocated %zu KB (+%zu B), mmapped %zu KB (+%zu B): malloc %zu (+%zu), calloc %zu (+%zu), realloc %zu (+%zu), strdup %zu (+%zu), free %zu (+%zu)\n", + line, file, function, + (memory_statistics.allocated_memory + 512) / 1024, memory_statistics.allocated_memory - old.allocated_memory, + (memory_statistics.mmapped_memory + 512) / 1024, memory_statistics.mmapped_memory - old.mmapped_memory, + memory_statistics.malloc_calls_made, memory_statistics.malloc_calls_made - old.malloc_calls_made, + memory_statistics.calloc_calls_made, memory_statistics.calloc_calls_made - old.calloc_calls_made, + memory_statistics.realloc_calls_made, memory_statistics.realloc_calls_made - old.realloc_calls_made, + memory_statistics.strdup_calls_made, memory_statistics.strdup_calls_made - old.strdup_calls_made, + memory_statistics.free_calls_made, memory_statistics.free_calls_made - old.free_calls_made + ); + + memcpy(&old, &memory_statistics, sizeof(struct memory_statistics)); + //} +} + +static inline void malloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) { +#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) + __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); +#else + // this is for debugging - we don't care locking it + memory_statistics.memory_calls_made++; + memory_statistics.malloc_calls_made++; + memory_statistics.allocated_memory += size; +#endif + print_allocations(file, function, line); +} + +static inline void mmap_accounting(size_t size) { +#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) + __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.mmapped_memory, size, __ATOMIC_SEQ_CST); +#else + // this is for debugging - we don't care locking it + memory_statistics.memory_calls_made++; + memory_statistics.mmapped_memory += size; +#endif +} + +static inline void calloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) { +#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) + __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.calloc_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); +#else + // this is for debugging - we don't care locking it + memory_statistics.memory_calls_made++; + memory_statistics.calloc_calls_made++; + memory_statistics.allocated_memory += size; +#endif + print_allocations(file, function, line); +} + +static inline void realloc_accounting(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) { + (void)ptr; + +#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) + __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.realloc_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); +#else + // this is for debugging - we don't care locking it + memory_statistics.memory_calls_made++; + memory_statistics.realloc_calls_made++; + memory_statistics.allocated_memory += size; +#endif + print_allocations(file, function, line); +} + +static inline void strdup_accounting(const char *file, const char *function, const unsigned long line, const char *s) { + size_t size = strlen(s) + 1; + +#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) + __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.strdup_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST); +#else + // this is for debugging - we don't care locking it + memory_statistics.memory_calls_made++; + memory_statistics.strdup_calls_made++; + memory_statistics.allocated_memory += size; +#endif + print_allocations(file, function, line); +} + +static inline void free_accounting(const char *file, const char *function, const unsigned long line, void *ptr) { + (void)file; + (void)function; + (void)line; + + if(likely(ptr)) { +#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS) + __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST); + __atomic_fetch_add(&memory_statistics.free_calls_made, 1, __ATOMIC_SEQ_CST); +#else + // this is for debugging - we don't care locking it + memory_statistics.memory_calls_made++; + memory_statistics.free_calls_made++; +#endif + } +} +#endif + +#ifdef NETDATA_LOG_ALLOCATIONS +char *strdupz_int(const char *file, const char *function, const unsigned long line, const char *s) { + strdup_accounting(file, function, line, s); +#else char *strdupz(const char *s) { +#endif + char *t = strdup(s); if (unlikely(!t)) fatal("Cannot strdup() string '%s'", s); return t; } +#ifdef NETDATA_LOG_ALLOCATIONS +void *mallocz_int(const char *file, const char *function, const unsigned long line, size_t size) { + malloc_accounting(file, function, line, size); +#else void *mallocz(size_t size) { +#endif + void *p = malloc(size); if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size); return p; } +#ifdef NETDATA_LOG_ALLOCATIONS +void *callocz_int(const char *file, const char *function, const unsigned long line, size_t nmemb, size_t size) { + calloc_accounting(file, function, line, nmemb * size); +#else void *callocz(size_t nmemb, size_t size) { +#endif + void *p = calloc(nmemb, size); if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size); return p; } +#ifdef NETDATA_LOG_ALLOCATIONS +void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) { + realloc_accounting(file, function, line, ptr, size); +#else void *reallocz(void *ptr, size_t size) { +#endif + void *p = realloc(ptr, size); if (unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size); return p; } +#ifdef NETDATA_LOG_ALLOCATIONS +void freez_int(const char *file, const char *function, const unsigned long line, void *ptr) { + free_accounting(file, function, line, ptr); +#else void freez(void *ptr) { +#endif + free(ptr); } -// ---------------------------------------------------------------------------- -// time functions - -inline unsigned long long timeval_usec(struct timeval *tv) { - return tv->tv_sec * 1000000ULL + tv->tv_usec; -} +void json_escape_string(char *dst, const char *src, size_t size) { + const char *t; + char *d = dst, *e = &dst[size - 1]; -// time(NULL) in nanoseconds -inline unsigned long long time_usec(void) { - struct timeval now; - gettimeofday(&now, NULL); - return timeval_usec(&now); -} + for(t = src; *t && d < e ;t++) { + if(unlikely(*t == '\\' || *t == '"')) { + if(unlikely(d + 1 >= e)) break; + *d++ = '\\'; + } + *d++ = *t; + } -inline unsigned long long usec_dt(struct timeval *now, struct timeval *old) { - unsigned long long tv1 = timeval_usec(now); - unsigned long long tv2 = timeval_usec(old); - return (tv1 > tv2) ? (tv1 - tv2) : (tv2 - tv1); + *d = '\0'; } -int sleep_usec(unsigned long long usec) { +int sleep_usec(usec_t usec) { #ifndef NETDATA_WITH_USLEEP // we expect microseconds (1.000.000 per second) @@ -74,7 +238,7 @@ int sleep_usec(unsigned long long usec) { while (nanosleep(&req, &rem) == -1) { if (likely(errno == EINTR)) { - info("nanosleep() interrupted (while sleeping for %llu microseconds).", usec); + debug(D_SYSTEM, "nanosleep() interrupted (while sleeping for %llu microseconds).", usec); req.tv_sec = rem.tv_sec; req.tv_nsec = rem.tv_nsec; } else { @@ -654,7 +818,7 @@ uint32_t simple_hash(const char *name) } */ - +/* // http://isthe.com/chongo/tech/comp/fnv/#FNV-1a uint32_t simple_hash(const char *name) { unsigned char *s = (unsigned char *) name; @@ -689,6 +853,7 @@ uint32_t simple_uhash(const char *name) { } return hval; } +*/ /* // http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx @@ -714,11 +879,9 @@ uint32_t simple_hash(const char *name) { */ void strreverse(char *begin, char *end) { - char aux; - while (end > begin) { // clearer code. - aux = *end; + char aux = *end; *end-- = *begin; *begin++ = aux; } @@ -755,11 +918,10 @@ void *mymmap(const char *filename, size_t size, int flags, int ksm) { #ifdef MADV_MERGEABLE static int log_madvise_2 = 1, log_madvise_3 = 1; #endif - int fd; void *mem = NULL; errno = 0; - fd = open(filename, O_RDWR | O_CREAT | O_NOATIME, 0664); + int fd = open(filename, O_RDWR | O_CREAT | O_NOATIME, 0664); if (fd != -1) { if (lseek(fd, size, SEEK_SET) == (off_t) size) { if (write(fd, "", 1) == 1) { @@ -775,6 +937,9 @@ void *mymmap(const char *filename, size_t size, int flags, int ksm) { mem = NULL; } else { +#ifdef NETDATA_LOG_ALLOCATIONS + mmap_accounting(size); +#endif int advise = MADV_SEQUENTIAL | MADV_DONTFORK; if (flags & MAP_SHARED) advise |= MADV_WILLNEED; @@ -804,6 +969,9 @@ void *mymmap(const char *filename, size_t size, int flags, int ksm) { mem = NULL; } else { +#ifdef NETDATA_LOG_ALLOCATIONS + mmap_accounting(size); +#endif if (lseek(fd, 0, SEEK_SET) == 0) { if (read(fd, mem, size) != (ssize_t) size) error("Cannot read from file '%s'", filename); @@ -872,7 +1040,15 @@ int fd_is_valid(int fd) { } pid_t gettid(void) { +#ifdef __FreeBSD__ + return (pid_t)pthread_getthreadid_np(); +#elif defined(__APPLE__) + uint64_t curthreadid; + pthread_threadid_np(NULL, &curthreadid); + return (pid_t)curthreadid; +#else return (pid_t)syscall(SYS_gettid); +#endif /* __FreeBSD__, __APPLE__*/ } char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) { @@ -895,17 +1071,6 @@ char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) { return s; } -char *strncpyz(char *dst, const char *src, size_t n) { - char *p = dst; - - while (*src && n--) - *dst++ = *src++; - - *dst = '\0'; - - return p; -} - int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) { int size = vsnprintf(dst, n, fmt, args); @@ -934,14 +1099,34 @@ int snprintfz(char *dst, size_t n, const char *fmt, ...) { int processors = 1; long get_system_cpus(void) { - procfile *ff = NULL; - processors = 1; + #ifdef __APPLE__ + int32_t tmp_processors; + + if (unlikely(GETSYSCTL("hw.logicalcpu", tmp_processors))) { + error("Assuming system has %d processors.", processors); + } else { + processors = tmp_processors; + } + + return processors; + #elif __FreeBSD__ + int32_t tmp_processors; + + if (unlikely(GETSYSCTL("hw.ncpu", tmp_processors))) { + error("Assuming system has %d processors.", processors); + } else { + processors = tmp_processors; + } + + return processors; + #else + char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/proc/stat", global_host_prefix); + snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix); - ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT); + procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT); if(!ff) { error("Cannot open file '%s'. Assuming system has %d processors.", filename, processors); return processors; @@ -965,39 +1150,54 @@ long get_system_cpus(void) { procfile_close(ff); - info("System has %d processors.", processors); + debug(D_SYSTEM, "System has %d processors.", processors); return processors; + + #endif /* __APPLE__, __FreeBSD__ */ } pid_t pid_max = 32768; pid_t get_system_pid_max(void) { - procfile *ff = NULL; + #ifdef __APPLE__ + // As we currently do not know a solution to query pid_max from the os + // we use the number defined in bsd/sys/proc_internal.h in XNU sources + pid_max = 99999; + return pid_max; + #elif __FreeBSD__ + int32_t tmp_pid_max; + + if (unlikely(GETSYSCTL("kern.pid_max", tmp_pid_max))) { + pid_max = 99999; + error("Assuming system's maximum pid is %d.", pid_max); + } else { + pid_max = tmp_pid_max; + } - char filename[FILENAME_MAX + 1]; - snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", global_host_prefix); - ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT); - if(!ff) { - error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max); return pid_max; - } + #else - ff = procfile_readall(ff); - if(!ff) { - error("Cannot read file '%s'. Assuming system supports %d pids.", filename, pid_max); + static char read = 0; + if(unlikely(read)) return pid_max; + read = 1; + + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix); + + unsigned long long max = 0; + if(read_single_number_file(filename, &max) != 0) { + error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max); return pid_max; } - pid_max = (pid_t)atoi(procfile_lineword(ff, 0, 0)); - if(!pid_max) { - procfile_close(ff); - pid_max = 32768; + if(!max) { error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max); return pid_max; } - procfile_close(ff); - info("System supports %d pids.", pid_max); + pid_max = (pid_t) max; return pid_max; + + #endif /* __APPLE__, __FreeBSD__ */ } unsigned int hz; @@ -1005,8 +1205,23 @@ void get_system_HZ(void) { long ticks; if ((ticks = sysconf(_SC_CLK_TCK)) == -1) { - perror("sysconf"); + error("Cannot get system clock ticks"); } hz = (unsigned int) ticks; } + +/* +// poor man cycle counting +static unsigned long tsc; +void begin_tsc(void) { + unsigned long a, d; + asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx"); + tsc = ((unsigned long)d << 32) | (unsigned long)a; +} +unsigned long end_tsc(void) { + unsigned long a, d; + asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx"); + return (((unsigned long)d << 32) | (unsigned long)a) - tsc; +} +*/