int init_process_info_sysdep(void) { char *ptr; char buf[1024]; long page_size; int page_shift; if (! read_proc_file(buf, sizeof(buf), "meminfo", -1, NULL)) return FALSE; if (! (ptr = strstr(buf, MEMTOTAL))) { DEBUG("system statistic error -- cannot get real memory amount\n"); return FALSE; } if (sscanf(ptr+strlen(MEMTOTAL), "%ld", &systeminfo.mem_kbyte_max) != 1) { DEBUG("system statistic error -- cannot get real memory amount\n"); return FALSE; } if ((systeminfo.cpus = sysconf(_SC_NPROCESSORS_CONF)) < 0) { DEBUG("system statistic error -- cannot get cpu count: %s\n", STRERROR); return FALSE; } else if (systeminfo.cpus == 0) { DEBUG("system reports cpu count 0, setting dummy cpu count 1\n"); systeminfo.cpus = 1; } if ((page_size = sysconf(_SC_PAGESIZE)) <= 0) { DEBUG("system statistic error -- cannot get page size: %s\n", STRERROR); return FALSE; } for (page_shift = 0; page_size != 1; page_size >>= 1, page_shift++); page_shift_to_kb = page_shift - 10; return TRUE; }
/** * @file * @brief * Cached Ram * * @details * This function looks up the amount of ram used for cache in bytes. * * @param totalram * Output, passed by reference. On successful return, the value * is set to the amount of ram used for disk cache (in bytes) available on the system. * * @return * The return value indicates the status of the function. */ int meminfo_cachedram(memsize_t *cachedram) { int ret = MEMINFO_OK; *cachedram = 0L; #if OS_LINUX int test = read_proc_file("/proc/meminfo", cachedram, "Cached:", 7); chkret(test, FAILURE); *cachedram *= 1024L; #elif OS_FREEBSD int page; memsize_t v = 0; page = sysconf(_SC_PAGESIZE); if (page == -1) return FAILURE; int test = sysctl_val("vm.stats.vm.v_cache_count", &v); chkret(test, FAILURE); *cachedram = (memsize_t) v*page; #else ret = PLATFORM_ERROR; #endif return ret; }
/** * Get system start time * @return seconds since unix epoch */ static time_t get_starttime() { char buf[1024]; double up = 0; if (! read_proc_file(buf, 1024, "uptime", -1, NULL)) { LogError("system statistic error -- cannot get system uptime\n"); return 0; } if (sscanf(buf, "%lf", &up) != 1) { LogError("system statistic error -- invalid uptime\n"); return 0; } return time(NULL) - (time_t)up; }
/** * This routine returns real memory in use. * @return: true if successful, false if failed */ boolean_t used_system_memory_sysdep(SystemInfo_T *si) { char *ptr; char buf[2048]; unsigned long mem_free = 0UL; unsigned long buffers = 0UL; unsigned long cached = 0UL; unsigned long slabreclaimable = 0UL; unsigned long swap_total = 0UL; unsigned long swap_free = 0UL; if (! read_proc_file(buf, sizeof(buf), "meminfo", -1, NULL)) { LogError("system statistic error -- cannot get real memory free amount\n"); goto error; } /* Memory */ if (! (ptr = strstr(buf, "MemFree:")) || sscanf(ptr + 8, "%ld", &mem_free) != 1) { LogError("system statistic error -- cannot get real memory free amount\n"); goto error; } if (! (ptr = strstr(buf, "Buffers:")) || sscanf(ptr + 8, "%ld", &buffers) != 1) DEBUG("system statistic error -- cannot get real memory buffers amount\n"); if (! (ptr = strstr(buf, "Cached:")) || sscanf(ptr + 7, "%ld", &cached) != 1) DEBUG("system statistic error -- cannot get real memory cache amount\n"); if (! (ptr = strstr(buf, "SReclaimable:")) || sscanf(ptr + 13, "%ld", &slabreclaimable) != 1) DEBUG("system statistic error -- cannot get slab reclaimable memory amount\n"); si->total_mem = systeminfo.mem_max - (uint64_t)(mem_free + buffers + cached + slabreclaimable) * 1024; /* Swap */ if (! (ptr = strstr(buf, "SwapTotal:")) || sscanf(ptr + 10, "%ld", &swap_total) != 1) { LogError("system statistic error -- cannot get swap total amount\n"); goto error; } if (! (ptr = strstr(buf, "SwapFree:")) || sscanf(ptr + 9, "%ld", &swap_free) != 1) { LogError("system statistic error -- cannot get swap free amount\n"); goto error; } si->swap_max = (uint64_t)swap_total * 1024; si->total_swap = (uint64_t)(swap_total - swap_free) * 1024; return true; error: si->total_mem = 0ULL; si->swap_max = 0ULL; return false; }
/** * This routine returns 'nelem' double precision floats containing * the load averages in 'loadv'; at most 3 values will be returned. * @param loadv destination of the load averages * @param nelem number of averages * @return: 0 if successful, -1 if failed (and all load averages are 0). */ int getloadavg_sysdep(double *loadv, int nelem) { #ifdef HAVE_GETLOADAVG return getloadavg(loadv, nelem); #else char buf[STRLEN]; double load[3]; if (! read_proc_file(buf, sizeof(buf), "loadavg", -1, NULL)) return -1; if (sscanf(buf, "%lf %lf %lf", &load[0], &load[1], &load[2]) != 3) { DEBUG("system statistic error -- cannot get load average\n"); return -1; } for (int i = 0; i < nelem; i++) loadv[i] = load[i]; return 0; #endif }
void refresh_global_stats(proc_global_stats_t *stat) { static int proc_stat_fd = -1; char buf[1024], *p, *end; int ret; ret = read_proc_file(&proc_stat_fd, "/proc/stat", buf, sizeof(buf)-1); if( ret < 0 ) return; buf[ret] = '\0'; // FIXME: parse CPU info (?) // parse pageing activity p = strstr(buf,"page "); if( p == NULL ) {warning("couldn't find page data in /proc/stat!\n"); return;} p += 5; // strlen("page "); stat->pages_in = strtol(p, &end, 0); if( p == end ) {warning("bad pagein data\n"); return;} p = end; stat->pages_out = strtol(p, &end, 0); if( p == end ) {warning("bad pagein data\n"); return;} // parse swap file activity p = strstr(buf,"swap "); if( p == NULL ) {warning("couldn't find swap data in /proc/stat!\n"); return;} p += 5; // strlen("swap "); stat->pages_swapin = strtol(p, &end, 0); if( p == end ) {warning("bad pswapin data\n"); return;} p = end; stat->pages_swapout = strtol(p, &end, 0); if( p == end ) {warning("bad pswapout data\n"); return;} warning("gstats: %d %d %d %d\n", stat->pages_in, stat->pages_out, stat->pages_swapin, stat->pages_swapout); }
boolean_t init_process_info_sysdep(void) { char *ptr; char buf[2048]; if ((hz = sysconf(_SC_CLK_TCK)) <= 0.) { DEBUG("system statistic error -- cannot get hz: %s\n", STRERROR); return false; } if ((page_size = sysconf(_SC_PAGESIZE)) <= 0) { DEBUG("system statistic error -- cannot get page size: %s\n", STRERROR); return false; } if (! read_proc_file(buf, sizeof(buf), "meminfo", -1, NULL)) { DEBUG("system statistic error -- cannot read /proc/meminfo\n"); return false; } if (! (ptr = strstr(buf, "MemTotal:"))) { DEBUG("system statistic error -- cannot get real memory amount\n"); return false; } long mem_max; if (sscanf(ptr + 9, "%ld", &mem_max) != 1) { DEBUG("system statistic error -- cannot get real memory amount\n"); return false; } systeminfo.mem_max = (uint64_t)mem_max * 1024; if ((systeminfo.cpus = sysconf(_SC_NPROCESSORS_CONF)) < 0) { DEBUG("system statistic error -- cannot get cpu count: %s\n", STRERROR); return false; } else if (systeminfo.cpus == 0) { DEBUG("system reports cpu count 0, setting dummy cpu count 1\n"); systeminfo.cpus = 1; } return true; }
/** * This routine returns system/user CPU time in use. * @return: true if successful, false if failed (or not available) */ boolean_t used_system_cpu_sysdep(SystemInfo_T *si) { boolean_t rv; unsigned long long cpu_total; unsigned long long cpu_user; unsigned long long cpu_nice; unsigned long long cpu_syst; unsigned long long cpu_idle; unsigned long long cpu_wait; unsigned long long cpu_irq; unsigned long long cpu_softirq; char buf[STRLEN]; if (! read_proc_file(buf, sizeof(buf), "stat", -1, NULL)) { LogError("system statistic error -- cannot read /proc/stat\n"); goto error; } rv = sscanf(buf, "cpu %llu %llu %llu %llu %llu %llu %llu", &cpu_user, &cpu_nice, &cpu_syst, &cpu_idle, &cpu_wait, &cpu_irq, &cpu_softirq); if (rv < 4) { LogError("system statistic error -- cannot read cpu usage\n"); goto error; } else if (rv == 4) { /* linux 2.4.x doesn't support these values */ cpu_wait = 0; cpu_irq = 0; cpu_softirq = 0; } cpu_total = cpu_user + cpu_nice + cpu_syst + cpu_idle + cpu_wait + cpu_irq + cpu_softirq; cpu_user = cpu_user + cpu_nice; if (old_cpu_total == 0) { si->total_cpu_user_percent = -1.; si->total_cpu_syst_percent = -1.; si->total_cpu_wait_percent = -1.; } else { unsigned long long delta = cpu_total - old_cpu_total; si->total_cpu_user_percent = 100. * (double)(cpu_user - old_cpu_user) / delta; si->total_cpu_syst_percent = 100. * (double)(cpu_syst - old_cpu_syst) / delta; si->total_cpu_wait_percent = 100. * (double)(cpu_wait - old_cpu_wait) / delta; } old_cpu_user = cpu_user; old_cpu_syst = cpu_syst; old_cpu_wait = cpu_wait; old_cpu_total = cpu_total; return true; error: si->total_cpu_user_percent = 0.; si->total_cpu_syst_percent = 0.; si->total_cpu_wait_percent = 0.; return false; }
/** * Read all processes of the proc files system to initialize the process tree * @param reference reference of ProcessTree * @param pflags Process engine flags * @return treesize > 0 if succeeded otherwise 0 */ int initprocesstree_sysdep(ProcessTree_T **reference, ProcessEngine_Flags pflags) { int rv, bytes = 0; int treesize = 0; int stat_pid = 0; int stat_ppid = 0; int stat_uid = 0; int stat_euid = 0; int stat_gid = 0; char *tmp = NULL; char procname[STRLEN]; char buf[4096]; char stat_item_state; long stat_item_cutime = 0; long stat_item_cstime = 0; long stat_item_rss = 0; int stat_item_threads = 0; glob_t globbuf; unsigned long stat_item_utime = 0; unsigned long stat_item_stime = 0; unsigned long long stat_item_starttime = 0ULL; ASSERT(reference); /* Find all processes in the /proc directory */ if ((rv = glob("/proc/[0-9]*", 0, NULL, &globbuf))) { LogError("system statistic error -- glob failed: %d (%s)\n", rv, STRERROR); return 0; } treesize = globbuf.gl_pathc; ProcessTree_T *pt = CALLOC(sizeof(ProcessTree_T), treesize); /* Insert data from /proc directory */ time_t starttime = get_starttime(); for (int i = 0; i < treesize; i++) { stat_pid = atoi(globbuf.gl_pathv[i] + 6); // skip "/proc/" /********** /proc/PID/stat **********/ if (! read_proc_file(buf, sizeof(buf), "stat", stat_pid, NULL)) { DEBUG("system statistic error -- cannot read /proc/%d/stat\n", stat_pid); continue; } if (! (tmp = strrchr(buf, ')'))) { DEBUG("system statistic error -- file /proc/%d/stat parse error\n", stat_pid); continue; } *tmp = 0; if (sscanf(buf, "%*d (%255s", procname) != 1) { DEBUG("system statistic error -- file /proc/%d/stat process name parse error\n", stat_pid); continue; } tmp += 2; if (sscanf(tmp, "%c %d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %ld %ld %*d %*d %d %*u %llu %*u %ld %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", &stat_item_state, &stat_ppid, &stat_item_utime, &stat_item_stime, &stat_item_cutime, &stat_item_cstime, &stat_item_threads, &stat_item_starttime, &stat_item_rss) != 9) { DEBUG("system statistic error -- file /proc/%d/stat parse error\n", stat_pid); continue; } /********** /proc/PID/status **********/ if (! read_proc_file(buf, sizeof(buf), "status", stat_pid, NULL)) { DEBUG("system statistic error -- cannot read /proc/%d/status\n", stat_pid); continue; } if (! (tmp = strstr(buf, "Uid:"))) { DEBUG("system statistic error -- cannot find process uid\n"); continue; } if (sscanf(tmp + 4, "\t%d\t%d", &stat_uid, &stat_euid) != 2) { DEBUG("system statistic error -- cannot read process uid\n"); continue; } if (! (tmp = strstr(buf, "Gid:"))) { DEBUG("system statistic error -- cannot find process gid\n"); continue; } if (sscanf(tmp + 4, "\t%d", &stat_gid) != 1) { DEBUG("system statistic error -- cannot read process gid\n"); continue; } /********** /proc/PID/cmdline **********/ if (pflags & ProcessEngine_CollectCommandLine) { if (! read_proc_file(buf, sizeof(buf), "cmdline", stat_pid, &bytes)) { DEBUG("system statistic error -- cannot read /proc/%d/cmdline\n", stat_pid); continue; } for (int j = 0; j < (bytes - 1); j++) // The cmdline file contains argv elements/strings terminated separated by '\0' => join the string if (buf[j] == 0) buf[j] = ' '; pt[i].cmdline = Str_dup(*buf ? buf : procname); } /* Set the data in ptree only if all process related reads succeeded (prevent partial data in the case that continue was called during data gathering) */ pt[i].pid = stat_pid; pt[i].ppid = stat_ppid; pt[i].cred.uid = stat_uid; pt[i].cred.euid = stat_euid; pt[i].cred.gid = stat_gid; pt[i].threads = stat_item_threads; pt[i].uptime = starttime > 0 ? (systeminfo.time / 10. - (starttime + (time_t)(stat_item_starttime / hz))) : 0; pt[i].cpu.time = (double)(stat_item_utime + stat_item_stime) / hz * 10.; // jiffies -> seconds = 1/hz pt[i].memory.usage = (uint64_t)stat_item_rss * (uint64_t)page_size; pt[i].zombie = stat_item_state == 'Z' ? true : false; } *reference = pt; globfree(&globbuf); return treesize; }
/** * Read stats from /proc/self/stat. * * FIXME: the FD caching may not work correctly for cloned children - * check on this later. **/ void refresh_process_stats(proc_self_stat_t *stat) { static int fd = -1; char buf[256]; int ret; //int len; ret = read_proc_file(&fd, "/proc/self/stat", buf, sizeof(buf)); if( ret < 0 ) return; if( ret == sizeof(buf) ) { warning("too much data in /proc/self/stat - can't get valid stats\n"); if( fd >= 0) close(fd); fd = -2; return; } // parse. We could do this faster ourselves, by not keeping all of // this data. The speed shouldn't really matter, though, since this // routine should only be called a few times / second. ret = sscanf(buf, "%d (%[^)]) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu", &stat->pid, &stat->comm[0], &stat->state, &stat->ppid, &stat->pgrp, &stat->session, &stat->tty_nr, &stat->tty_pgrp, &stat->flags, &stat->min_flt, &stat->cmin_flt, &stat->maj_flt, &stat->cmaj_flt, &stat->tms_utime, &stat->tms_stime, &stat->tms_cutime, &stat->tms_cstime, &stat->priority, &stat->nice, &stat->removed, &stat->it_real_value, &stat->start_time, // just unsigned long in 2.4 &stat->vsize, &stat->rss, &stat->rss_rlim_cur, &stat->start_code, &stat->end_code, &stat->start_stack, &stat->esp, &stat->eip, &stat->pending_sig, // obsolete - use /proc/self/status &stat->blocked_sig, // obsolete - use /proc/self/status &stat->sigign, // obsolete - use /proc/self/status &stat->sigcatch, // obsolete - use /proc/self/status &stat->wchan, &stat->nswap, &stat->cnswap, &stat->exit_signal, &stat->cpu_num, &stat->rt_priority, // new in 2.5 &stat->policy // new in 2.5 ); warning("stats: %d (%s)... %ld %ld %ld ret=%d\n", stat->pid, stat->comm, stat->vsize, stat->rss, stat->maj_flt, ret); if( ret != 39 && ret != 41 ) { warning("error parsing /proc/self/stat - got %d items\n", ret); //bzero(stat, sizeof(proc_self_stat_t)); if( fd >= 0) close(fd); fd = -1; return; } }
int read_proc_dir(const char *dir_name, const char *pid, int position) { DIR *dp; struct dirent *entry; if ((dir_name == NULL) || (strlen(dir_name) > PATH_MAX)) { merror("%s: Invalid directory given", ARGV0); return (-1); } /* Open the directory */ dp = opendir(dir_name); if (!dp) { return (0); } while ((entry = readdir(dp)) != NULL) { char f_name[PATH_MAX + 2]; /* Ignore . and .. */ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } if (position == PROC) { char *tmp_str; tmp_str = entry->d_name; while (*tmp_str != '\0') { if (!isdigit((int)*tmp_str)) { break; } tmp_str++; } if (*tmp_str != '\0') { continue; } snprintf(f_name, PATH_MAX + 1, "%s/%s", dir_name, entry->d_name); read_proc_file(f_name, pid, position + 1); } else if (position == PID) { if (strcmp(entry->d_name, "task") == 0) { snprintf(f_name, PATH_MAX + 1, "%s/%s", dir_name, entry->d_name); read_proc_file(f_name, pid, position + 1); } } else if (position == TASK) { /* Check under proc/pid/task/lwp */ if (strcmp(entry->d_name, pid) == 0) { proc_pid_found = 1; break; } } else { break; } } closedir(dp); return (0); }
/** * Read all processes of the proc files system to initialize * the process tree (sysdep version... but should work for * all procfs based unices) * @param reference reference of ProcessTree * @return treesize>0 if succeeded otherwise =0. */ int initprocesstree_sysdep(ProcessTree_T ** reference) { int i = 0, j; int rv, bytes = 0; int treesize = 0; int stat_ppid = 0; char *tmp = NULL; char procname[STRLEN]; char buf[1024]; char stat_item_state; long stat_item_cutime = 0; long stat_item_cstime = 0; long stat_item_rss = 0; glob_t globbuf; unsigned long stat_item_utime = 0; unsigned long stat_item_stime = 0; unsigned long long stat_item_starttime = 0ULL; ProcessTree_T *pt = NULL; ASSERT(reference); /* Find all processes in the /proc directory */ if ((rv = glob("/proc/[0-9]*", GLOB_ONLYDIR, NULL, &globbuf))) { LogError("system statistic error -- glob failed: %d (%s)\n", rv, STRERROR); return FALSE; } treesize = globbuf.gl_pathc; pt = CALLOC(sizeof(ProcessTree_T), treesize); /* Insert data from /proc directory */ for (i = 0; i < treesize; i++) { pt[i].pid = atoi(globbuf.gl_pathv[i] + strlen("/proc/")); if (!read_proc_file(buf, sizeof(buf), "stat", pt[i].pid, NULL)) { DEBUG("system statistic error -- cannot read /proc/%d/stat\n", pt[i].pid); continue; } pt[i].time = get_float_time(); if (!(tmp = strrchr(buf, ')'))) { DEBUG("system statistic error -- file /proc/%d/stat parse error\n", pt[i].pid); continue; } *tmp = 0; if (sscanf(buf, "%*d (%256s", procname) != 1) { DEBUG("system statistic error -- file /proc/%d/stat process name parse error\n", pt[i].pid); continue; } tmp += 2; /* This implementation is done by using fs/procfs/array.c as a basis * it is also worth looking into the source of the procps utils */ if (sscanf(tmp, "%c %d %*d %*d %*d %*d %*u %*u" "%*u %*u %*u %lu %lu %ld %ld %*d %*d %*d " "%*u %llu %*u %ld %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", &stat_item_state, &stat_ppid, &stat_item_utime, &stat_item_stime, &stat_item_cutime, &stat_item_cstime, &stat_item_starttime, &stat_item_rss) != 8) { DEBUG("system statistic error -- file /proc/%d/stat parse error\n", pt[i].pid); continue; } pt[i].ppid = stat_ppid; pt[i].starttime = get_starttime() + (time_t)(stat_item_starttime / HZ); /* jiffies -> seconds = 1 / HZ * HZ is defined in "asm/param.h" and it is usually 1/100s but on * alpha system it is 1/1024s */ pt[i].cputime = ((float)(stat_item_utime + stat_item_stime) * 10.0) / HZ; pt[i].cpu_percent = 0; /* State is Zombie -> then we are a Zombie ... clear or? (-: */ if (stat_item_state == 'Z') pt[i].status_flag |= PROCESS_ZOMBIE; if (page_shift_to_kb < 0) pt[i].mem_kbyte = (stat_item_rss >> abs(page_shift_to_kb)); else pt[i].mem_kbyte = (stat_item_rss << abs(page_shift_to_kb)); if (! read_proc_file(buf, sizeof(buf), "cmdline", pt[i].pid, &bytes)) { DEBUG("system statistic error -- cannot read /proc/%d/cmdline\n", pt[i].pid); continue; } /* The cmdline file contains argv elements/strings terminated separated by '\0' => join the string: */ for (j = 0; j < (bytes - 1); j++) if (buf[j] == 0) buf[j] = ' '; pt[i].cmdline = *buf ? Str_dup(buf) : Str_dup(procname); }
/** * Read all processes of the proc files system to initialize * the process tree (sysdep version... but should work for * all procfs based unices) * @param reference reference of ProcessTree * @return treesize>0 if succeeded otherwise =0. */ int initprocesstree_sysdep(ProcessTree_T ** reference) { int i; int rv; int pid; int treesize; char buf[4096]; glob_t globbuf; pstatus_t pstatus; psinfo_t *psinfo = (psinfo_t *)&buf; ProcessTree_T *pt; ASSERT(reference); /* Find all processes in the /proc directory */ if ((rv = glob("/proc/[0-9]*", NULL, NULL, &globbuf)) != 0) { LogError("system statistic error -- glob failed: %d (%s)\n", rv, STRERROR); return 0; } treesize = globbuf.gl_pathc; /* Allocate the tree */ pt = xcalloc(sizeof(ProcessTree_T), treesize); /* Insert data from /proc directory */ for (i = 0; i < treesize; i++) { pid = atoi(globbuf.gl_pathv[i] + strlen("/proc/")); pt[i].pid = pid; /* get the actual time */ pt[i].time = get_float_time(); if (! read_proc_file(buf, sizeof(buf), "psinfo", pt[i].pid, NULL)) { pt[i].cputime = 0; pt[i].cpu_percent = 0; pt[i].mem_kbyte = 0; continue; } pt[i].ppid = psinfo->pr_ppid; pt[i].starttime = psinfo->pr_start.tv_sec; /* If we don't have any light-weight processes (LWP) then we are definitely a zombie */ if (psinfo->pr_nlwp == 0) { pt[i].status_flag = PROCESS_ZOMBIE; pt[i].cputime = 0; pt[i].cpu_percent = 0; pt[i].mem_kbyte = 0; continue; } pt[i].mem_kbyte = psinfo->pr_rssize; pt[i].cmdline = xstrdup(psinfo->pr_psargs); if (! pt[i].cmdline || ! *pt[i].cmdline) pt[i].cmdline = xstrdup(psinfo->pr_fname); if (! read_proc_file(buf, sizeof(buf), "status", pt[i].pid, NULL)) { pt[i].cputime = 0; pt[i].cpu_percent = 0; } else { memcpy(&pstatus, buf, sizeof(pstatus_t)); pt[i].cputime = (timestruc_to_tseconds(pstatus.pr_utime) + timestruc_to_tseconds(pstatus.pr_stime)); pt[i].cpu_percent = 0; } } *reference = pt; /* Free globbing buffer */ globfree(&globbuf); return treesize; }