X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fvserver-stat.c;h=2b55f1522be5c53b02b41eba5fc4036dcd1d055d;hb=HEAD;hp=49271413c05d322ad140dbb97bfc2d4363d7260e;hpb=60e7abd16144869d483db5ec516a7b9ea842727c;p=util-vserver.git diff --git a/src/vserver-stat.c b/src/vserver-stat.c index 4927141..2b55f15 100644 --- a/src/vserver-stat.c +++ b/src/vserver-stat.c @@ -24,6 +24,7 @@ #include "vserver.h" #include "util.h" #include "internal.h" +#include "pathconfig.h" #include @@ -42,6 +43,7 @@ #include #include #include +#include #define ENSC_WRAPPERS_DIRENT 1 #define ENSC_WRAPPERS_VSERVER 1 @@ -50,6 +52,7 @@ #include "wrappers.h" #define PROC_DIR_NAME "/proc" +#define PROC_VIRT_DIR_NAME "/proc/virtual" #define CTX_DIR_NAME "/var/run/vservers/" #define CTX_NAME_MAX_LEN 50 @@ -65,9 +68,9 @@ static unsigned long pagesize=0x42; struct XidData { xid_t xid; - int process_count; - int VmSize_total; - int VmRSS_total; + unsigned int process_count; + uint64_t VmSize_total; + uint64_t VmRSS_total; uint64_t start_time_oldest; uint64_t stime_total, utime_total; @@ -114,7 +117,7 @@ showHelp(char const *cmd) WRITE_STR(1, cmd); WRITE_MSG(1, "\n" - "Show informations about all the active context.\n\n" + "Show information about all active contexts.\n\n" " CTX# Context number\n" " #0 = root context\n" " #1 = monitoring context\n" @@ -187,6 +190,12 @@ getUptime() return secs*1000 + msecs; } +static inline uint64_t +toMsec(uint64_t v) +{ + return v*1000llu/hertz; +} + static int cmpData(void const *xid_v, void const *map_v) { @@ -223,10 +232,269 @@ registerXid(struct Vector *vec, struct process_info *process) res->start_time_oldest = MIN(res->start_time_oldest, process->start_time); } -static inline uint64_t -toMsec(uint64_t v) +static void +registerXidVstat(struct Vector *vec, unsigned long xid_l) { - return v*1000llu/hertz; + xid_t xid = (xid_t) xid_l; + struct XidData *res; + struct vc_rlimit_stat limit[3]; + struct vc_virt_stat vstat; + struct vc_sched_info sched; + int cpu; + + res = Vector_search(vec, &xid, cmpData); + if (res!=0) { + WRITE_MSG(2, "Duplicate xid found?!\n"); + return; + } + if (vc_virt_stat(xid, &vstat) == -1) { + perror("vc_virt_stat()"); + return; + } + if (vc_rlimit_stat(xid, RLIMIT_NPROC, &limit[0]) == -1) { + perror("vc_rlimit_stat(RLIMIT_NRPOC)"); + return; + } + if (vc_rlimit_stat(xid, RLIMIT_AS, &limit[1]) == -1) { + perror("vc_rlimit_stat(RLIMIT_AS)"); + return; + } + if (vc_rlimit_stat(xid, RLIMIT_RSS, &limit[2]) == -1) { + perror("vc_rlimit_stat(RLIMIT_RSS)"); + return; + } + + res = Vector_insert(vec, &xid, cmpData); + res->xid = xid; + + res->process_count = limit[0].value; + res->VmSize_total = limit[1].value * pagesize; + res->VmRSS_total = limit[2].value; + res->start_time_oldest= getUptime() - vstat.uptime/1000000; + + res->utime_total = 0; + res->stime_total = 0; + // XXX: arbitrary CPU limit. + for (cpu = 0; cpu < 1024; cpu++) { + sched.cpu_id = cpu; + sched.bucket_id = 0; + if (vc_sched_info(xid, &sched) == -1) + break; + + res->utime_total += sched.user_msec; + res->stime_total += sched.sys_msec; + } +} + +static void +registerXidCgroups(struct Vector *vec, struct process_info *process) +{ + xid_t xid = (xid_t) process->s_context; + struct XidData *res; + + switch (vc_getXIDType(xid)) { + case vcTYPE_STATIC: + case vcTYPE_DYNAMIC: + break; + default: + return; + } + + res = Vector_search(vec, &xid, cmpData); + if (res == 0) { + struct vc_rlimit_stat limit; + struct vc_virt_stat vstat; + struct vc_sched_info sched; + int cpu; + char vhi_name[65], + filename[128], + cgroup[129], + name[129], + buf[30]; + int fd; + ssize_t cgroup_len, name_len; + unsigned long long rss = 0; + char *endptr; + ssize_t len; + unsigned long long stime_total, utime_total; + int per_ss = 0; + FILE *fp; + + + if (vc_virt_stat(xid, &vstat) == -1) { + perror("vc_virt_stat()"); + return; + } + if (vc_rlimit_stat(xid, RLIMIT_NPROC, &limit) == -1) { + perror("vc_rlimit_stat(RLIMIT_NRPOC)"); + return; + } + if (vc_get_vhi_name(xid, vcVHI_CONTEXT, vhi_name, sizeof(vhi_name)) == -1) { + perror("vc_get_vhi_name(CONTEXT)"); + return; + } + + if ((fd = open(DEFAULTCONFDIR "/cgroup/mnt", O_RDONLY)) == -1) { + if (utilvserver_isDirectory("/sys/fs/cgroup/memory", false)) { + strcpy(cgroup, "/sys/fs/cgroup/"); + cgroup_len = sizeof("/sys/fs/cgroup"); + per_ss = 1; + } else { + strcpy(cgroup, "/dev/cgroup/"); + cgroup_len = sizeof("/dev/cgroup"); + } + } + else { + cgroup_len = read(fd, cgroup, sizeof(cgroup)); + if (cgroup_len == -1) { + perror("read(cgroup/mnt)"); + return; + } + if (cgroup_len > 0) { + close(fd); + while (cgroup[cgroup_len - 1] == '\n' || cgroup[cgroup_len - 1] == '\r') + cgroup_len--; + cgroup[cgroup_len] = '/'; + cgroup_len += 1; + cgroup[cgroup_len] = 0; + } + } + + if ((fd = open(DEFAULTCONFDIR "/cgroup/base", O_RDONLY)) != -1) { + len = read(fd, cgroup + cgroup_len, sizeof(cgroup) - cgroup_len); + if (len == -1) { + perror("read(cgroup/base)"); + return; + } + close(fd); + if (len > 0) { + while (cgroup[cgroup_len + len - 1] == '\n' || cgroup[cgroup_len + len - 1] == '\r') + len--; + cgroup_len += len; + if (cgroup[cgroup_len - 1] != '/') { + cgroup[cgroup_len] = '/'; + cgroup_len += 1; + } + cgroup[cgroup_len] = 0; + } + } + + if (access(DEFAULTCONFDIR "/cgroup/per-ss", F_OK) == 0) + per_ss = 1; + + len = strlen(vhi_name); + if ((len + sizeof("/cgroup/name")) >= sizeof(filename)) { + WRITE_MSG(2, "too long context name: "); + WRITE_STR(2, vhi_name); + WRITE_MSG(2, "\n"); + return; + } + strcpy(filename, vhi_name); + strcpy(filename + len, "/cgroup/name"); + + if ((fd = open(filename, O_RDONLY)) == -1) { + char *dir = strrchr(vhi_name, '/'); + if (dir == NULL) { + WRITE_MSG(2, "invalid context name: "); + WRITE_STR(2, vhi_name); + WRITE_MSG(2, "\n"); + return; + } + name_len = strlen(dir); + if (name_len >= sizeof(name)) { + WRITE_MSG(2, "cgroup name too long: "); + WRITE_STR(2, dir); + WRITE_MSG(2, "\n"); + return; + } + strcpy(name, dir); + } + else { + name_len = read(fd, name, sizeof(name)); + if (name_len == -1) { + perror("read(cgroup/name)"); + return; + } + if (name_len > 0) { + while (name[name_len - 1] == '\n' || name[name_len - 1] == '\r') + name_len--; + name[name_len] = '\0'; + } + close(fd); + } + + if ((cgroup_len + name_len + sizeof("/memory/memory.stat")) > sizeof(filename)) { + WRITE_MSG(2, "cgroup name too long: "); + WRITE_STR(2, cgroup); + WRITE_MSG(2, "\n"); + return; + } + snprintf(filename, sizeof(filename), "%s%s%s/memory.stat", cgroup, (per_ss ? "/memory" : ""), name); + + if ((fp = fopen(filename, "r")) == NULL) + perror("open(memory.stat)"); + else { + unsigned long long _rss = 0, _mapped_file = 0; + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (strncmp(buf, "rss ", 4) == 0) { + if ((_rss = strtoull(buf + 4, &endptr, 0)) == ULLONG_MAX || + (*endptr != '\n' && *endptr != '\0')) { + perror("strtoull(memory.stat:rss)"); + return; + } + } + else if (strncmp(buf, "mapped_file ", 12) == 0) { + if ((_mapped_file = strtoull(buf + 12, &endptr, 0)) == ULLONG_MAX || + (*endptr != '\n' && *endptr != '\0')) { + perror("strtoull(memory.stat:mapped_file)"); + return; + } + } + } + rss = _rss + _mapped_file; + } + + snprintf(filename, sizeof(filename), "%s%s%s/cpuacct.stat", cgroup, (per_ss ? "/cpuacct" : ""), name); + + if ((fd = open(filename, O_RDONLY)) == -1) { + utime_total = 0; + stime_total = 0; + // XXX: arbitrary CPU limit. + for (cpu = 0; cpu < 1024; cpu++) { + sched.cpu_id = cpu; + sched.bucket_id = 0; + if (vc_sched_info(xid, &sched) == -1) + break; + + utime_total += sched.user_msec; + stime_total += sched.sys_msec; + } + } + else { + if (read(fd, buf, sizeof(buf)) == -1) { + perror("read(cpuacct.stat)"); + return; + } + close(fd); + + if (sscanf(buf, "user %llu\nsystem %llu\n", &utime_total, &stime_total) != 2) { + perror("sscanf(cpuacct.stat)"); + return; + } + } + + res = Vector_insert(vec, &xid, cmpData); + res->xid = xid; + + res->process_count = limit.value; + res->VmRSS_total = rss / 4096; + res->start_time_oldest= getUptime() - vstat.uptime/1000000; + + res->utime_total = toMsec(utime_total); + res->stime_total = toMsec(stime_total); + } + + res->VmSize_total += process->VmSize; } @@ -543,7 +811,7 @@ int main(int argc, char **argv) default : WRITE_MSG(2, "Try '"); WRITE_STR(2, argv[0]); - WRITE_MSG(2, " --help\" for more information.\n"); + WRITE_MSG(2, " --help' for more information.\n"); return EXIT_FAILURE; break; } @@ -557,36 +825,57 @@ int main(int argc, char **argv) if (hertz==0x42) initHertz(); if (pagesize==0x42) initPageSize(); - my_pid = getpid(); + Vector_init(&xid_data, sizeof(struct XidData)); - if (!switchToWatchXid(&errptr)) { - perror(errptr); - exit(1); + if (vc_isSupported(vcFEATURE_VSTAT)) { + unsigned long xid; + Echdir(PROC_VIRT_DIR_NAME); + proc_dir = Eopendir("."); + while ((dir_entry = readdir(proc_dir)) != NULL) { + if (!isNumberUnsigned(dir_entry->d_name, &xid, false)) + continue; + + registerXidVstat(&xid_data, xid); + } + closedir(proc_dir); } + else { + void (*handler)(struct Vector *vec, struct process_info *process); + + my_pid = getpid(); - if (access("/proc/uptime",R_OK)==-1 && errno==ENOENT) - WRITE_MSG(2, + if (!switchToWatchXid(&errptr)) { + perror(errptr); + exit(1); + } + + if (access("/proc/uptime",R_OK)==-1 && errno==ENOENT) + WRITE_MSG(2, "WARNING: can not access /proc/uptime. Usually, this is caused by\n" " procfs-security. Please read the FAQ for more details\n" " http://linux-vserver.org/Proc-Security\n"); - Vector_init(&xid_data, sizeof(struct XidData)); + if (vc_isSupported(vcFEATURE_MEMCG)) + handler = registerXidCgroups; + else + handler = registerXid; - Echdir(PROC_DIR_NAME); - proc_dir = Eopendir("."); - while ((dir_entry = readdir(proc_dir)) != NULL) - { + Echdir(PROC_DIR_NAME); + proc_dir = Eopendir("."); + while ((dir_entry = readdir(proc_dir)) != NULL) + { // select only process file - if (!isdigit(*dir_entry->d_name)) - continue; + if (!isdigit(*dir_entry->d_name)) + continue; - if (atoi(dir_entry->d_name) != my_pid) { - struct process_info * info = get_process_info(dir_entry->d_name); - if (info) - registerXid(&xid_data, info); + if (atoi(dir_entry->d_name) != my_pid) { + struct process_info * info = get_process_info(dir_entry->d_name); + if (info) + handler(&xid_data, info); + } } + closedir(proc_dir); } - closedir(proc_dir); Vector_foreach(&xid_data, fillName, 0);