3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 // based on vserver-stat.cc by Guillaum Dallaire and Jacques Gelinas
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <ensc_vector/vector.h>
35 #include <sys/types.h>
43 #include <sys/param.h>
45 #define ENSC_WRAPPERS_DIRENT 1
46 #define ENSC_WRAPPERS_VSERVER 1
47 #define ENSC_WRAPPERS_FCNTL 1
48 #define ENSC_WRAPPERS_UNISTD 1
51 #define PROC_DIR_NAME "/proc"
52 #define CTX_DIR_NAME "/var/run/vservers/"
53 #define CTX_NAME_MAX_LEN 50
55 int wrapper_exit_code = 1;
58 #define AT_CLKTCK 17 /* frequency of times() */
61 static unsigned long hertz=0x42;
69 uint64_t start_time_oldest;
70 uint64_t stime_total, utime_total;
75 long VmSize; // number of pages of virtual memory
76 long VmRSS; // resident set size from /proc/#/stat
77 uint64_t start_time; // start time of process -- milliseconds since 1-1-70
78 uint64_t stime, utime; // kernel & user-mode CPU time accumulated by process
79 uint64_t cstime, cutime; // cumulative time of process and reaped children
84 enum { tpUNSET, tpCTX, tpPID } type;
87 unsigned int interval;
95 showHelp(int fd, char const *cmd, int res)
97 WRITE_MSG(fd, "Usage: ");
101 "Show informations about all the active context.\n\n"
102 " CTX# Context number\n"
103 " #0 = root context\n"
104 " #1 = monitoring context\n"
105 " PROC QTY Quantity of processes in each context\n"
106 " VSZ Number of pages of virtual memory\n"
107 " RSS Resident set size\n"
108 " userTIME User-mode CPU time accumulated\n"
109 " sysTIME Kernel-mode CPU time accumulated\n"
110 " UPTIME Uptime/context\n"
111 " NAME Virtual server name\n"
120 "vserver-stat " VERSION " -- show virtual context statistics\n"
121 "This program is part of " PACKAGE_STRING "\n\n"
122 "Copyright (C) 2003 Enrico Scholz\n"
123 VERSION_COPYRIGHT_DISCLAIMER);
128 // return uptime (in ms) from /proc/uptime
139 // open the /proc/uptime file
140 fd = EopenD("/proc/uptime", O_RDONLY, 0);
141 len = Eread(fd, buffer, sizeof buffer);
143 if (len==sizeof(buffer)) {
144 WRITE_MSG(2, "Too much data in /proc/uptime; aborting...\n");
149 while (len>0 && buffer[len-1]=='\n') --len;
152 secs = strtol(buffer, &errptr, 10);
153 if (*errptr!='.') errptr = buffer;
156 switch (strlen(errptr+1)) {
157 case 0 : mult = 1000; break;
158 case 1 : mult = 100; break;
159 case 2 : mult = 10; break;
160 case 3 : mult = 1; break;
161 default : mult = 0; break;
163 msecs = strtol(errptr+1, &errptr, 10) * mult;
166 if ((*errptr!='\0' && *errptr!=' ') || errptr==buffer) {
167 WRITE_MSG(2, "Bad data in /proc/uptime\n");
171 return secs*1000 + msecs;
175 cmpData(void const *xid_v, void const *map_v)
177 xid_t const * const xid = xid_v;
178 struct XidData const * const map = map_v;
179 int res = *xid - map->xid;
185 registerXid(struct Vector *vec, struct process_info *process)
189 res = Vector_search(vec, &process->s_context, cmpData);
191 res = Vector_insert(vec, &process->s_context, cmpData);
192 res->xid = process->s_context;
193 res->process_count = 0;
194 res->VmSize_total = 0;
195 res->VmRSS_total = 0;
196 res->utime_total = 0;
197 res->stime_total = 0;
198 res->start_time_oldest = process->start_time;
201 ++res->process_count;
202 res->VmSize_total += process->VmSize;
203 res->VmRSS_total += process->VmRSS;
204 res->utime_total += process->utime + process->cutime;
205 res->stime_total += process->stime + process->cstime;
207 res->start_time_oldest = MIN(res->start_time_oldest, process->start_time);
210 static inline uint64_t
213 return v*1000llu/hertz;
217 // shamelessly stolen from procps...
219 find_elf_note(unsigned long findme){
220 unsigned long *ep = (unsigned long *)environ;
223 if(ep[0]==findme) return ep[1];
226 return (unsigned long)(-1);
229 static void initHertz() __attribute__((__constructor__));
234 hertz = find_elf_note(AT_CLKTCK);
235 if (hertz==(unsigned long)(-1))
236 hertz = sysconf(_SC_CLK_TCK);
239 // open the process's status file to get the ctx number, and other stat
240 struct process_info *
241 get_process_info(char *pid)
246 size_t idx, l=strlen(pid);
247 static struct process_info process;
250 process.s_context = vc_get_task_xid(atoi(pid));
252 # warning Compiling in debug-code
253 process.s_context = random()%6;
256 if (process.s_context==VC_NOCTX) {
258 WRITE_MSG(2, "vc_get_task_xid(");
261 WRITE_STR(2, strerror(err));
267 memcpy(buffer, "/proc/", 6); idx = 6;
268 memcpy(buffer+idx, pid, l); idx += l;
269 memcpy(buffer+idx, "/stat", 6);
271 // open the /proc/#/stat file
272 if ((fd = open(buffer, O_RDONLY, 0)) == -1)
274 // put the file in a buffer
275 if (read(fd, buffer, sizeof(buffer)) < 1)
280 p = strchr(buffer, ')'); // go after the PID (process_name)
281 for (idx = 0; idx<12 && *p!='\0'; ++p)
282 if ((*p)==' ') ++idx;
284 process.utime = toMsec(strtol(p, &p, 10));
285 process.stime = toMsec(strtol(p+1, &p, 10));
286 process.cutime = toMsec(strtol(p+1, &p, 10));
287 process.cstime = toMsec(strtol(p+1, &p, 10));
289 for (idx = 0; idx<5 && *p!='\0'; ++p)
290 if ((*p)==' ') ++idx;
292 process.start_time = toMsec(strtol(p, &p, 10));
293 process.VmSize = strtol(p+1, &p, 10);
294 process.VmRSS = strtol(p+1, &p, 10);
296 //printf("pid=%s, start_time=%llu\n", pid, process.start_time);
301 fillUintZero(char *buf, unsigned long val, size_t cnt)
305 l = utilvserver_fmt_ulong(buf, val);
307 memmove(buf+cnt-l, buf, l);
308 memset(buf, '0', cnt-l);
316 shortenMem(char *buf, unsigned long val)
318 char const * SUFFIXES[] = { " ", "K", "M", "G", "T", "+" };
320 char const * suffix = "+";
322 unsigned int mod = 0;
324 for (i=0; i<6; ++i) {
326 suffix = SUFFIXES[i];
329 mod = 10*(val & 1023)/1024;
333 if (val >9999) val=9999;
334 if (val>=1000) mod=0;
336 l = utilvserver_fmt_ulong(tmp, val);
339 l += utilvserver_fmt_ulong(tmp+l, mod);
341 i = 7-l-strlen(suffix);
343 memcpy(buf+i, tmp, l);
344 memcpy(buf+i+l, suffix, strlen(suffix));
348 shortenTime(char *buf, uint64_t t)
353 unsigned long hh, mm, ss, ms;
366 memcpy(ptr, "INVALID", 7);
370 ptr += utilvserver_fmt_ulong(ptr, t/365);
372 ptr += fillUintZero(ptr, t%365, 2);
374 ptr += fillUintZero(ptr, hh, 2);
377 ptr += utilvserver_fmt_ulong(ptr, t);
379 ptr += fillUintZero(ptr, hh, 2);
381 ptr += fillUintZero(ptr, mm, 2);
384 ptr += utilvserver_fmt_ulong(ptr, hh);
386 ptr += fillUintZero(ptr, mm, 2);
388 ptr += fillUintZero(ptr, ss, 2);
391 ptr += utilvserver_fmt_ulong(ptr, mm);
393 ptr += fillUintZero(ptr, ss, 2);
395 ptr += fillUintZero(ptr, ms, 2);
399 memcpy(buf+10-(ptr-tmp), tmp, ptr-tmp);
403 showContexts(struct Vector *vec)
405 uint64_t uptime = getUptime();
406 struct XidData const * ptr = Vector_begin_const(vec);
407 struct XidData const * const end_ptr = Vector_end_const(vec);
410 WRITE_MSG(1, "CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME\n");
411 for (; ptr<end_ptr; ++ptr) {
412 char buf[sizeof(xid_t)*3 + 512];
413 char tmp[sizeof(int)*3 + 2];
416 memset(buf, ' ', sizeof(buf));
417 l = utilvserver_fmt_long(buf, ptr->xid);
418 l = utilvserver_fmt_long(tmp, ptr->process_count);
419 memcpy(buf+10-l, tmp, l);
421 shortenMem (buf+10, ptr->VmSize_total);
422 shortenMem (buf+17, ptr->VmRSS_total);
423 shortenTime(buf+24, ptr->utime_total);
424 shortenTime(buf+34, ptr->stime_total);
425 //printf("%llu, %llu\n", uptime, ptr->start_time_oldest);
426 shortenTime(buf+44, uptime - ptr->start_time_oldest);
429 case 0 : strncpy(buf+55, "root server", 20); break;
430 case 1 : strncpy(buf+55, "monitoring server", 20); break;
434 vcCfgStyle cfgstyle = vcCFG_AUTO;
436 if ((cfgpath = vc_getVserverByCtx(ptr->xid, &cfgstyle, 0))!=0 &&
437 (name = vc_getVserverName(cfgpath, cfgstyle))!=0)
438 strncpy(buf+55, name, 20);
449 int main(int argc, char **argv)
452 struct dirent* dir_entry;
454 struct Vector xid_data;
458 if (strcmp(argv[1], "--help") ==0) showHelp(1, argv[0], 0);
459 if (strcmp(argv[1], "--version")==0) showVersion();
462 WRITE_MSG(2, "Unknown parameter, use '--help' for more information\n");
466 if (hertz==0x42) initHertz();
468 //printf("hertz=%lu\n", hertz);
469 // do not include own stat
472 if (!switchToWatchXid(&errptr)) {
477 Vector_init(&xid_data, sizeof(struct XidData));
479 Echdir(PROC_DIR_NAME);
480 proc_dir = Eopendir(".");
481 while ((dir_entry = readdir(proc_dir)) != NULL)
483 // select only process file
484 if (!isdigit(*dir_entry->d_name))
487 if (atoi(dir_entry->d_name) != my_pid) {
488 struct process_info * info = get_process_info(dir_entry->d_name);
490 registerXid(&xid_data, info);
495 // output the ctx_list
496 showContexts(&xid_data);
499 Vector_free(&xid_data);