@cryptotaxi247 / netdata-1 / commits / 8e5c1eaaf

yet another rewrite of apps.plugin to fix cpu spikes on slow systems; fixes #644

Costa Tsaousis (ktsaou) committed Jul 8, 2016 at 02:41 UTC 8e5c1eaafce5f7c4f6c270c3b29c2ada0e9cd9b1
1 file changed +667 -513
src/apps_plugin.c
+667 -513
@@ -48,12 +48,14 @@ pid_t pid_max = 32768;
48 int debug = 0;
49
50 int update_every = 1;
51 +unsigned long long global_iterations_counter = 1;
52 unsigned long long file_counter = 0;
53 int proc_pid_cmdline_is_needed = 0;
54 int include_exited_childs = 1;
55 char *host_prefix = "";
56 char *config_dir = CONFIG_DIR;
57
58 +pid_t *all_pids_sortlist = NULL;
59
60 // ----------------------------------------------------------------------------
61
@@ -146,15 +148,6 @@ struct target {
148 unsigned long long num_threads;
149 unsigned long long rss;
150
149 - long long fix_minflt;
150 - long long fix_cminflt;
151 - long long fix_majflt;
152 - long long fix_cmajflt;
153 - long long fix_utime;
154 - long long fix_stime;
155 - long long fix_cutime;
156 - long long fix_cstime;
157 -
151 unsigned long long statm_size;
152 unsigned long long statm_resident;
153 unsigned long long statm_share;
@@ -171,14 +164,6 @@ struct target {
164 unsigned long long io_storage_bytes_written;
165 unsigned long long io_cancelled_write_bytes;
166
174 - unsigned long long fix_io_logical_bytes_read;
175 - unsigned long long fix_io_logical_bytes_written;
176 - unsigned long long fix_io_read_calls;
177 - unsigned long long fix_io_write_calls;
178 - unsigned long long fix_io_storage_bytes_read;
179 - unsigned long long fix_io_storage_bytes_written;
180 - unsigned long long fix_io_cancelled_write_bytes;
181 -
167 int *fds;
168 unsigned long long openfiles;
169 unsigned long long openpipes;
@@ -459,6 +444,18 @@ struct pid_stat {
444 // int32_t tty_nr;
445 // int32_t tpgid;
446 // uint64_t flags;
447 +
448 + // these are raw values collected
449 + unsigned long long minflt_raw;
450 + unsigned long long cminflt_raw;
451 + unsigned long long majflt_raw;
452 + unsigned long long cmajflt_raw;
453 + unsigned long long utime_raw;
454 + unsigned long long stime_raw;
455 + unsigned long long cutime_raw;
456 + unsigned long long cstime_raw;
457 +
458 + // these are rates
459 unsigned long long minflt;
460 unsigned long long cminflt;
461 unsigned long long majflt;
@@ -467,6 +464,7 @@ struct pid_stat {
464 unsigned long long stime;
465 unsigned long long cutime;
466 unsigned long long cstime;
467 +
468 // int64_t priority;
469 // int64_t nice;
470 int32_t num_threads;
@@ -506,6 +504,14 @@ struct pid_stat {
504 unsigned long long statm_data;
505 unsigned long long statm_dirty;
506
507 + unsigned long long io_logical_bytes_read_raw;
508 + unsigned long long io_logical_bytes_written_raw;
509 + unsigned long long io_read_calls_raw;
510 + unsigned long long io_write_calls_raw;
511 + unsigned long long io_storage_bytes_read_raw;
512 + unsigned long long io_storage_bytes_written_raw;
513 + unsigned long long io_cancelled_write_bytes_raw;
514 +
515 unsigned long long io_logical_bytes_read;
516 unsigned long long io_logical_bytes_written;
517 unsigned long long io_read_calls;
@@ -514,61 +520,42 @@ struct pid_stat {
520 unsigned long long io_storage_bytes_written;
521 unsigned long long io_cancelled_write_bytes;
522
517 - // we need the last values
518 - // for all incremental counters
519 - // so that when a process switches users/groups
520 - // we will subtract these values from the old
521 - // target
522 - unsigned long long last_minflt;
523 - unsigned long long last_majflt;
524 - unsigned long long last_utime;
525 - unsigned long long last_stime;
526 -
527 - unsigned long long last_cminflt;
528 - unsigned long long last_cmajflt;
529 - unsigned long long last_cutime;
530 - unsigned long long last_cstime;
531 -
532 - unsigned long long last_fix_cminflt;
533 - unsigned long long last_fix_cmajflt;
534 - unsigned long long last_fix_cutime;
535 - unsigned long long last_fix_cstime;
536 -
537 - unsigned long long last_io_logical_bytes_read;
538 - unsigned long long last_io_logical_bytes_written;
539 - unsigned long long last_io_read_calls;
540 - unsigned long long last_io_write_calls;
541 - unsigned long long last_io_storage_bytes_read;
542 - unsigned long long last_io_storage_bytes_written;
543 - unsigned long long last_io_cancelled_write_bytes;
544 -
545 - unsigned long long fix_cminflt;
546 - unsigned long long fix_cmajflt;
547 - unsigned long long fix_cutime;
548 - unsigned long long fix_cstime;
549 -
523 int *fds; // array of fds it uses
524 int fds_size; // the size of the fds array
525
526 int children_count; // number of processes directly referencing this
554 - int updated; // 1 when update
527 + int keep; // 1 when we need to keep this process in memory even after it exited
528 + int keeploops; // increases by 1 every time keep is 1 and updated 0
529 + int updated; // 1 when the process is currently running
530 int merged; // 1 when it has been merged to its parent
556 - int new_entry;
531 + int new_entry; // 1 when this is a new process, just saw for the first time
532 + int read; // 1 when we have already read this process for this iteration
533 + int sortlist; // higher numbers = top on the process tree
534 + // each process gets a unique number
535
536 struct target *target; // app_groups.conf targets
537 struct target *user_target; // uid based targets
538 struct target *group_target; // gid based targets
539
540 + unsigned long long stat_collected_usec;
541 + unsigned long long last_stat_collected_usec;
542 +
543 + unsigned long long io_collected_usec;
544 + unsigned long long last_io_collected_usec;
545 +
546 + char *stat_filename;
547 + char *statm_filename;
548 + char *io_filename;
549 + char *cmdline_filename;
550 +
551 struct pid_stat *parent;
552 struct pid_stat *prev;
553 struct pid_stat *next;
565 -
554 } *root_of_pids = NULL, **all_pids;
555
556 long all_pids_count = 0;
557
570 -struct pid_stat *get_pid_entry(pid_t pid)
571 -{
558 +struct pid_stat *get_pid_entry(pid_t pid) {
559 if(all_pids[pid]) {
560 all_pids[pid]->new_entry = 0;
561 return all_pids[pid];
@@ -592,12 +579,16 @@ struct pid_stat *get_pid_entry(pid_t pid)
579 all_pids[pid]->pid = pid;
580 all_pids[pid]->new_entry = 1;
581
582 + all_pids_count++;
583 +
584 return all_pids[pid];
585 }
586
598 -void del_pid_entry(pid_t pid)
599 -{
600 - if(!all_pids[pid]) return;
587 +void del_pid_entry(pid_t pid) {
588 + if(!all_pids[pid]) {
589 + error("attempted to free pid %d that is not allocated.", pid);
590 + return;
591 + }
592
593 if(unlikely(debug))
594 fprintf(stderr, "apps.plugin: process %d %s exited, deleting it.\n", pid, all_pids[pid]->comm);
@@ -607,8 +598,14 @@ void del_pid_entry(pid_t pid)
598 if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
599
600 if(all_pids[pid]->fds) free(all_pids[pid]->fds);
601 + if(all_pids[pid]->stat_filename) free(all_pids[pid]->stat_filename);
602 + if(all_pids[pid]->statm_filename) free(all_pids[pid]->statm_filename);
603 + if(all_pids[pid]->io_filename) free(all_pids[pid]->io_filename);
604 + if(all_pids[pid]->cmdline_filename) free(all_pids[pid]->cmdline_filename);
605 free(all_pids[pid]);
606 +
607 all_pids[pid] = NULL;
608 + all_pids_count--;
609 }
610
611
@@ -616,42 +613,51 @@ void del_pid_entry(pid_t pid)
613 // update pids from proc
614
615 int read_proc_pid_cmdline(struct pid_stat *p) {
619 - char filename[FILENAME_MAX + 1];
620 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
616 +
617 + if(unlikely(!p->cmdline_filename)) {
618 + char filename[FILENAME_MAX + 1];
619 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
620 + if(!(p->cmdline_filename = strdup(filename)))
621 + fatal("Cannot allocate memory for filename '%s'", filename);
622 + }
623
622 - int fd = open(filename, O_RDONLY, 0666);
623 - if(unlikely(fd == -1)) return 1;
624 + int fd = open(p->cmdline_filename, O_RDONLY, 0666);
625 + if(unlikely(fd == -1)) goto cleanup;
626
627 int i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
628 close(fd);
629
628 - if(bytes <= 0) {
629 - // copy the command to the command line
630 - strncpyz(p->cmdline, p->comm, MAX_CMDLINE);
631 - return 0;
632 - }
630 + if(unlikely(bytes <= 0)) goto cleanup;
631
632 p->cmdline[bytes] = '\0';
633 for(i = 0; i < bytes ; i++)
636 - if(!p->cmdline[i]) p->cmdline[i] = ' ';
634 + if(unlikely(!p->cmdline[i])) p->cmdline[i] = ' ';
635
636 if(unlikely(debug))
639 - fprintf(stderr, "Read file '%s' contents: %s\n", filename, p->cmdline);
637 + fprintf(stderr, "Read file '%s' contents: %s\n", p->cmdline_filename, p->cmdline);
638 +
639 + return 0;
640
641 +cleanup:
642 + // copy the command to the command line
643 + strncpyz(p->cmdline, p->comm, MAX_CMDLINE);
644 return 0;
645 }
646
647 int read_proc_pid_ownership(struct pid_stat *p) {
645 - char filename[FILENAME_MAX + 1];
646 -
647 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d", host_prefix, p->pid);
648 + if(unlikely(!p->stat_filename)) {
649 + error("pid %d does not have a stat_filename", p->pid);
650 + return 1;
651 + }
652
653 // ----------------------------------------
654 // read uid and gid
655
656 struct stat st;
653 - if(stat(filename, &st) != 0)
657 + if(stat(p->stat_filename, &st) != 0) {
658 + error("Cannot stat file '%s'", p->stat_filename);
659 return 1;
660 + }
661
662 p->uid = st.st_uid;
663 p->gid = st.st_gid;
@@ -662,26 +668,26 @@ int read_proc_pid_ownership(struct pid_stat *p) {
668 int read_proc_pid_stat(struct pid_stat *p) {
669 static procfile *ff = NULL;
670
665 - char filename[FILENAME_MAX + 1];
666 -
667 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
668 -
669 - // ----------------------------------------
671 + if(unlikely(!p->stat_filename)) {
672 + char filename[FILENAME_MAX + 1];
673 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
674 + if(!(p->stat_filename = strdup(filename)))
675 + fatal("Cannot allocate memory for filename '%s'", filename);
676 + }
677
678 int set_quotes = (!ff)?1:0;
679
673 - ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
674 - if(!ff) return 1;
680 + ff = procfile_reopen(ff, p->stat_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
681 + if(unlikely(!ff)) goto cleanup;
682
683 // if(set_quotes) procfile_set_quotes(ff, "()");
684 if(set_quotes) procfile_set_open_close(ff, "(", ")");
685
686 ff = procfile_readall(ff);
680 - if(!ff) {
681 - // procfile_close(ff);
682 - return 1;
683 - }
687 + if(unlikely(!ff)) goto cleanup;
688
689 + p->last_stat_collected_usec = p->stat_collected_usec;
690 + p->stat_collected_usec = timems();
691 file_counter++;
692
693 // parse the process name
@@ -697,14 +703,41 @@ int read_proc_pid_stat(struct pid_stat *p) {
703 // p->tty_nr = atol(procfile_lineword(ff, 0, 6+i));
704 // p->tpgid = atol(procfile_lineword(ff, 0, 7+i));
705 // p->flags = strtoull(procfile_lineword(ff, 0, 8+i), NULL, 10);
700 - p->minflt = strtoull(procfile_lineword(ff, 0, 9+i), NULL, 10);
701 - p->cminflt = strtoull(procfile_lineword(ff, 0, 10+i), NULL, 10);
702 - p->majflt = strtoull(procfile_lineword(ff, 0, 11+i), NULL, 10);
703 - p->cmajflt = strtoull(procfile_lineword(ff, 0, 12+i), NULL, 10);
704 - p->utime = strtoull(procfile_lineword(ff, 0, 13+i), NULL, 10);
705 - p->stime = strtoull(procfile_lineword(ff, 0, 14+i), NULL, 10);
706 - p->cutime = strtoull(procfile_lineword(ff, 0, 15+i), NULL, 10);
707 - p->cstime = strtoull(procfile_lineword(ff, 0, 16+i), NULL, 10);
706 +
707 + unsigned long long last;
708 +
709 + last = p->minflt_raw;
710 + p->minflt_raw = strtoull(procfile_lineword(ff, 0, 9+i), NULL, 10);
711 + p->minflt = (p->minflt_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
712 +
713 + last = p->cminflt_raw;
714 + p->cminflt_raw = strtoull(procfile_lineword(ff, 0, 10+i), NULL, 10);
715 + p->cminflt = (p->cminflt_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
716 +
717 + last = p->majflt_raw;
718 + p->majflt_raw = strtoull(procfile_lineword(ff, 0, 11+i), NULL, 10);
719 + p->majflt = (p->majflt_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
720 +
721 + last = p->cmajflt_raw;
722 + p->cmajflt_raw = strtoull(procfile_lineword(ff, 0, 12+i), NULL, 10);
723 + p->cmajflt = (p->cmajflt_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
724 +
725 + last = p->utime_raw;
726 + p->utime_raw = strtoull(procfile_lineword(ff, 0, 13+i), NULL, 10);
727 + p->utime = (p->utime_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
728 +
729 + last = p->stime_raw;
730 + p->stime_raw = strtoull(procfile_lineword(ff, 0, 14+i), NULL, 10);
731 + p->stime = (p->stime_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
732 +
733 + last = p->cutime_raw;
734 + p->cutime_raw = strtoull(procfile_lineword(ff, 0, 15+i), NULL, 10);
735 + p->cutime = (p->cutime_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
736 +
737 + last = p->cstime_raw;
738 + p->cstime_raw = strtoull(procfile_lineword(ff, 0, 16+i), NULL, 10);
739 + p->cstime = (p->cstime_raw - last) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
740 +
741 // p->priority = strtoull(procfile_lineword(ff, 0, 17+i), NULL, 10);
742 // p->nice = strtoull(procfile_lineword(ff, 0, 18+i), NULL, 10);
743 p->num_threads = (int32_t) atol(procfile_lineword(ff, 0, 19 + i));
@@ -734,27 +767,50 @@ int read_proc_pid_stat(struct pid_stat *p) {
767 // p->cguest_time = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
768
769 if(unlikely(debug || (p->target && p->target->debug)))
737 - fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
770 + fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' on target '%s' (dt=%llu) VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, (p->target)?p->target->name:"UNSET", p->stat_collected_usec - p->last_stat_collected_usec, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
771 +
772 + if(unlikely(global_iterations_counter == 1)) {
773 + p->minflt = 0;
774 + p->cminflt = 0;
775 + p->majflt = 0;
776 + p->cmajflt = 0;
777 + p->utime = 0;
778 + p->stime = 0;
779 + p->cutime = 0;
780 + p->cstime = 0;
781 + }
782
739 - // procfile_close(ff);
783 return 0;
784 +
785 +cleanup:
786 + p->minflt = 0;
787 + p->cminflt = 0;
788 + p->majflt = 0;
789 + p->cmajflt = 0;
790 + p->utime = 0;
791 + p->stime = 0;
792 + p->cutime = 0;
793 + p->cstime = 0;
794 + p->num_threads = 0;
795 + p->rss = 0;
796 + return 1;
797 }
798
799 int read_proc_pid_statm(struct pid_stat *p) {
800 static procfile *ff = NULL;
801
746 - char filename[FILENAME_MAX + 1];
747 -
748 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
802 + if(unlikely(!p->statm_filename)) {
803 + char filename[FILENAME_MAX + 1];
804 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
805 + if(!(p->statm_filename = strdup(filename)))
806 + fatal("Cannot allocate memory for filename '%s'", filename);
807 + }
808
750 - ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
751 - if(!ff) return 1;
809 + ff = procfile_reopen(ff, p->statm_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
810 + if(unlikely(!ff)) goto cleanup;
811
812 ff = procfile_readall(ff);
754 - if(!ff) {
755 - // procfile_close(ff);
756 - return 1;
757 - }
813 + if(unlikely(!ff)) goto cleanup;
814
815 file_counter++;
816
@@ -766,38 +822,92 @@ int read_proc_pid_statm(struct pid_stat *p) {
822 p->statm_data = strtoull(procfile_lineword(ff, 0, 5), NULL, 10);
823 p->statm_dirty = strtoull(procfile_lineword(ff, 0, 6), NULL, 10);
824
769 - // procfile_close(ff);
825 return 0;
826 +
827 +cleanup:
828 + p->statm_size = 0;
829 + p->statm_resident = 0;
830 + p->statm_share = 0;
831 + p->statm_text = 0;
832 + p->statm_lib = 0;
833 + p->statm_data = 0;
834 + p->statm_dirty = 0;
835 + return 1;
836 }
837
838 int read_proc_pid_io(struct pid_stat *p) {
839 static procfile *ff = NULL;
840
776 - char filename[FILENAME_MAX + 1];
777 -
778 - snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
841 + if(unlikely(!p->io_filename)) {
842 + char filename[FILENAME_MAX + 1];
843 + snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
844 + if(!(p->io_filename = strdup(filename)))
845 + fatal("Cannot allocate memory for filename '%s'", filename);
846 + }
847
780 - ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
781 - if(!ff) return 1;
848 + // open the file
849 + ff = procfile_reopen(ff, p->io_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
850 + if(unlikely(!ff)) goto cleanup;
851
852 ff = procfile_readall(ff);
784 - if(!ff) {
785 - // procfile_close(ff);
786 - return 1;
787 - }
853 + if(unlikely(!ff)) goto cleanup;
854
855 file_counter++;
856
791 - p->io_logical_bytes_read = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
792 - p->io_logical_bytes_written = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
793 - p->io_read_calls = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
794 - p->io_write_calls = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
795 - p->io_storage_bytes_read = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
796 - p->io_storage_bytes_written = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
797 - p->io_cancelled_write_bytes = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
857 + p->last_io_collected_usec = p->io_collected_usec;
858 + p->io_collected_usec = timems();
859 +
860 + unsigned long long last;
861 +
862 + last = p->io_logical_bytes_read_raw;
863 + p->io_logical_bytes_read_raw = strtoull(procfile_lineword(ff, 0, 1), NULL, 10);
864 + p->io_logical_bytes_read = (p->io_logical_bytes_read_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
865 +
866 + last = p->io_logical_bytes_written_raw;
867 + p->io_logical_bytes_written_raw = strtoull(procfile_lineword(ff, 1, 1), NULL, 10);
868 + p->io_logical_bytes_written = (p->io_logical_bytes_written_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
869 +
870 + last = p->io_read_calls_raw;
871 + p->io_read_calls_raw = strtoull(procfile_lineword(ff, 2, 1), NULL, 10);
872 + p->io_read_calls = (p->io_read_calls_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
873 +
874 + last = p->io_write_calls_raw;
875 + p->io_write_calls_raw = strtoull(procfile_lineword(ff, 3, 1), NULL, 10);
876 + p->io_write_calls = (p->io_write_calls_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
877 +
878 + last = p->io_storage_bytes_read_raw;
879 + p->io_storage_bytes_read_raw = strtoull(procfile_lineword(ff, 4, 1), NULL, 10);
880 + p->io_storage_bytes_read = (p->io_storage_bytes_read_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
881 +
882 + last = p->io_storage_bytes_written_raw;
883 + p->io_storage_bytes_written_raw = strtoull(procfile_lineword(ff, 5, 1), NULL, 10);
884 + p->io_storage_bytes_written = (p->io_storage_bytes_written_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
885 +
886 + last = p->io_cancelled_write_bytes_raw;
887 + p->io_cancelled_write_bytes_raw = strtoull(procfile_lineword(ff, 6, 1), NULL, 10);
888 + p->io_cancelled_write_bytes = (p->io_cancelled_write_bytes_raw - last) * (update_every * 1000000 * 100) / (p->io_collected_usec - p->last_io_collected_usec);
889 +
890 + if(unlikely(global_iterations_counter == 1)) {
891 + p->io_logical_bytes_read = 0;
892 + p->io_logical_bytes_written = 0;
893 + p->io_read_calls = 0;
894 + p->io_write_calls = 0;
895 + p->io_storage_bytes_read = 0;
896 + p->io_storage_bytes_written = 0;
897 + p->io_cancelled_write_bytes = 0;
898 + }
899
799 - // procfile_close(ff);
900 return 0;
901 +
902 +cleanup:
903 + p->io_logical_bytes_read = 0;
904 + p->io_logical_bytes_written = 0;
905 + p->io_read_calls = 0;
906 + p->io_write_calls = 0;
907 + p->io_storage_bytes_read = 0;
908 + p->io_storage_bytes_written = 0;
909 + p->io_cancelled_write_bytes = 0;
910 + return 1;
911 }
912
913
@@ -1120,6 +1230,173 @@ int read_pid_file_descriptors(struct pid_stat *p) {
1230
1231 // ----------------------------------------------------------------------------
1232
1233 +#ifdef NETDATA_INTERNAL_CHECKS
1234 +void find_lost_child_debug(struct pid_stat *pe, struct pid_stat *ppe, unsigned long long lost, int type) {
1235 + int found = 0;
1236 + struct pid_stat *p = NULL, *pp = pe->parent;
1237 +
1238 + log_date(stderr);
1239 + fprintf(stderr, "Searching for candidate of lost resources of process %d (%s, %s) which is aggregated on %d (%s, %s)\n", pe->pid, pe->comm, pe->updated?"running":"exited", ppe->pid, ppe->comm, ppe->updated?"running":"exited");
1240 + while(pp) {
1241 + fprintf(stderr, " >> parent %d (%s, %s)\n", pp->pid, pp->comm, pp->updated?"running":"exited");
1242 + pp = pp->parent;
1243 + }
1244 +
1245 + for(p = root_of_pids; p ; p = p->next) {
1246 + if(p == pe) continue;
1247 +
1248 + switch(type) {
1249 + case 1:
1250 + if(p->cminflt > lost) {
1251 + fprintf(stderr, " > process %d (%s) could use the lost exited child minflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1252 + found++;
1253 + }
1254 + break;
1255 +
1256 + case 2:
1257 + if(p->cmajflt > lost) {
1258 + fprintf(stderr, " > process %d (%s) could use the lost exited child majflt %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1259 + found++;
1260 + }
1261 + break;
1262 +
1263 + case 3:
1264 + if(p->cutime > lost) {
1265 + fprintf(stderr, " > process %d (%s) could use the lost exited child utime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1266 + found++;
1267 + }
1268 + break;
1269 +
1270 + case 4:
1271 + if(p->cstime > lost) {
1272 + fprintf(stderr, " > process %d (%s) could use the lost exited child stime %llu of process %d (%s)\n", p->pid, p->comm, lost, pe->pid, pe->comm);
1273 + found++;
1274 + }
1275 + break;
1276 + }
1277 + }
1278 +
1279 + if(!found) {
1280 + switch(type) {
1281 + case 1:
1282 + fprintf(stderr, " > cannot find any process to use the lost exited child minflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1283 + break;
1284 +
1285 + case 2:
1286 + fprintf(stderr, " > cannot find any process to use the lost exited child majflt %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1287 + break;
1288 +
1289 + case 3:
1290 + fprintf(stderr, " > cannot find any process to use the lost exited child utime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1291 + break;
1292 +
1293 + case 4:
1294 + fprintf(stderr, " > cannot find any process to use the lost exited child stime %llu of process %d (%s)\n", lost, pe->pid, pe->comm);
1295 + break;
1296 + }
1297 + }
1298 +}
1299 +#endif /* NETDATA_INTERNAL_CHECKS */
1300 +
1301 +void remove_exited_child_from_parent(unsigned long long *field, unsigned long long *pfield, unsigned long long *ifield, struct pid_stat *pe, struct pid_stat *ppe, int type) {
1302 + if(pfield) {
1303 + if(*field > *pfield) {
1304 + *field -= *pfield;
1305 + *pfield = 0;
1306 + }
1307 + else {
1308 + *pfield -= *field;
1309 + *field = 0;
1310 + }
1311 + }
1312 +
1313 + if(*field) {
1314 + if(ifield && ifield != pfield) {
1315 + if(*field > *ifield) {
1316 + *field -= *ifield;
1317 + *ifield = 0;
1318 + }
1319 + else {
1320 + *ifield -= *field;
1321 + *field = 0;
1322 + }
1323 + }
1324 + }
1325 +
1326 + if(*field) {
1327 +#ifdef NETDATA_INTERNAL_CHECKS
1328 + find_lost_child_debug(pe, ppe, *field, type);
1329 +#endif
1330 + while(pe && !pe->updated) {
1331 + pe->keep = 1;
1332 + pe = pe->parent;
1333 + }
1334 + }
1335 +}
1336 +
1337 +void process_exited_processes() {
1338 + struct pid_stat *init = all_pids[1];
1339 + struct pid_stat *p;
1340 +
1341 + for(p = root_of_pids; p ; p = p->next) {
1342 + if(p->updated || !p->stat_collected_usec) continue;
1343 +
1344 + struct pid_stat *pp = p->parent;
1345 +
1346 + // find the first parent that is running
1347 + while(pp && !pp->updated)
1348 + pp = pp->parent;
1349 +
1350 + unsigned long long rate;
1351 +
1352 + rate = (p->utime_raw + p->cutime_raw) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
1353 + remove_exited_child_from_parent(&rate, (pp)?&pp->cutime:NULL, (init)?&init->cutime:NULL, p, pp, 3);
1354 + p->cutime_raw = 0;
1355 + p->utime_raw = rate * (p->stat_collected_usec - p->last_stat_collected_usec) / (update_every * 1000000 * 100);
1356 +
1357 + rate = (p->stime_raw + p->cstime_raw) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
1358 + remove_exited_child_from_parent(&rate, (pp)?&pp->cstime:NULL, (init)?&init->cstime:NULL, p, pp, 4);
1359 + p->cstime_raw = 0;
1360 + p->stime_raw = rate * (p->stat_collected_usec - p->last_stat_collected_usec) / (update_every * 1000000 * 100);
1361 +
1362 + rate = (p->minflt_raw + p->cminflt_raw) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
1363 + remove_exited_child_from_parent(&rate, (pp)?&pp->cminflt:NULL, (init)?&init->cminflt:NULL, p, pp, 1);
1364 + p->cminflt_raw = 0;
1365 + p->minflt_raw = rate * (p->stat_collected_usec - p->last_stat_collected_usec) / (update_every * 1000000 * 100);
1366 +
1367 + rate = (p->majflt_raw + p->cmajflt_raw) * (update_every * 1000000 * 100) / (p->stat_collected_usec - p->last_stat_collected_usec);
1368 + remove_exited_child_from_parent(&rate, (pp)?&pp->cmajflt:NULL, (init)?&init->cmajflt:NULL, p, pp, 2);
1369 + p->cmajflt_raw = 0;
1370 + p->majflt_raw = rate * (p->stat_collected_usec - p->last_stat_collected_usec) / (update_every * 1000000 * 100);
1371 + }
1372 +}
1373 +
1374 +void link_all_processes_to_their_parents(void) {
1375 + struct pid_stat *p = NULL;
1376 +
1377 + // link all children to their parents
1378 + // and update children count on parents
1379 + for(p = root_of_pids; p ; p = p->next) {
1380 + // for each process found running
1381 +
1382 + if(likely(p->ppid > 0 && all_pids[p->ppid])) {
1383 + // valid parent processes
1384 +
1385 + struct pid_stat *pp;
1386 +
1387 + p->parent = pp = all_pids[p->ppid];
1388 + p->parent->children_count++;
1389 +
1390 + if(unlikely(debug || (p->target && p->target->debug)))
1391 + fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) on target '%s' has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", (p->target)?p->target->name:"UNSET", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cminflt, pp->cmajflt);
1392 + }
1393 + else if(unlikely(p->ppid != 0))
1394 + error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1395 + }
1396 +}
1397 +
1398 +// ----------------------------------------------------------------------------
1399 +
1400 // 1. read all files in /proc
1401 // 2. for each numeric directory:
1402 // i. read /proc/pid/stat
@@ -1136,173 +1413,186 @@ int read_pid_file_descriptors(struct pid_stat *p) {
1413 // to avoid filling up all disk space
1414 // if debug is enabled, all errors are printed
1415
1139 -int collect_data_for_all_processes_from_proc(void)
1140 -{
1141 - char dirname[FILENAME_MAX + 1];
1416 +static int compar_pid(const void *pid1, const void *pid2) {
1417
1143 - snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
1144 - DIR *dir = opendir(dirname);
1145 - if(!dir) return 0;
1418 + struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
1419 + struct pid_stat *p2 = all_pids[*((pid_t *)pid2)];
1420
1147 - struct dirent *file = NULL;
1148 - struct pid_stat *p = NULL;
1149 -
1150 - // mark them all as un-updated
1151 - all_pids_count = 0;
1152 - for(p = root_of_pids; p ; p = p->next) {
1153 - all_pids_count++;
1421 + if(p1->sortlist > p2->sortlist)
1422 + return -1;
1423 + else
1424 + return 1;
1425 +}
1426
1155 - p->parent = NULL;
1427 +void collect_data_for_pid(pid_t pid) {
1428 + if(unlikely(pid <= 0 || pid > pid_max)) {
1429 + error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
1430 + return;
1431 + }
1432
1157 - p->updated = 0;
1158 - p->children_count = 0;
1159 - p->merged = 0;
1160 - p->new_entry = 0;
1433 + struct pid_stat *p = get_pid_entry(pid);
1434 + if(unlikely(!p || p->read)) return;
1435
1162 - p->last_minflt = p->minflt;
1163 - p->last_majflt = p->majflt;
1164 - p->last_utime = p->utime;
1165 - p->last_stime = p->stime;
1436 + // fprintf(stderr, "Reading process %d (%s), sortlist %d\n", p->pid, p->comm, p->sortlist);
1437
1167 - p->last_cminflt = p->cminflt;
1168 - p->last_cmajflt = p->cmajflt;
1169 - p->last_cutime = p->cutime;
1170 - p->last_cstime = p->cstime;
1438 + p->read = 1;
1439 + p->sortlist = 0;
1440
1172 - p->last_fix_cminflt = p->fix_cminflt;
1173 - p->last_fix_cmajflt = p->fix_cmajflt;
1174 - p->last_fix_cutime = p->fix_cutime;
1175 - p->last_fix_cstime = p->fix_cstime;
1441 + // --------------------------------------------------------------------
1442 + // /proc/<pid>/stat
1443
1177 - p->last_io_logical_bytes_read = p->io_logical_bytes_read;
1178 - p->last_io_logical_bytes_written = p->io_logical_bytes_written;
1179 - p->last_io_read_calls = p->io_read_calls;
1180 - p->last_io_write_calls = p->io_write_calls;
1181 - p->last_io_storage_bytes_read = p->io_storage_bytes_read;
1182 - p->last_io_storage_bytes_written = p->io_storage_bytes_written;
1183 - p->last_io_cancelled_write_bytes = p->io_cancelled_write_bytes;
1444 + if(unlikely(read_proc_pid_stat(p))) {
1445 + error("Cannot process %s/proc/%d/stat", host_prefix, pid);
1446 + // there is no reason to proceed if we cannot get its status
1447 + return;
1448 }
1449
1186 - while((file = readdir(dir))) {
1187 - char *endptr = file->d_name;
1188 - pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1450 + read_proc_pid_ownership(p);
1451
1190 - // make sure we read a valid number
1191 - if(unlikely(endptr == file->d_name || *endptr != '\0'))
1192 - continue;
1452 + // check its parent pid
1453 + if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
1454 + error("Pid %d states invalid parent pid %d. Using 0.", pid, p->ppid);
1455 + p->ppid = 0;
1456 + }
1457
1194 - if(unlikely(pid <= 0 || pid > pid_max)) {
1195 - error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
1196 - continue;
1197 - }
1458 + // --------------------------------------------------------------------
1459 + // /proc/<pid>/io
1460
1199 - p = get_pid_entry(pid);
1200 - if(unlikely(!p)) continue;
1461 + if(unlikely(read_proc_pid_io(p)))
1462 + error("Cannot process %s/proc/%d/io", host_prefix, pid);
1463
1464 + // --------------------------------------------------------------------
1465 + // /proc/<pid>/statm
1466
1203 - // --------------------------------------------------------------------
1204 - // /proc/<pid>/stat
1467 + if(unlikely(read_proc_pid_statm(p))) {
1468 + error("Cannot process %s/proc/%d/statm", host_prefix, pid);
1469 + // there is no reason to proceed if we cannot get its memory status
1470 + return;
1471 + }
1472
1206 - if(unlikely(read_proc_pid_stat(p))) {
1207 - error("Cannot process %s/proc/%d/stat", host_prefix, pid);
1208 - // there is no reason to proceed if we cannot get its status
1209 - continue;
1210 - }
1473 + // --------------------------------------------------------------------
1474 + // link it
1475
1212 - // check its parent pid
1213 - if(unlikely(p->ppid < 0 || p->ppid > pid_max)) {
1214 - error("Pid %d states invalid parent pid %d. Using 0.", pid, p->ppid);
1215 - p->ppid = 0;
1476 + // check if it is target
1477 + // we do this only once, the first time this pid is loaded
1478 + if(unlikely(p->new_entry)) {
1479 + // /proc/<pid>/cmdline
1480 + if(likely(proc_pid_cmdline_is_needed)) {
1481 + if(unlikely(read_proc_pid_cmdline(p)))
1482 + error("Cannot process %s/proc/%d/cmdline", host_prefix, pid);
1483 }
1484
1218 - // --------------------------------------------------------------------
1219 - // /proc/<pid>/statm
1485 + if(unlikely(debug))
1486 + fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
1487 +
1488 + uint32_t hash = simple_hash(p->comm);
1489 + size_t pclen = strlen(p->comm);
1490 +
1491 + struct target *w;
1492 + for(w = apps_groups_root_target; w ; w = w->next) {
1493 + // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1494 +
1495 + // find it - 4 cases:
1496 + // 1. the target is not a pattern
1497 + // 2. the target has the prefix
1498 + // 3. the target has the suffix
1499 + // 4. the target is something inside cmdline
1500 + if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1501 + || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1502 + || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1503 + || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1504 + ) {
1505 + if(w->target) p->target = w->target;
1506 + else p->target = w;
1507
1221 - if(unlikely(read_proc_pid_statm(p))) {
1222 - error("Cannot process %s/proc/%d/statm", host_prefix, pid);
1223 - // there is no reason to proceed if we cannot get its memory status
1224 - continue;
1508 + if(debug || (p->target && p->target->debug))
1509 + fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1510 +
1511 + break;
1512 + }
1513 }
1514 + }
1515
1516 + // --------------------------------------------------------------------
1517 + // /proc/<pid>/fd
1518
1228 - // --------------------------------------------------------------------
1229 - // /proc/<pid>/io
1519 + if(unlikely(read_pid_file_descriptors(p))) {
1520 + error("Cannot process entries in %s/proc/%d/fd", host_prefix, pid);
1521 + }
1522
1231 - if(unlikely(read_proc_pid_io(p))) {
1232 - error("Cannot process %s/proc/%d/io", host_prefix, pid);
1523 + // --------------------------------------------------------------------
1524 + // done!
1525
1234 - // on systems without /proc/X/io
1235 - // allow proceeding without I/O information
1236 - // continue;
1237 - }
1526 + if(p->ppid && all_pids[p->ppid] && !all_pids[p->ppid]->read)
1527 + error("read process %d (%s), but its parent %d (%s) is not read\n", p->pid, p->comm, all_pids[p->ppid]->pid, all_pids[p->ppid]->comm);
1528
1239 - // --------------------------------------------------------------------
1240 - // <pid> ownership
1529 + // mark it as updated
1530 + p->updated = 1;
1531 + p->keep = 0;
1532 + p->keeploops = 0;
1533 +}
1534
1242 - if(unlikely(read_proc_pid_ownership(p))) {
1243 - error("Cannot stat %s/proc/%d", host_prefix, pid);
1535 +int collect_data_for_all_processes_from_proc(void) {
1536 + struct pid_stat *p = NULL;
1537 +
1538 + if(all_pids_count) {
1539 + // read parents before childs
1540 + // this is needed to prevent a situation where
1541 + // a child is found running, but until we read
1542 + // its parent, it has exited and its parent
1543 + // has accumulated its resources
1544 +
1545 + long slc = 0;
1546 + for(p = root_of_pids; p ; p = p->next) {
1547 + p->read = 0;
1548 + p->updated = 0;
1549 + p->new_entry = 0;
1550 + p->merged = 0;
1551 + p->children_count = 0;
1552 + p->parent = NULL;
1553 +
1554 +#ifdef NETDATA_INTERNAL_CHECKS
1555 + if(unlikely(slc >= all_pids_count))
1556 + error("Internal error: I was thinking I had %ld processes in my arrays, but it seems there are more.", all_pids_count);
1557 +#endif
1558 + all_pids_sortlist[slc++] = p->pid;
1559 }
1560
1246 - // --------------------------------------------------------------------
1247 - // link it
1248 -
1249 - // check if it is target
1250 - // we do this only once, the first time this pid is loaded
1251 - if(unlikely(p->new_entry)) {
1252 - // /proc/<pid>/cmdline
1253 - if(proc_pid_cmdline_is_needed) {
1254 - if(unlikely(read_proc_pid_cmdline(p))) {
1255 - error("Cannot process %s/proc/%d/cmdline", host_prefix, pid);
1256 - }
1257 - }
1561 + qsort((void *)all_pids_sortlist, all_pids_count, sizeof(pid_t), compar_pid);
1562
1259 - if(unlikely(debug))
1260 - fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
1261 -
1262 - uint32_t hash = simple_hash(p->comm);
1263 - size_t pclen = strlen(p->comm);
1264 -
1265 - struct target *w;
1266 - for(w = apps_groups_root_target; w ; w = w->next) {
1267 - // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1268 -
1269 - // find it - 4 cases:
1270 - // 1. the target is not a pattern
1271 - // 2. the target has the prefix
1272 - // 3. the target has the suffix
1273 - // 4. the target is something inside cmdline
1274 - if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1275 - || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1276 - || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1277 - || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1278 - ) {
1279 - if(w->target) p->target = w->target;
1280 - else p->target = w;
1563 + for(slc = 0; slc < all_pids_count; slc++)
1564 + collect_data_for_pid(all_pids_sortlist[slc]);
1565 + }
1566
1282 - if(debug || (p->target && p->target->debug))
1283 - fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1567 + char dirname[FILENAME_MAX + 1];
1568
1285 - break;
1286 - }
1287 - }
1288 - }
1569 + snprintfz(dirname, FILENAME_MAX, "%s/proc", host_prefix);
1570 + DIR *dir = opendir(dirname);
1571 + if(!dir) return 0;
1572
1290 - // --------------------------------------------------------------------
1291 - // /proc/<pid>/fd
1573 + struct dirent *file = NULL;
1574
1293 - if(unlikely(read_pid_file_descriptors(p))) {
1294 - error("Cannot process entries in %s/proc/%d/fd", host_prefix, pid);
1295 - }
1575 + while((file = readdir(dir))) {
1576 + char *endptr = file->d_name;
1577 + pid_t pid = (pid_t) strtoul(file->d_name, &endptr, 10);
1578
1297 - // --------------------------------------------------------------------
1298 - // done!
1579 + // make sure we read a valid number
1580 + if(unlikely(endptr == file->d_name || *endptr != '\0'))
1581 + continue;
1582
1300 - // mark it as updated
1301 - p->updated = 1;
1583 + collect_data_for_pid(pid);
1584 }
1303 -
1585 closedir(dir);
1586
1587 + // normally this is done
1588 + // however we may have processes exited while we collected values
1589 + // so let's find the exited ones
1590 + // we do this by collecting the ownership of process
1591 + // if we manage to get the ownership, the process still runs
1592 +
1593 + link_all_processes_to_their_parents();
1594 + process_exited_processes();
1595 +
1596 return 1;
1597 }
1598
@@ -1322,128 +1612,19 @@ int collect_data_for_all_processes_from_proc(void)
1612 // 9. find the unique file count for each target
1613 // check: update_apps_groups_statistics()
1614
1325 -void link_all_processes_to_their_parents(void) {
1326 - struct pid_stat *init = all_pids[1];
1327 - struct pid_stat *p = NULL;
1328 -
1329 - // link all children to their parents
1330 - // and update children count on parents
1331 - for(p = root_of_pids; p ; p = p->next) {
1332 - // for each process found running
1333 -
1334 - if(likely(p->new_entry && p->updated)) {
1335 - // the first time we see an entry
1336 - // we remove the exited children figures
1337 - // to avoid spikes
1338 - p->fix_cminflt = p->cminflt;
1339 - p->fix_cmajflt = p->cmajflt;
1340 - p->fix_cutime = p->cutime;
1341 - p->fix_cstime = p->cstime;
1342 - }
1343 -
1344 - if(likely(p->ppid > 0 && all_pids[p->ppid])) {
1345 - // valid parent processes
1346 -
1347 - struct pid_stat *pp;
1348 -
1349 - p->parent = pp = all_pids[p->ppid];
1350 - p->parent->children_count++;
1351 -
1352 - if(unlikely(debug || (p->target && p->target->debug)))
1353 - fprintf(stderr, "apps.plugin: \tchild %d (%s, %s) has parent %d (%s, %s). Parent: utime=%llu, stime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu, fix_cutime=%llu, fix_cstime=%llu, fix_cminflt=%llu, fix_cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cminflt, pp->cmajflt, pp->fix_cutime, pp->fix_cstime, pp->fix_cminflt, pp->fix_cmajflt);
1354 -
1355 - if(unlikely(!p->updated)) {
1356 - // this process has exit
1357 -
1358 - // find the first parent that has been updated
1359 - while(pp && !pp->updated) {
1360 - // we may have to forward link it to its parent
1361 - if(unlikely(!pp->parent && pp->ppid > 0 && all_pids[pp->ppid]))
1362 - pp->parent = all_pids[pp->ppid];
1363 -
1364 - // check again for parent
1365 - pp = pp->parent;
1366 - }
1367 -
1368 - if(likely(pp)) {
1369 - // this is an exited child with a parent
1370 - // remove the known time from the parent's data
1371 - pp->fix_cminflt += p->last_minflt + p->last_cminflt + p->last_fix_cminflt;
1372 - pp->fix_cmajflt += p->last_majflt + p->last_cmajflt + p->last_fix_cmajflt;
1373 - pp->fix_cutime += p->last_utime + p->last_cutime + p->last_fix_cutime;
1374 - pp->fix_cstime += p->last_stime + p->last_cstime + p->last_fix_cstime;
1375 -
1376 - // The known exited children (the ones we track) may have
1377 - // contributed more than the value accumulated into the process
1378 - // by the kernel.
1379 - // This can happen if the parent process has not waited-for
1380 - // its children (check: man 2 times).
1381 - // In this case, the kernel adds these resources to init (pid 1).
1382 - //
1383 - // The following code, attempts to fix this.
1384 - // Without this code, the charts will have random spikes
1385 - // for example, when an SSH session ends (sshd forks a child
1386 - // to serve the session, but when this session ends, sshd
1387 - // does not wait-for its child, thus all the resources of the
1388 - // ssh session get added to init, resulting in a huge spike on
1389 - // the charts).
1390 -
1391 - if(unlikely(pp->cminflt < pp->fix_cminflt)) {
1392 - if(likely(init && pp != init)) {
1393 - unsigned long long have = pp->fix_cminflt - pp->cminflt;
1394 - unsigned long long max = init->cminflt - init->fix_cminflt;
1395 - if(have > max) have = max;
1396 - init->fix_cminflt += have;
1397 - }
1398 - pp->fix_cminflt = pp->cminflt;
1399 - }
1400 - if(unlikely(pp->cmajflt < pp->fix_cmajflt)) {
1401 - if(likely(init && pp != init)) {
1402 - unsigned long long have = pp->fix_cmajflt - pp->cmajflt;
1403 - unsigned long long max = init->cmajflt - init->fix_cmajflt;
1404 - if(have > max) have = max;
1405 - init->fix_cmajflt += have;
1406 - }
1407 - pp->fix_cmajflt = pp->cmajflt;
1408 - }
1409 - if(unlikely(pp->cutime < pp->fix_cutime)) {
1410 - if(likely(init && pp != init)) {
1411 - unsigned long long have = pp->fix_cutime - pp->cutime;
1412 - unsigned long long max = init->cutime - init->fix_cutime;
1413 - if(have > max) have = max;
1414 - init->fix_cutime += have;
1415 - }
1416 - pp->fix_cutime = pp->cutime;
1417 - }
1418 - if(unlikely(pp->cstime < pp->fix_cstime)) {
1419 - if(likely(init && pp != init)) {
1420 - unsigned long long have = pp->fix_cstime - pp->cstime;
1421 - unsigned long long max = init->cstime - init->fix_cstime;
1422 - if(have > max) have = max;
1423 - init->fix_cstime += have;
1424 - }
1425 - pp->fix_cstime = pp->cstime;
1426 - }
1427 -
1428 - if(unlikely(debug))
1429 - fprintf(stderr, "apps.plugin: \tupdating child metrics of %d (%s, %s) to its parent %d (%s, %s). Parent has now: utime=%llu, stime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu, fix_cutime=%llu, fix_cstime=%llu, fix_cminflt=%llu, fix_cmajflt=%llu\n", p->pid, p->comm, p->updated?"running":"exited", pp->pid, pp->comm, pp->updated?"running":"exited", pp->utime, pp->stime, pp->minflt, pp->majflt, pp->cutime, pp->cstime, pp->cminflt, pp->cmajflt, pp->fix_cutime, pp->fix_cstime, pp->fix_cminflt, pp->fix_cmajflt);
1430 - }
1431 - }
1432 - }
1433 - else if(unlikely(p->ppid != 0))
1434 - error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1435 - }
1436 -}
1437 -
1438 -
1439 -void cleanup_non_existing_pids(void) {
1615 +void cleanup_exited_pids(void) {
1616 int c;
1617 struct pid_stat *p = NULL;
1618
1619 for(p = root_of_pids; p ;) {
1444 - if(!p->updated) {
1620 + if(!p->updated && (!p->keep || p->keeploops > 1)) {
1621 // fprintf(stderr, "\tEXITED %d %s [parent %d %s, target %s] utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, p->parent->pid, p->parent->comm, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1622
1623 +#ifdef NETDATA_INTERNAL_CHECKS
1624 + if(p->keep)
1625 + fprintf(stderr, " > cannot keep exited process %d (%s) anymore - removing it.\n", p->pid, p->comm);
1626 +#endif
1627 +
1628 for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] > 0) {
1629 file_descriptor_not_used(p->fds[c]);
1630 p->fds[c] = 0;
@@ -1453,7 +1634,11 @@ void cleanup_non_existing_pids(void) {
1634 p = p->next;
1635 del_pid_entry(r);
1636 }
1456 - else p = p->next;
1637 + else {
1638 + if(unlikely(p->keep)) p->keeploops++;
1639 + p->keep = 0;
1640 + p = p->next;
1641 + }
1642 }
1643 }
1644
@@ -1481,13 +1666,14 @@ void apply_apps_groups_targets_inheritance(void) {
1666 }
1667 }
1668
1484 -
1669 // find all the procs with 0 childs and merge them to their parents
1670 // repeat, until nothing more can be done.
1671 + int sortlist = 1;
1672 found = 1;
1673 while(found) {
1674 if(unlikely(debug)) loops++;
1675 found = 0;
1676 +
1677 for(p = root_of_pids; p ; p = p->next) {
1678 // if this process does not have any children
1679 // and is not already merged
@@ -1517,10 +1703,15 @@ void apply_apps_groups_targets_inheritance(void) {
1703
1704 found++;
1705 }
1706 +
1707 + // since this process does not have any childs
1708 + // assign it to the current sortlist
1709 + if(unlikely(!p->sortlist && !p->children_count))
1710 + p->sortlist = sortlist++;
1711 }
1712
1713 if(unlikely(debug))
1523 - fprintf(stderr, "apps.plugin: merged %d processes\n", found);
1714 + fprintf(stderr, "apps.plugin: TARGET INHERITANCE: merged %d processes\n", found);
1715 }
1716
1717 // init goes always to default target
@@ -1532,8 +1723,12 @@ void apply_apps_groups_targets_inheritance(void) {
1723 for(p = root_of_pids; p ; p = p->next) {
1724 // if the process is not merged itself
1725 // then is is a top level process
1535 - if(!p->merged && !p->target)
1726 + if(unlikely(!p->merged && !p->target))
1727 p->target = apps_groups_default_target;
1728 +
1729 + // make sure all processes have a sortlist
1730 + if(unlikely(!p->sortlist))
1731 + p->sortlist = sortlist++;
1732 }
1733
1734 // give a target to all merged child processes
@@ -1599,6 +1794,8 @@ long zero_all_targets(struct target *root) {
1794 }
1795
1796 void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
1797 + (void)o;
1798 +
1799 if(unlikely(!w->fds)) {
1800 w->fds = calloc(sizeof(int), (size_t) all_files_size);
1801 if(unlikely(!w->fds))
@@ -1606,26 +1803,16 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1803 }
1804
1805 if(likely(p->updated)) {
1609 - if(unlikely(debug && (p->fix_cutime || p->fix_cstime || p->fix_cminflt || p->fix_cmajflt)))
1610 - fprintf(stderr, "apps.plugin: \tadding child counters of %d (%s) to target %s. Currents: cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu, Fixes: cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu\n", p->pid, p->comm, w->name, p->cutime, p->cstime, p->cminflt, p->cmajflt, p->fix_cutime, p->fix_cstime, p->fix_cminflt, p->fix_cmajflt);
1611 -
1612 - w->cutime += p->cutime - p->fix_cutime;
1613 - w->cstime += p->cstime - p->fix_cstime;
1614 - w->cminflt += p->cminflt - p->fix_cminflt;
1615 - w->cmajflt += p->cmajflt - p->fix_cmajflt;
1616 -
1617 - w->utime += p->utime; //+ (p->pid != 1)?(p->cutime - p->fix_cutime):0;
1618 - w->stime += p->stime; //+ (p->pid != 1)?(p->cstime - p->fix_cstime):0;
1619 - w->minflt += p->minflt; //+ (p->pid != 1)?(p->cminflt - p->fix_cminflt):0;
1620 - w->majflt += p->majflt; //+ (p->pid != 1)?(p->cmajflt - p->fix_cmajflt):0;
1806 + w->cutime += p->cutime;
1807 + w->cstime += p->cstime;
1808 + w->cminflt += p->cminflt;
1809 + w->cmajflt += p->cmajflt;
1810
1622 - //if(p->num_threads < 0)
1623 - // error("Negative threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
1811 + w->utime += p->utime;
1812 + w->stime += p->stime;
1813 + w->minflt += p->minflt;
1814 + w->majflt += p->majflt;
1815
1625 - //if(p->num_threads > 10000)
1626 - // error("Excessive threads number for pid '%s' (%d): %d", p->comm, p->pid, p->num_threads);
1627 -
1628 - w->num_threads += p->num_threads;
1816 w->rss += p->rss;
1817
1818 w->statm_size += p->statm_size;
@@ -1636,15 +1823,16 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1823 w->statm_data += p->statm_data;
1824 w->statm_dirty += p->statm_dirty;
1825
1639 - w->io_logical_bytes_read += p->io_logical_bytes_read;
1826 + w->io_logical_bytes_read += p->io_logical_bytes_read;
1827 w->io_logical_bytes_written += p->io_logical_bytes_written;
1641 - w->io_read_calls += p->io_read_calls;
1642 - w->io_write_calls += p->io_write_calls;
1643 - w->io_storage_bytes_read += p->io_storage_bytes_read;
1828 + w->io_read_calls += p->io_read_calls;
1829 + w->io_write_calls += p->io_write_calls;
1830 + w->io_storage_bytes_read += p->io_storage_bytes_read;
1831 w->io_storage_bytes_written += p->io_storage_bytes_written;
1832 w->io_cancelled_write_bytes += p->io_cancelled_write_bytes;
1833
1834 w->processes++;
1835 + w->num_threads += p->num_threads;
1836
1837 if(likely(w->fds)) {
1838 int c;
@@ -1660,103 +1848,8 @@ void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target
1848 }
1849
1850 if(unlikely(debug || w->debug))
1663 - fprintf(stderr, "apps.plugin: \tAggregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, fix_cutime=%llu, fix_cstime=%llu, fix_cminflt=%llu, fix_cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->fix_cutime, p->fix_cstime, p->fix_cminflt, p->fix_cmajflt);
1664 -
1665 -/* if(p->utime - p->old_utime > 100) fprintf(stderr, "BIG CHANGE: %d %s utime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->utime - p->old_utime, p->old_utime, p->utime);
1666 - if(p->cutime - p->old_cutime > 100) fprintf(stderr, "BIG CHANGE: %d %s cutime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cutime - p->old_cutime, p->old_cutime, p->cutime);
1667 - if(p->stime - p->old_stime > 100) fprintf(stderr, "BIG CHANGE: %d %s stime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->stime - p->old_stime, p->old_stime, p->stime);
1668 - if(p->cstime - p->old_cstime > 100) fprintf(stderr, "BIG CHANGE: %d %s cstime increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cstime - p->old_cstime, p->old_cstime, p->cstime);
1669 - if(p->minflt - p->old_minflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s minflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->minflt - p->old_minflt, p->old_minflt, p->minflt);
1670 - if(p->majflt - p->old_majflt > 5000) fprintf(stderr, "BIG CHANGE: %d %s majflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->majflt - p->old_majflt, p->old_majflt, p->majflt);
1671 - if(p->cminflt - p->old_cminflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cminflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cminflt - p->old_cminflt, p->old_cminflt, p->cminflt);
1672 - if(p->cmajflt - p->old_cmajflt > 15000) fprintf(stderr, "BIG CHANGE: %d %s cmajflt increased by %llu from %llu to %llu\n", p->pid, p->comm, p->cmajflt - p->old_cmajflt, p->old_cmajflt, p->cmajflt);
1673 -*/
1674 -
1675 - if(o) {
1676 - // since the process switched target
1677 - // for all incremental values
1678 - // we have to subtract its OLD values from the new target
1679 - // and add its OLD values to the old target
1680 -
1681 - // IMPORTANT
1682 - // We add/subtract the last/OLD values we added to the target
1683 -
1684 - unsigned long long cutime = p->last_cutime - p->last_fix_cutime;
1685 - unsigned long long cstime = p->last_cstime - p->last_fix_cstime;
1686 - unsigned long long cminflt = p->last_cminflt - p->last_fix_cminflt;
1687 - unsigned long long cmajflt = p->last_cmajflt - p->last_fix_cmajflt;
1688 -
1689 - w->fix_cutime -= cutime;
1690 - w->fix_cstime -= cstime;
1691 - w->fix_cminflt -= cminflt;
1692 - w->fix_cmajflt -= cmajflt;
1693 -
1694 - w->fix_utime -= p->last_utime;
1695 - w->fix_stime -= p->last_stime;
1696 - w->fix_minflt -= p->last_minflt;
1697 - w->fix_majflt -= p->last_majflt;
1698 -
1699 - w->fix_io_logical_bytes_read -= p->last_io_logical_bytes_read;
1700 - w->fix_io_logical_bytes_written -= p->last_io_logical_bytes_written;
1701 - w->fix_io_read_calls -= p->last_io_read_calls;
1702 - w->fix_io_write_calls -= p->last_io_write_calls;
1703 - w->fix_io_storage_bytes_read -= p->last_io_storage_bytes_read;
1704 - w->fix_io_storage_bytes_written -= p->last_io_storage_bytes_written;
1705 - w->fix_io_cancelled_write_bytes -= p->last_io_cancelled_write_bytes;
1706 -
1707 - // ---
1708 -
1709 - o->fix_cutime += cutime;
1710 - o->fix_cstime += cstime;
1711 - o->fix_cminflt += cminflt;
1712 - o->fix_cmajflt += cmajflt;
1713 -
1714 - o->fix_utime += p->last_utime;
1715 - o->fix_stime += p->last_stime;
1716 - o->fix_minflt += p->last_minflt;
1717 - o->fix_majflt += p->last_majflt;
1718 -
1719 - o->fix_io_logical_bytes_read += p->last_io_logical_bytes_read;
1720 - o->fix_io_logical_bytes_written += p->last_io_logical_bytes_written;
1721 - o->fix_io_read_calls += p->last_io_read_calls;
1722 - o->fix_io_write_calls += p->last_io_write_calls;
1723 - o->fix_io_storage_bytes_read += p->last_io_storage_bytes_read;
1724 - o->fix_io_storage_bytes_written += p->last_io_storage_bytes_written;
1725 - o->fix_io_cancelled_write_bytes += p->last_io_cancelled_write_bytes;
1726 - }
1727 - }
1728 - else {
1729 - // if(o) fprintf(stderr, "apps.plugin: \t\tpid %d (%s) is not updated by OLD target %s (%s) is present.\n", p->pid, p->comm, o->id, o->name);
1730 -
1731 - // since the process has exited, the user
1732 - // will see a drop in our charts, because the incremental
1733 - // values of this process will not be there from now on
1734 -
1735 - // add them to the fix_* values and they will be added to
1736 - // the reported values, so that the report goes steady
1737 -
1738 - w->fix_minflt += p->last_minflt;
1739 - w->fix_majflt += p->last_majflt;
1740 - w->fix_utime += p->last_utime;
1741 - w->fix_stime += p->last_stime;
1742 -
1743 - w->fix_cminflt += (p->last_cminflt - p->last_fix_cminflt);
1744 - w->fix_cmajflt += (p->last_cmajflt - p->last_fix_cmajflt);
1745 - w->fix_cutime += (p->last_cutime - p->last_fix_cutime);
1746 - w->fix_cstime += (p->last_cstime - p->last_fix_cstime);
1747 -
1748 - w->fix_io_logical_bytes_read += p->last_io_logical_bytes_read;
1749 - w->fix_io_logical_bytes_written += p->last_io_logical_bytes_written;
1750 - w->fix_io_read_calls += p->last_io_read_calls;
1751 - w->fix_io_write_calls += p->last_io_write_calls;
1752 - w->fix_io_storage_bytes_read += p->last_io_storage_bytes_read;
1753 - w->fix_io_storage_bytes_written += p->last_io_storage_bytes_written;
1754 - w->fix_io_cancelled_write_bytes += p->last_io_cancelled_write_bytes;
1851 + fprintf(stderr, "apps.plugin: \taggregating '%s' pid %d on target '%s' utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, w->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt);
1852 }
1756 -
1757 - //if((long long)w->cutime + w->fix_cutime < 0)
1758 - // error("Negative total cutime (%llu - %lld) on target %s after adding process %d (%s, %s) with utime=%llu, stime=%llu, minflt=%llu, majflt=%llu, cutime=%llu, cstime=%llu, cminflt=%llu, cmajflt=%llu, fix_cutime=%llu, fix_cstime=%llu, fix_cminflt=%llu, fix_cmajflt=%llu\n",
1759 - // w->cutime, w->fix_cutime, w->name, p->pid, p->comm, p->updated?"running":"exited", p->utime, p->stime, p->minflt, p->majflt, p->cutime, p->cstime, p->cminflt, p->cmajflt, p->fix_cutime, p->fix_cstime, p->fix_cminflt, p->fix_cmajflt);
1853 }
1854
1855 void count_targets_fds(struct target *root) {
@@ -1821,9 +1914,7 @@ void count_targets_fds(struct target *root) {
1914 }
1915 }
1916
1824 -void calculate_netdata_statistics(void)
1825 -{
1826 - link_all_processes_to_their_parents();
1917 +void calculate_netdata_statistics(void) {
1918 apply_apps_groups_targets_inheritance();
1919
1920 zero_all_targets(users_root_target);
@@ -1886,7 +1977,7 @@ void calculate_netdata_statistics(void)
1977 count_targets_fds(users_root_target);
1978 count_targets_fds(groups_root_target);
1979
1889 - cleanup_non_existing_pids();
1980 + cleanup_exited_pids();
1981 }
1982
1983 // ----------------------------------------------------------------------------
@@ -1944,12 +2035,68 @@ unsigned long long send_resource_usage_to_netdata() {
2035 void send_collected_data_to_netdata(struct target *root, const char *type, unsigned long long usec)
2036 {
2037 struct target *w;
2038 + int childs = include_exited_childs;
2039 +
2040 + {
2041 + // childs processing introduces spikes
2042 + // here we try to eliminate them by disabling childs processing either for specific dimensions
2043 + // or entirely. Of course, either way, we disable it just a single iteration.
2044 +
2045 + unsigned long long max = update_every * processors * 100 * 100;
2046 + unsigned long long utime = 0, cutime = 0, stime = 0, cstime = 0, minflt = 0, cminflt = 0, majflt = 0, cmajflt = 0;
2047 +
2048 + for (w = root; w ; w = w->next) {
2049 + if(w->target || (!w->processes && !w->exposed)) continue;
2050 +
2051 + if((w->utime + w->stime + w->cutime + w->cstime) > max) {
2052 +#ifdef NETDATA_INTERNAL_CHECKS
2053 + log_date(stderr);
2054 + fprintf(stderr, "Prevented a spike on target '%s', reported CPU time = %llu (without childs = %llu)\n", w->name, (w->utime + w->stime + w->cutime + w->cstime) / 100, (w->utime + w->stime) / 100);
2055 +#endif
2056 + w->cutime = w->cstime = w->cminflt = w->majflt = 0;
2057 + }
2058 +
2059 + utime += w->utime;
2060 + cutime += w->cutime;
2061 + stime += w->stime;
2062 + cstime += w->cstime;
2063 + minflt += w->minflt;
2064 + cminflt += w->cminflt;
2065 + majflt += w->majflt;
2066 + cmajflt += w->cmajflt;
2067 + }
2068 +
2069 + if((utime + stime + cutime + cstime) > max) {
2070 + childs = 0;
2071 +#ifdef NETDATA_INTERNAL_CHECKS
2072 + log_date(stderr);
2073 + fprintf(stderr, "Prevented a spike because the total CPU of all dimensions = %llu (without childs = %llu)\n", (utime + stime + cutime + cstime) / 100, (utime + stime) / 100);
2074 +#endif
2075 + }
2076 +
2077 + if((utime + stime) > max) {
2078 + childs = 0;
2079 + unsigned long long multiplier = max, divider = utime + stime;
2080 + for (w = root; w ; w = w->next) {
2081 + w->utime = w->utime * multiplier / divider;
2082 + w->stime = w->stime * multiplier / divider;
2083 + w->minflt = w->minflt * multiplier / divider;
2084 + w->majflt = w->majflt * multiplier / divider;
2085 + }
2086 +
2087 +#ifdef NETDATA_INTERNAL_CHECKS
2088 + log_date(stderr);
2089 + fprintf(stderr, "Reduced processes utilization (without childs) by %0.2f%% (CPU was %llu)\n", (float)((utime + stime - max * 100.0)/(float)max), (utime + stime) / 100);
2090 +#endif
2091 + }
2092 +
2093 + }
2094
2095 fprintf(stdout, "BEGIN %s.cpu %llu\n", type, usec);
2096 for (w = root; w ; w = w->next) {
2097 if(w->target || (!w->processes && !w->exposed)) continue;
2098
1952 - fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + w->fix_utime + w->fix_stime + (include_exited_childs?(w->cutime + w->cstime + w->fix_cutime + w->fix_cstime):0));
2099 + fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->stime + (childs?(w->cutime + w->cstime):0));
2100 }
2101 fprintf(stdout, "END\n");
2102
@@ -1957,7 +2104,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2104 for (w = root; w ; w = w->next) {
2105 if(w->target || (!w->processes && !w->exposed)) continue;
2106
1960 - fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + w->fix_utime + (include_exited_childs?(w->cutime + w->fix_cutime):0));
2107 + fprintf(stdout, "SET %s = %llu\n", w->name, w->utime + (childs?(w->cutime):0));
2108 }
2109 fprintf(stdout, "END\n");
2110
@@ -1965,7 +2112,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2112 for (w = root; w ; w = w->next) {
2113 if(w->target || (!w->processes && !w->exposed)) continue;
2114
1968 - fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + w->fix_stime + (include_exited_childs?(w->cstime + w->fix_cstime):0));
2115 + fprintf(stdout, "SET %s = %llu\n", w->name, w->stime + (childs?(w->cstime):0));
2116 }
2117 fprintf(stdout, "END\n");
2118
@@ -1997,7 +2144,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2144 for (w = root; w ; w = w->next) {
2145 if(w->target || (!w->processes && !w->exposed)) continue;
2146
2000 - fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + w->fix_minflt + (include_exited_childs?(w->cminflt + w->fix_cminflt):0));
2147 + fprintf(stdout, "SET %s = %llu\n", w->name, w->minflt + (childs?(w->cminflt):0));
2148 }
2149 fprintf(stdout, "END\n");
2150
@@ -2005,7 +2152,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2152 for (w = root; w ; w = w->next) {
2153 if(w->target || (!w->processes && !w->exposed)) continue;
2154
2008 - fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + w->fix_majflt + (include_exited_childs?(w->cmajflt + w->fix_cmajflt):0));
2155 + fprintf(stdout, "SET %s = %llu\n", w->name, w->majflt + (childs?(w->cmajflt):0));
2156 }
2157 fprintf(stdout, "END\n");
2158
@@ -2013,7 +2160,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2160 for (w = root; w ; w = w->next) {
2161 if(w->target || (!w->processes && !w->exposed)) continue;
2162
2016 - fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read + w->fix_io_logical_bytes_read);
2163 + fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_read);
2164 }
2165 fprintf(stdout, "END\n");
2166
@@ -2021,7 +2168,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2168 for (w = root; w ; w = w->next) {
2169 if(w->target || (!w->processes && !w->exposed)) continue;
2170
2024 - fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written + w->fix_io_logical_bytes_written);
2171 + fprintf(stdout, "SET %s = %llu\n", w->name, w->io_logical_bytes_written);
2172 }
2173 fprintf(stdout, "END\n");
2174
@@ -2029,7 +2176,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2176 for (w = root; w ; w = w->next) {
2177 if(w->target || (!w->processes && !w->exposed)) continue;
2178
2032 - fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read + w->fix_io_storage_bytes_read);
2179 + fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_read);
2180 }
2181 fprintf(stdout, "END\n");
2182
@@ -2037,7 +2184,7 @@ void send_collected_data_to_netdata(struct target *root, const char *type, unsig
2184 for (w = root; w ; w = w->next) {
2185 if(w->target || (!w->processes && !w->exposed)) continue;
2186
2040 - fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written + w->fix_io_storage_bytes_written);
2187 + fprintf(stdout, "SET %s = %llu\n", w->name, w->io_storage_bytes_written);
2188 }
2189 fprintf(stdout, "END\n");
2190
@@ -2093,7 +2240,7 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
2240 for (w = root; w ; w = w->next) {
2241 if(w->target || (!w->processes && !w->exposed)) continue;
2242
2096 - fprintf(stdout, "DIMENSION %s '' incremental 100 %u %s\n", w->name, hz, w->hidden ? "hidden,noreset" : "noreset");
2243 + fprintf(stdout, "DIMENSION %s '' absolute 1 %u %s\n", w->name, hz, w->hidden ? "hidden,noreset" : "noreset");
2244 }
2245
2246 fprintf(stdout, "CHART %s.mem '' '%s Dedicated Memory (w/o shared)' 'MB' mem %s.mem stacked 20003 %d\n", type, title, type, update_every);
@@ -2121,56 +2268,56 @@ void send_charts_updates_to_netdata(struct target *root, const char *type, const
2268 for (w = root; w ; w = w->next) {
2269 if(w->target || (!w->processes && !w->exposed)) continue;
2270
2124 - fprintf(stdout, "DIMENSION %s '' incremental 100 %u noreset\n", w->name, hz);
2271 + fprintf(stdout, "DIMENSION %s '' absolute 1 %u noreset\n", w->name, hz);
2272 }
2273
2274 fprintf(stdout, "CHART %s.cpu_system '' '%s CPU System Time (%d%% = %d core%s)' 'cpu time %%' cpu %s.cpu_system stacked 20021 %d\n", type, title, (processors * 100), processors, (processors>1)?"s":"", type, update_every);
2275 for (w = root; w ; w = w->next) {
2276 if(w->target || (!w->processes && !w->exposed)) continue;
2277
2131 - fprintf(stdout, "DIMENSION %s '' incremental 100 %u noreset\n", w->name, hz);
2278 + fprintf(stdout, "DIMENSION %s '' absolute 1 %u noreset\n", w->name, hz);
2279 }
2280
2281 fprintf(stdout, "CHART %s.major_faults '' '%s Major Page Faults (swap read)' 'page faults/s' swap %s.major_faults stacked 20010 %d\n", type, title, type, update_every);
2282 for (w = root; w ; w = w->next) {
2283 if(w->target || (!w->processes && !w->exposed)) continue;
2284
2138 - fprintf(stdout, "DIMENSION %s '' incremental 1 1 noreset\n", w->name);
2285 + fprintf(stdout, "DIMENSION %s '' absolute 1 100 noreset\n", w->name);
2286 }
2287
2288 fprintf(stdout, "CHART %s.minor_faults '' '%s Minor Page Faults' 'page faults/s' mem %s.minor_faults stacked 20011 %d\n", type, title, type, update_every);
2289 for (w = root; w ; w = w->next) {
2290 if(w->target || (!w->processes && !w->exposed)) continue;
2291
2145 - fprintf(stdout, "DIMENSION %s '' incremental 1 1 noreset\n", w->name);
2292 + fprintf(stdout, "DIMENSION %s '' absolute 1 100 noreset\n", w->name);
2293 }
2294
2295 fprintf(stdout, "CHART %s.lreads '' '%s Disk Logical Reads' 'kilobytes/s' disk %s.lreads stacked 20042 %d\n", type, title, type, update_every);
2296 for (w = root; w ; w = w->next) {
2297 if(w->target || (!w->processes && !w->exposed)) continue;
2298
2152 - fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2299 + fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024*100);
2300 }
2301
2302 fprintf(stdout, "CHART %s.lwrites '' '%s I/O Logical Writes' 'kilobytes/s' disk %s.lwrites stacked 20042 %d\n", type, title, type, update_every);
2303 for (w = root; w ; w = w->next) {
2304 if(w->target || (!w->processes && !w->exposed)) continue;
2305
2159 - fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2306 + fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024*100);
2307 }
2308
2309 fprintf(stdout, "CHART %s.preads '' '%s Disk Reads' 'kilobytes/s' disk %s.preads stacked 20002 %d\n", type, title, type, update_every);
2310 for (w = root; w ; w = w->next) {
2311 if(w->target || (!w->processes && !w->exposed)) continue;
2312
2166 - fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2313 + fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024*100);
2314 }
2315
2316 fprintf(stdout, "CHART %s.pwrites '' '%s Disk Writes' 'kilobytes/s' disk %s.pwrites stacked 20002 %d\n", type, title, type, update_every);
2317 for (w = root; w ; w = w->next) {
2318 if(w->target || (!w->processes && !w->exposed)) continue;
2319
2173 - fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024);
2320 + fprintf(stdout, "DIMENSION %s '' incremental 1 %d noreset\n", w->name, 1024*100);
2321 }
2322
2323 fprintf(stdout, "CHART %s.files '' '%s Open Files' 'open files' disk %s.files stacked 20050 %d\n", type, title, type, update_every);
@@ -2215,7 +2362,7 @@ void parse_args(int argc, char **argv)
2362
2363 if(strcmp("debug", argv[i]) == 0) {
2364 debug = 1;
2218 - debug_flags = 0xffffffff;
2365 + // debug_flags = 0xffffffff;
2366 continue;
2367 }
2368
@@ -2294,6 +2441,13 @@ int main(int argc, char **argv)
2441
2442 parse_args(argc, argv);
2443
2444 + all_pids_sortlist = calloc(sizeof(pid_t), (size_t)pid_max);
2445 + if(!all_pids_sortlist) {
2446 + error("Cannot allocate %lu bytes of memory.", sizeof(pid_t) * pid_max);
2447 + printf("DISABLE\n");
2448 + exit(1);
2449 + }
2450 +
2451 all_pids = calloc(sizeof(struct pid_stat *), (size_t) pid_max);
2452 if(!all_pids) {
2453 error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
@@ -2315,8 +2469,8 @@ int main(int argc, char **argv)
2469 unsigned long long sunow;
2470 #endif /* PROFILING_MODE */
2471
2318 - unsigned long long counter = 1;
2319 - for(;1; counter++) {
2472 + global_iterations_counter = 1;
2473 + for(;1; global_iterations_counter++) {
2474 #ifndef PROFILING_MODE
2475 // delay until it is our time to run
2476 while((sunow = timems()) < sunext)
@@ -2347,7 +2501,7 @@ int main(int argc, char **argv)
2501 send_collected_data_to_netdata(groups_root_target, "groups", dt);
2502
2503 if(unlikely(debug))
2350 - fprintf(stderr, "apps.plugin: done Loop No %llu\n", counter);
2504 + fprintf(stderr, "apps.plugin: done Loop No %llu\n", global_iterations_counter);
2505
2506 current_t = time(NULL);
2507