diff options
Diffstat (limited to 'src/collectors/apps.plugin/apps_plugin.c')
-rw-r--r-- | src/collectors/apps.plugin/apps_plugin.c | 722 |
1 files changed, 223 insertions, 499 deletions
diff --git a/src/collectors/apps.plugin/apps_plugin.c b/src/collectors/apps.plugin/apps_plugin.c index 8fe1ff008..b8ea0e797 100644 --- a/src/collectors/apps.plugin/apps_plugin.c +++ b/src/collectors/apps.plugin/apps_plugin.c @@ -27,18 +27,21 @@ // options bool debug_enabled = false; -bool enable_guest_charts = false; + bool enable_detailed_uptime_charts = false; bool enable_users_charts = true; bool enable_groups_charts = true; bool include_exited_childs = true; -bool proc_pid_cmdline_is_needed = false; // true when we need to read /proc/cmdline - -#if defined(__FreeBSD__) || defined(__APPLE__) -bool enable_file_charts = false; -#else -bool enable_file_charts = true; +bool proc_pid_cmdline_is_needed = true; // true when we need to read /proc/cmdline + +#if defined(OS_FREEBSD) || defined(OS_MACOS) +int enable_file_charts = CONFIG_BOOLEAN_NO; +#elif defined(OS_LINUX) +int enable_file_charts = CONFIG_BOOLEAN_AUTO; +#elif defined(OS_WINDOWS) +int enable_file_charts = CONFIG_BOOLEAN_YES; #endif +bool obsolete_file_charts = false; // ---------------------------------------------------------------------------- // internal counters @@ -53,19 +56,16 @@ size_t targets_assignment_counter = 0, apps_groups_targets_count = 0; // # of apps_groups.conf targets -int - all_files_len = 0, - all_files_size = 0, - show_guest_time = 0, // 1 when guest values are collected - show_guest_time_old = 0; - -#if defined(__FreeBSD__) || defined(__APPLE__) -usec_t system_current_time_ut; -#else -kernel_uint_t system_uptime_secs; +#if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) +bool enable_guest_charts = false; +bool show_guest_time = false; // set when guest values are collected #endif -// ---------------------------------------------------------------------------- +uint32_t + all_files_len = 0, + all_files_size = 0; + +// -------------------------------------------------------------------------------------------------------------------- // Normalization // // With normalization we lower the collected metrics by a factor to make them @@ -74,16 +74,18 @@ kernel_uint_t system_uptime_secs; // the metrics. This results in utilization that exceeds the total utilization // of the system. // -// During normalization, we align the per-process utilization, to the total of -// the system. We first consume the exited children utilization and it the -// collected values is above the total, we proportionally scale each reported -// metric. +// During normalization, we align the per-process utilization to the global +// utilization of the system. We first consume the exited children utilization +// and it the collected values is above the total, we proportionally scale each +// reported metric. // the total system time, as reported by /proc/stat +#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) kernel_uint_t global_utime = 0, global_stime = 0, global_gtime = 0; +#endif // the normalization ratios, as calculated by normalize_utilization() NETDATA_DOUBLE @@ -98,21 +100,11 @@ NETDATA_DOUBLE cminflt_fix_ratio = 1.0, cmajflt_fix_ratio = 1.0; -// ---------------------------------------------------------------------------- -// factor for calculating correct CPU time values depending on units of raw data -unsigned int time_factor = 0; - -// ---------------------------------------------------------------------------- -// command line options +// -------------------------------------------------------------------------------------------------------------------- int update_every = 1; -#if defined(__APPLE__) -mach_timebase_info_data_t mach_info; -#endif - -#if !defined(__FreeBSD__) && !defined(__APPLE__) -int max_fds_cache_seconds = 60; +#if defined(OS_LINUX) proc_state proc_state_count[PROC_STATUS_END]; const char *proc_states[] = { [PROC_STATUS_RUNNING] = "running", @@ -127,420 +119,104 @@ const char *proc_states[] = { static char *user_config_dir = CONFIG_DIR; static char *stock_config_dir = LIBCONFIG_DIR; -struct target - *apps_groups_default_target = NULL, // the default target - *apps_groups_root_target = NULL, // apps_groups.conf defined - *users_root_target = NULL, // users - *groups_root_target = NULL; // user groups - size_t pagesize; -// ---------------------------------------------------------------------------- - -int managed_log(struct pid_stat *p, PID_LOG log, int status) { - if(unlikely(!status)) { - // netdata_log_error("command failed log %u, errno %d", log, errno); - - if(unlikely(debug_enabled || errno != ENOENT)) { - if(unlikely(debug_enabled || !(p->log_thrown & log))) { - p->log_thrown |= log; - switch(log) { - case PID_LOG_IO: - #if defined(__FreeBSD__) || defined(__APPLE__) - netdata_log_error("Cannot fetch process %d I/O info (command '%s')", p->pid, p->comm); - #else - netdata_log_error("Cannot process %s/proc/%d/io (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_STATUS: - #if defined(__FreeBSD__) || defined(__APPLE__) - netdata_log_error("Cannot fetch process %d status info (command '%s')", p->pid, p->comm); - #else - netdata_log_error("Cannot process %s/proc/%d/status (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_CMDLINE: - #if defined(__FreeBSD__) || defined(__APPLE__) - netdata_log_error("Cannot fetch process %d command line (command '%s')", p->pid, p->comm); - #else - netdata_log_error("Cannot process %s/proc/%d/cmdline (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_FDS: - #if defined(__FreeBSD__) || defined(__APPLE__) - netdata_log_error("Cannot fetch process %d files (command '%s')", p->pid, p->comm); - #else - netdata_log_error("Cannot process entries in %s/proc/%d/fd (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - break; - - case PID_LOG_LIMITS: - #if defined(__FreeBSD__) || defined(__APPLE__) - ; - #else - netdata_log_error("Cannot process %s/proc/%d/limits (command '%s')", netdata_configured_host_prefix, p->pid, p->comm); - #endif - - case PID_LOG_STAT: - break; - - default: - netdata_log_error("unhandled error for pid %d, command '%s'", p->pid, p->comm); - break; - } - } - } - errno_clear(); - } - else if(unlikely(p->log_thrown & log)) { - // netdata_log_error("unsetting log %u on pid %d", log, p->pid); - p->log_thrown &= ~log; - } - - return status; +void sanitize_apps_plugin_chart_meta(char *buf) { + external_plugins_sanitize(buf, buf, strlen(buf) + 1); } // ---------------------------------------------------------------------------- -// update statistics on the targets - -// 1. link all childs to their parents -// 2. go from bottom to top, marking as merged all children to their parents, -// this step links all parents without a target to the child target, if any -// 3. link all top level processes (the ones not merged) to default target -// 4. go from top to bottom, linking all children without a target to their parent target -// after this step all processes have a target. -// [5. for each killed pid (updated = 0), remove its usage from its target] -// 6. zero all apps_groups_targets -// 7. concentrate all values on the apps_groups_targets -// 8. remove all killed processes -// 9. find the unique file count for each target -// check: update_apps_groups_statistics() - -static void apply_apps_groups_targets_inheritance(void) { - struct pid_stat *p = NULL; - - // children that do not have a target - // inherit their target from their parent - int found = 1, loops = 0; - while(found) { - if(unlikely(debug_enabled)) loops++; - found = 0; - for(p = root_of_pids; p ; p = p->next) { - // if this process does not have a target, - // and it has a parent - // and its parent has a target - // then, set the parent's target to this process - if(unlikely(!p->target && p->parent && p->parent->target)) { - p->target = p->parent->target; - found++; - - if(debug_enabled || (p->target && p->target->debug_enabled)) - debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s).", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm); - } - } - } - - // find all the procs with 0 childs and merge them to their parents - // repeat, until nothing more can be done. - int sortlist = 1; - found = 1; - while(found) { - if(unlikely(debug_enabled)) loops++; - found = 0; - - for(p = root_of_pids; p ; p = p->next) { - if(unlikely(!p->sortlist && !p->children_count)) - p->sortlist = sortlist++; - - if(unlikely( - !p->children_count // if this process does not have any children - && !p->merged // and is not already merged - && p->parent // and has a parent - && p->parent->children_count // and its parent has children - // and the target of this process and its parent is the same, - // or the parent does not have a target - && (p->target == p->parent->target || !p->parent->target) - && p->ppid != INIT_PID // and its parent is not init - )) { - // mark it as merged - p->parent->children_count--; - p->merged = true; - - // the parent inherits the child's target, if it does not have a target itself - if(unlikely(p->target && !p->parent->target)) { - p->parent->target = p->target; - - if(debug_enabled || (p->target && p->target->debug_enabled)) - debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its child %d (%s).", p->target->name, p->parent->pid, p->parent->comm, p->pid, p->comm); - } - - found++; - } - } - - debug_log("TARGET INHERITANCE: merged %d processes", found); - } - - // init goes always to default target - struct pid_stat *pi = find_pid_entry(INIT_PID); - if(pi && !pi->matched_by_config) - pi->target = apps_groups_default_target; - - // pid 0 goes always to default target - pi = find_pid_entry(0); - if(pi && !pi->matched_by_config) - pi->target = apps_groups_default_target; - - // give a default target on all top level processes - if(unlikely(debug_enabled)) loops++; - for(p = root_of_pids; p ; p = p->next) { - // if the process is not merged itself - // then it is a top level process - if(unlikely(!p->merged && !p->target)) - p->target = apps_groups_default_target; - - // make sure all processes have a sortlist - if(unlikely(!p->sortlist)) - p->sortlist = sortlist++; - } - - pi = find_pid_entry(1); - if(pi) - pi->sortlist = sortlist++; - - // give a target to all merged child processes - found = 1; - while(found) { - if(unlikely(debug_enabled)) loops++; - found = 0; - for(p = root_of_pids; p ; p = p->next) { - if(unlikely(!p->target && p->merged && p->parent && p->parent->target)) { - p->target = p->parent->target; - found++; - - if(debug_enabled || (p->target && p->target->debug_enabled)) - debug_log_int("TARGET INHERITANCE: %s is inherited by %d (%s) from its parent %d (%s) at phase 2.", p->target->name, p->pid, p->comm, p->parent->pid, p->parent->comm); - } - } - } - - debug_log("apply_apps_groups_targets_inheritance() made %d loops on the process tree", loops); -} - -static size_t zero_all_targets(struct target *root) { - struct target *w; - size_t count = 0; - - for (w = root; w ; w = w->next) { - count++; - - w->minflt = 0; - w->majflt = 0; - w->utime = 0; - w->stime = 0; - w->gtime = 0; - w->cminflt = 0; - w->cmajflt = 0; - w->cutime = 0; - w->cstime = 0; - w->cgtime = 0; - w->num_threads = 0; - // w->rss = 0; - w->processes = 0; - - w->status_vmsize = 0; - w->status_vmrss = 0; - w->status_vmshared = 0; - w->status_rssfile = 0; - w->status_rssshmem = 0; - w->status_vmswap = 0; - w->status_voluntary_ctxt_switches = 0; - w->status_nonvoluntary_ctxt_switches = 0; - - w->io_logical_bytes_read = 0; - w->io_logical_bytes_written = 0; - w->io_read_calls = 0; - w->io_write_calls = 0; - w->io_storage_bytes_read = 0; - w->io_storage_bytes_written = 0; - w->io_cancelled_write_bytes = 0; - - // zero file counters - if(w->target_fds) { - memset(w->target_fds, 0, sizeof(int) * w->target_fds_size); - w->openfds.files = 0; - w->openfds.pipes = 0; - w->openfds.sockets = 0; - w->openfds.inotifies = 0; - w->openfds.eventfds = 0; - w->openfds.timerfds = 0; - w->openfds.signalfds = 0; - w->openfds.eventpolls = 0; - w->openfds.other = 0; - - w->max_open_files_percent = 0.0; - } - - w->uptime_min = 0; - w->uptime_sum = 0; - w->uptime_max = 0; - - if(unlikely(w->root_pid)) { - struct pid_on_target *pid_on_target = w->root_pid; +// update chart dimensions - while(pid_on_target) { - struct pid_on_target *pid_on_target_to_free = pid_on_target; - pid_on_target = pid_on_target->next; - freez(pid_on_target_to_free); - } +// Helper function to count the number of processes in the linked list +int count_processes(struct pid_stat *root) { + int count = 0; - w->root_pid = NULL; - } - } + for(struct pid_stat *p = root; p ; p = p->next) + if(p->updated) count++; return count; } -static inline void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) { - (void)o; - - if(unlikely(!p->updated)) { - // the process is not running - return; - } - - if(unlikely(!w)) { - netdata_log_error("pid %d %s was left without a target!", p->pid, p->comm); - return; - } - - if(p->openfds_limits_percent > w->max_open_files_percent) - w->max_open_files_percent = p->openfds_limits_percent; - - w->cutime += p->cutime; - w->cstime += p->cstime; - w->cgtime += p->cgtime; - w->cminflt += p->cminflt; - w->cmajflt += p->cmajflt; - - w->utime += p->utime; - w->stime += p->stime; - w->gtime += p->gtime; - w->minflt += p->minflt; - w->majflt += p->majflt; - - // w->rss += p->rss; - - w->status_vmsize += p->status_vmsize; - w->status_vmrss += p->status_vmrss; - w->status_vmshared += p->status_vmshared; - w->status_rssfile += p->status_rssfile; - w->status_rssshmem += p->status_rssshmem; - w->status_vmswap += p->status_vmswap; - w->status_voluntary_ctxt_switches += p->status_voluntary_ctxt_switches; - w->status_nonvoluntary_ctxt_switches += p->status_nonvoluntary_ctxt_switches; - - w->io_logical_bytes_read += p->io_logical_bytes_read; - w->io_logical_bytes_written += p->io_logical_bytes_written; - w->io_read_calls += p->io_read_calls; - w->io_write_calls += p->io_write_calls; - w->io_storage_bytes_read += p->io_storage_bytes_read; - w->io_storage_bytes_written += p->io_storage_bytes_written; - w->io_cancelled_write_bytes += p->io_cancelled_write_bytes; - - w->processes++; - w->num_threads += p->num_threads; - - if(!w->uptime_min || p->uptime < w->uptime_min) w->uptime_min = p->uptime; - if(!w->uptime_max || w->uptime_max < p->uptime) w->uptime_max = p->uptime; - w->uptime_sum += p->uptime; - - if(unlikely(debug_enabled || w->debug_enabled)) { - debug_log_int("aggregating '%s' pid %d on target '%s' utime=" KERNEL_UINT_FORMAT ", stime=" KERNEL_UINT_FORMAT ", gtime=" KERNEL_UINT_FORMAT ", cutime=" KERNEL_UINT_FORMAT ", cstime=" KERNEL_UINT_FORMAT ", cgtime=" KERNEL_UINT_FORMAT ", minflt=" KERNEL_UINT_FORMAT ", majflt=" KERNEL_UINT_FORMAT ", cminflt=" KERNEL_UINT_FORMAT ", cmajflt=" KERNEL_UINT_FORMAT "", p->comm, p->pid, w->name, p->utime, p->stime, p->gtime, p->cutime, p->cstime, p->cgtime, p->minflt, p->majflt, p->cminflt, p->cmajflt); - - struct pid_on_target *pid_on_target = mallocz(sizeof(struct pid_on_target)); - pid_on_target->pid = p->pid; - pid_on_target->next = w->root_pid; - w->root_pid = pid_on_target; - } +// Comparator function to sort by pid +int compare_by_pid(const void *a, const void *b) { + struct pid_stat *pa = *(struct pid_stat **)a; + struct pid_stat *pb = *(struct pid_stat **)b; + return ((int)pa->pid - (int)pb->pid); } -static void calculate_netdata_statistics(void) { - apply_apps_groups_targets_inheritance(); - - zero_all_targets(users_root_target); - zero_all_targets(groups_root_target); - apps_groups_targets_count = zero_all_targets(apps_groups_root_target); - - // this has to be done, before the cleanup - struct pid_stat *p = NULL; - struct target *w = NULL, *o = NULL; - - // concentrate everything on the targets - for(p = root_of_pids; p ; p = p->next) { - - // -------------------------------------------------------------------- - // apps_groups target - - aggregate_pid_on_target(p->target, p, NULL); +// Function to print a process and its children recursively +void print_process_tree(struct pid_stat *root, struct pid_stat *parent, int depth, int total_processes) { + // Allocate an array of pointers for processes with the given parent + struct pid_stat **children = (struct pid_stat **)malloc(total_processes * sizeof(struct pid_stat *)); + int children_count = 0; - - // -------------------------------------------------------------------- - // user target - - o = p->user_target; - if(likely(p->user_target && p->user_target->uid == p->uid)) - w = p->user_target; - else { - if(unlikely(debug_enabled && p->user_target)) - debug_log("pid %d (%s) switched user from %u (%s) to %u.", p->pid, p->comm, p->user_target->uid, p->user_target->name, p->uid); - - w = p->user_target = get_users_target(p->uid); + // Populate the array with processes that have the given parent + struct pid_stat *p = root; + while (p != NULL) { + if (p->updated && p->parent == parent) { + children[children_count++] = p; } + p = p->next; + } - aggregate_pid_on_target(w, p, o); - - - // -------------------------------------------------------------------- - // user group target - - o = p->group_target; - if(likely(p->group_target && p->group_target->gid == p->gid)) - w = p->group_target; - else { - if(unlikely(debug_enabled && p->group_target)) - debug_log("pid %d (%s) switched group from %u (%s) to %u.", p->pid, p->comm, p->group_target->gid, p->group_target->name, p->gid); + // Sort the children array by pid + qsort(children, children_count, sizeof(struct pid_stat *), compare_by_pid); - w = p->group_target = get_groups_target(p->gid); + // Print each child and recurse + for (int i = 0; i < children_count; i++) { + // Print the current process with indentation based on depth + if (depth > 0) { + for (int j = 0; j < (depth - 1) * 4; j++) { + printf(" "); + } + printf(" \\_ "); } - aggregate_pid_on_target(w, p, o); +#if (PROCESSES_HAVE_COMM_AND_NAME == 1) + printf("[%d] %s (name: %s) [%s]: %s\n", children[i]->pid, + string2str(children[i]->comm), + string2str(children[i]->name), + string2str(children[i]->target->name), + string2str(children[i]->cmdline)); +#else + printf("[%d] orig: '%s' new: '%s' [target: %s]: cmdline: %s\n", children[i]->pid, + string2str(children[i]->comm_orig), + string2str(children[i]->comm), + string2str(children[i]->target->name), + string2str(children[i]->cmdline)); +#endif + // Recurse to print this child's children + print_process_tree(root, children[i], depth + 1, total_processes); + } - // -------------------------------------------------------------------- - // aggregate all file descriptors + // Free the allocated array + free(children); +} - if(enable_file_charts) - aggregate_pid_fds_on_targets(p); - } +// Function to print the full hierarchy +void print_hierarchy(struct pid_stat *root) { + // Count the total number of processes + int total_processes = count_processes(root); - cleanup_exited_pids(); + // Start printing from processes with parent = NULL (i.e., root processes) + print_process_tree(root, NULL, 0, total_processes); } // ---------------------------------------------------------------------------- // update chart dimensions +#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) static void normalize_utilization(struct target *root) { struct target *w; - // childs processing introduces spikes - // here we try to eliminate them by disabling childs processing either for specific dimensions - // or entirely. Of course, either way, we disable it just a single iteration. + // children processing introduces spikes, + // here we try to eliminate them by disabling children processing either + // for specific dimensions or entirely. + // of course, either way, we disable it just for a single iteration. - kernel_uint_t max_time = os_get_system_cpus() * time_factor * RATES_DETAIL; + kernel_uint_t max_time = os_get_system_cpus() * NSEC_PER_SEC; kernel_uint_t utime = 0, cutime = 0, stime = 0, cstime = 0, gtime = 0, cgtime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0; if(global_utime > max_time) global_utime = max_time; @@ -548,19 +224,19 @@ static void normalize_utilization(struct target *root) { if(global_gtime > max_time) global_gtime = max_time; for(w = root; w ; w = w->next) { - if(w->target || (!w->processes && !w->exposed)) continue; - - utime += w->utime; - stime += w->stime; - gtime += w->gtime; - cutime += w->cutime; - cstime += w->cstime; - cgtime += w->cgtime; - - minflt += w->minflt; - majflt += w->majflt; - cminflt += w->cminflt; - cmajflt += w->cmajflt; + if(w->target || (!w->values[PDF_PROCESSES] && !w->exposed)) continue; + + utime += w->values[PDF_UTIME]; + stime += w->values[PDF_STIME]; + gtime += w->values[PDF_GTIME]; + cutime += w->values[PDF_CUTIME]; + cstime += w->values[PDF_CSTIME]; + cgtime += w->values[PDF_CGTIME]; + + minflt += w->values[PDF_MINFLT]; + majflt += w->values[PDF_MAJFLT]; + cminflt += w->values[PDF_CMINFLT]; + cmajflt += w->values[PDF_CMAJFLT]; } if(global_utime || global_stime || global_gtime) { @@ -574,7 +250,7 @@ static void normalize_utilization(struct target *root) { cgtime_fix_ratio = 1.0; //(NETDATA_DOUBLE)(global_utime + global_stime) / (NETDATA_DOUBLE)(utime + cutime + stime + cstime); } else if((global_utime + global_stime > utime + stime) && (cutime || cstime)) { - // children resources are too high + // children resources are too high, // lower only the children resources utime_fix_ratio = stime_fix_ratio = @@ -683,6 +359,7 @@ static void normalize_utilization(struct target *root) { , (kernel_uint_t)(cgtime * cgtime_fix_ratio) ); } +#endif // ---------------------------------------------------------------------------- // parse command line arguments @@ -690,6 +367,7 @@ static void normalize_utilization(struct target *root) { int check_proc_1_io() { int ret = 0; +#if defined(OS_LINUX) procfile *ff = procfile_open("/proc/1/io", NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); if(!ff) goto cleanup; @@ -700,9 +378,14 @@ int check_proc_1_io() { cleanup: procfile_close(ff); +#endif + return ret; } +static bool profile_speed = false; +static bool print_tree_and_exit = false; + static void parse_args(int argc, char **argv) { int i, freq = 0; @@ -721,6 +404,12 @@ static void parse_args(int argc, char **argv) exit(0); } + if(strcmp("print", argv[i]) == 0 || strcmp("-print", argv[i]) == 0 || strcmp("--print", argv[i]) == 0) { + print_tree_and_exit = true; + continue; + } + +#if defined(OS_LINUX) if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) { if(!check_proc_1_io()) { perror("Tried to read /proc/1/io and it failed"); @@ -729,6 +418,7 @@ static void parse_args(int argc, char **argv) printf("OK\n"); exit(0); } +#endif if(strcmp("debug", argv[i]) == 0) { debug_enabled = true; @@ -738,7 +428,12 @@ static void parse_args(int argc, char **argv) continue; } -#if !defined(__FreeBSD__) && !defined(__APPLE__) + if(strcmp("profile-speed", argv[i]) == 0) { + profile_speed = true; + continue; + } + +#if defined(OS_LINUX) if(strcmp("fds-cache-secs", argv[i]) == 0) { if(argc <= i + 1) { fprintf(stderr, "Parameter 'fds-cache-secs' requires a number as argument.\n"); @@ -751,6 +446,7 @@ static void parse_args(int argc, char **argv) } #endif +#if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) || (PROCESSES_HAVE_CHILDREN_FLTS == 1) if(strcmp("no-childs", argv[i]) == 0 || strcmp("without-childs", argv[i]) == 0) { include_exited_childs = 0; continue; @@ -760,7 +456,9 @@ static void parse_args(int argc, char **argv) include_exited_childs = 1; continue; } +#endif +#if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) if(strcmp("with-guest", argv[i]) == 0) { enable_guest_charts = true; continue; @@ -770,26 +468,33 @@ static void parse_args(int argc, char **argv) enable_guest_charts = false; continue; } +#endif +#if (PROCESSES_HAVE_FDS == 1) if(strcmp("with-files", argv[i]) == 0) { - enable_file_charts = 1; + enable_file_charts = CONFIG_BOOLEAN_YES; continue; } if(strcmp("no-files", argv[i]) == 0 || strcmp("without-files", argv[i]) == 0) { - enable_file_charts = 0; + enable_file_charts = CONFIG_BOOLEAN_NO; continue; } +#endif +#if (PROCESSES_HAVE_UID == 1) || (PROCESSES_HAVE_SID == 1) if(strcmp("no-users", argv[i]) == 0 || strcmp("without-users", argv[i]) == 0) { enable_users_charts = 0; continue; } +#endif +#if (PROCESSES_HAVE_GID == 1) if(strcmp("no-groups", argv[i]) == 0 || strcmp("without-groups", argv[i]) == 0) { enable_groups_charts = 0; continue; } +#endif if(strcmp("with-detailed-uptime", argv[i]) == 0) { enable_detailed_uptime_charts = 1; @@ -821,26 +526,36 @@ static void parse_args(int argc, char **argv) " it may include sensitive data such as passwords and tokens\n" " enabling this could be a security risk\n" "\n" +#if (PROCESSES_HAVE_CPU_CHILDREN_TIME == 1) || (PROCESSES_HAVE_CHILDREN_FLTS == 1) " with-childs\n" " without-childs enable / disable aggregating exited\n" " children resources into parents\n" " (default is enabled)\n" "\n" +#endif +#if (PROCESSES_HAVE_CPU_GUEST_TIME == 1) " with-guest\n" " without-guest enable / disable reporting guest charts\n" " (default is disabled)\n" "\n" +#endif +#if (PROCESSES_HAVE_FDS == 1) " with-files\n" " without-files enable / disable reporting files, sockets, pipes\n" " (default is enabled)\n" "\n" +#endif +#if (PROCESSES_HAVE_UID == 1) || (PROCESSES_HAVE_SID == 1) " without-users disable reporting per user charts\n" "\n" +#endif +#if (PROCESSES_HAVE_GID == 1) " without-groups disable reporting per user group charts\n" "\n" +#endif " with-detailed-uptime enable reporting min/avg/max uptime charts\n" "\n" -#if !defined(__FreeBSD__) && !defined(__APPLE__) +#if defined(OS_LINUX) " fds-cache-secs N cache the files of processed for N seconds\n" " caching is adaptive per file (when a file\n" " is found, it starts at 0 and while the file\n" @@ -852,15 +567,17 @@ static void parse_args(int argc, char **argv) " version or -v or -V print program version and exit\n" "\n" , NETDATA_VERSION -#if !defined(__FreeBSD__) && !defined(__APPLE__) +#if defined(OS_LINUX) , max_fds_cache_seconds #endif ); - exit(1); + exit(0); } +#if !defined(OS_WINDOWS) || !defined(RUN_UNDER_CLION) netdata_log_error("Cannot understand option %s", argv[i]); exit(1); +#endif } if(freq > 0) update_every = freq; @@ -879,7 +596,8 @@ static void parse_args(int argc, char **argv) netdata_log_info("Loaded config file '%s/apps_groups.conf'", user_config_dir); } -static int am_i_running_as_root() { +#if !defined(OS_WINDOWS) +static inline int am_i_running_as_root() { uid_t uid = getuid(), euid = geteuid(); if(uid == 0 || euid == 0) { @@ -892,7 +610,7 @@ static int am_i_running_as_root() { } #ifdef HAVE_SYS_CAPABILITY_H -static int check_capabilities() { +static inline int check_capabilities() { cap_t caps = cap_get_proc(); if(!caps) { netdata_log_error("Cannot get current capabilities."); @@ -936,27 +654,17 @@ static int check_capabilities() { return ret; } #else -static int check_capabilities() { +static inline int check_capabilities() { return 0; } #endif +#endif -static netdata_mutex_t apps_and_stdout_mutex = NETDATA_MUTEX_INITIALIZER; - -struct target *find_target_by_name(struct target *base, const char *name) { - struct target *t; - for(t = base; t ; t = t->next) { - if (strcmp(t->name, name) == 0) - return t; - } - - return NULL; -} +netdata_mutex_t apps_and_stdout_mutex = NETDATA_MUTEX_INITIALIZER; static bool apps_plugin_exit = false; int main(int argc, char **argv) { - clocks_init(); nd_log_initialize_for_external_plugins("apps.plugin"); pagesize = (size_t)sysconf(_SC_PAGESIZE); @@ -999,48 +707,46 @@ int main(int argc, char **argv) { } #endif /* NETDATA_INTERNAL_CHECKS */ - procfile_adaptive_initial_allocation = 1; - - os_get_system_HZ(); -#if defined(__FreeBSD__) - time_factor = 1000000ULL / RATES_DETAIL; // FreeBSD uses usecs -#endif -#if defined(__APPLE__) - mach_timebase_info(&mach_info); - time_factor = 1000000ULL / RATES_DETAIL; -#endif -#if !defined(__FreeBSD__) && !defined(__APPLE__) - time_factor = system_hz; // Linux uses clock ticks -#endif - - os_get_system_pid_max(); + procfile_set_adaptive_allocation(true, 0, 0, 0); os_get_system_cpus_uncached(); - + apps_managers_and_aggregators_init(); // before parsing args! parse_args(argc, argv); +#if !defined(OS_WINDOWS) if(!check_capabilities() && !am_i_running_as_root() && !check_proc_1_io()) { uid_t uid = getuid(), euid = geteuid(); #ifdef HAVE_SYS_CAPABILITY_H netdata_log_error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. " - "Without these, apps.plugin cannot report disk I/O utilization of other processes. " - "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; " - "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; " - , uid, euid, argv[0], argv[0], argv[0] - ); + "Without these, apps.plugin cannot report disk I/O utilization of other processes. " + "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; " + "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; " + , uid, euid, argv[0], argv[0], argv[0]); #else netdata_log_error("apps.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. " - "Without these, apps.plugin cannot report disk I/O utilization of other processes. " - "Your system does not support capabilities. " - "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; " - , uid, euid, argv[0], argv[0] - ); + "Without these, apps.plugin cannot report disk I/O utilization of other processes. " + "Your system does not support capabilities. " + "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; " + , uid, euid, argv[0], argv[0]); #endif } +#endif netdata_log_info("started on pid %d", getpid()); - users_and_groups_init(); - pids_init(); +#if (PROCESSES_HAVE_UID == 1) + cached_usernames_init(); +#endif + +#if (PROCESSES_HAVE_GID == 1) + cached_groupnames_init(); +#endif + +#if (PROCESSES_HAVE_SID == 1) + cached_sid_username_init(); +#endif + + apps_pids_init(); + OS_FUNCTION(apps_os_init)(); // ------------------------------------------------------------------------ // the event loop for functions @@ -1055,22 +761,22 @@ int main(int argc, char **argv) { netdata_mutex_lock(&apps_and_stdout_mutex); APPS_PLUGIN_GLOBAL_FUNCTIONS(); - usec_t step = update_every * USEC_PER_SEC; global_iterations_counter = 1; heartbeat_t hb; - heartbeat_init(&hb); + heartbeat_init(&hb, update_every * USEC_PER_SEC); for(; !apps_plugin_exit ; global_iterations_counter++) { netdata_mutex_unlock(&apps_and_stdout_mutex); -#ifdef NETDATA_PROFILING -#warning "compiling for profiling" - static int profiling_count=0; - profiling_count++; - if(unlikely(profiling_count > 2000)) exit(0); - usec_t dt = update_every * USEC_PER_SEC; -#else - usec_t dt = heartbeat_next(&hb, step); -#endif + usec_t dt; + if(profile_speed) { + static int profiling_count=0; + profiling_count++; + if(unlikely(profiling_count > 500)) exit(0); + dt = update_every * USEC_PER_SEC; + } + else + dt = heartbeat_next(&hb); + netdata_mutex_lock(&apps_and_stdout_mutex); struct pollfd pollfd = { .fd = fileno(stdout), .events = POLLERR }; @@ -1083,9 +789,6 @@ int main(int argc, char **argv) { fatal("Received error on read pipe."); } - if(global_iterations_counter % 10 == 0) - get_MemTotal(); - if(!collect_data_for_all_pids()) { netdata_log_error("Cannot collect /proc data for running processes. Disabling apps.plugin..."); printf("DISABLE\n"); @@ -1093,29 +796,50 @@ int main(int argc, char **argv) { exit(1); } - calculate_netdata_statistics(); + aggregate_processes_to_targets(); + +#if (ALL_PIDS_ARE_READ_INSTANTLY == 0) + OS_FUNCTION(apps_os_read_global_cpu_utilization)(); normalize_utilization(apps_groups_root_target); +#endif + + if(unlikely(print_tree_and_exit)) { + print_hierarchy(root_of_pids()); + exit(0); + } if(send_resource_usage) send_resource_usage_to_netdata(dt); +#if (PROCESSES_HAVE_STATE == 1) send_proc_states_count(dt); - send_charts_updates_to_netdata(apps_groups_root_target, "app", "app_group", "Apps"); +#endif + + send_charts_updates_to_netdata(apps_groups_root_target, "app", "app_group", "Applications Groups"); send_collected_data_to_netdata(apps_groups_root_target, "app", dt); +#if (PROCESSES_HAVE_UID == 1) if (enable_users_charts) { - send_charts_updates_to_netdata(users_root_target, "user", "user", "Users"); + send_charts_updates_to_netdata(users_root_target, "user", "user", "User Processes"); send_collected_data_to_netdata(users_root_target, "user", dt); } +#endif +#if (PROCESSES_HAVE_GID == 1) if (enable_groups_charts) { - send_charts_updates_to_netdata(groups_root_target, "usergroup", "user_group", "User Groups"); + send_charts_updates_to_netdata(groups_root_target, "usergroup", "user_group", "User Group Processes"); send_collected_data_to_netdata(groups_root_target, "usergroup", dt); } +#endif - fflush(stdout); +#if (PROCESSES_HAVE_SID == 1) + if (enable_users_charts) { + send_charts_updates_to_netdata(sids_root_target, "user", "user", "User Processes"); + send_collected_data_to_netdata(sids_root_target, "user", dt); + } +#endif - show_guest_time_old = show_guest_time; + fflush(stdout); debug_log("done Loop No %zu", global_iterations_counter); } |