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.
21 vserver-stat help you to see all the active context currently in the kernel
26 2003-01-08 Jacques Gelinas: Shows vserver description
27 2002-02-28 Jacques Gelinas: Use dynamic system call
28 2002-06-05 Martial Rioux : fix memory output error
29 2002-12-05 Martial Rioux : fix output glitch
30 2001-11-29 added uptime/ctx stat
31 2001-11-20 added vmsize, rss, stime and utime stat
41 #include <ensc_vector/vector.h>
48 #include <sys/types.h>
57 #define ENSC_WRAPPERS_DIRENT 1
58 #define ENSC_WRAPPERS_VSERVER 1
59 #define ENSC_WRAPPERS_FCNTL 1
60 #define ENSC_WRAPPERS_UNISTD 1
63 #define PROC_DIR_NAME "/proc"
64 #define CTX_DIR_NAME "/var/run/vservers/"
65 #define CTX_NAME_MAX_LEN 50
67 int wrapper_exit_code = 1;
75 long start_time_oldest;
76 long stime_total, utime_total;
81 long VmSize; // number of pages of virtual memory
82 long VmRSS; // resident set size from /proc/#/stat
83 long start_time; // start time of process -- seconds since 1-1-70
84 long stime, utime; // kernel & user-mode CPU time accumulated by process
85 long cstime, cutime; // cumulative time of process and reaped children
90 enum { tpUNSET, tpCTX, tpPID } type;
93 unsigned int interval;
101 showHelp(int fd, char const *cmd, int res)
103 WRITE_MSG(fd, "Usage: ");
107 "Show informations about all the active context.\n\n"
108 " CTX# Context number\n"
109 " #0 = root context\n"
110 " #1 = monitoring context\n"
111 " PROC QTY Quantity of processes in each context\n"
112 " VSZ Number of pages of virtual memory\n"
113 " RSS Resident set size\n"
114 " userTIME User-mode CPU time accumulated\n"
115 " sysTIME Kernel-mode CPU time accumulated\n"
116 " UPTIME Uptime/context\n"
117 " NAME Virtual server name\n"
126 "vserver-stat " VERSION " -- show virtual context statistics\n"
127 "This program is part of " PACKAGE_STRING "\n\n"
128 "Copyright (C) 2003 Enrico Scholz\n"
129 VERSION_COPYRIGHT_DISCLAIMER);
134 // return uptime (in ms) from /proc/uptime
145 // open the /proc/uptime file
146 fd = EopenD("/proc/uptime", O_RDONLY, 0);
147 len = Eread(fd, buffer, sizeof buffer);
149 if (len==sizeof(buffer)) {
150 WRITE_MSG(2, "Too much data in /proc/uptime; aborting...\n");
155 while (len>0 && buffer[len-1]=='\n') --len;
158 secs = strtol(buffer, &errptr, 10);
159 if (*errptr!='.') errptr = buffer;
160 else msecs = strtol(errptr+1, &errptr, 10);
162 if ((*errptr!='\0' && *errptr!=' ') || errptr==buffer) {
163 WRITE_MSG(2, "Bad data in /proc/uptime\n");
167 return secs*100 + msecs;
171 cmpData(void const *xid_v, void const *map_v)
173 xid_t const * const xid = xid_v;
174 struct XidData const * const map = map_v;
175 int res = *xid - map->xid;
181 registerXid(struct Vector *vec, struct process_info *process)
185 res = Vector_search(vec, &process->s_context, cmpData);
187 res = Vector_insert(vec, &process->s_context, cmpData);
188 res->xid = process->s_context;
189 res->process_count = 0;
190 res->VmSize_total = 0;
191 res->VmRSS_total = 0;
192 res->utime_total = 0;
193 res->stime_total = 0;
194 res->start_time_oldest = 0;
197 ++res->process_count;
198 res->VmSize_total += process->VmSize;
199 res->VmRSS_total += process->VmRSS;
200 res->utime_total += process->utime + process->cutime;
201 res->stime_total += process->stime + process->cstime;
203 if (res->start_time_oldest == 0) // first entry
204 res->start_time_oldest = process->start_time;
206 if (res->start_time_oldest > process->start_time)
207 res->start_time_oldest = process->start_time;
210 // open the process's status file to get the ctx number, and other stat
211 struct process_info *
212 get_process_info(char *pid)
217 size_t idx, l=strlen(pid);
218 static struct process_info process;
221 process.s_context = vc_get_task_xid(atoi(pid));
223 # warning Compiling in debug-code
224 process.s_context = random()%6;
227 if (process.s_context==VC_NOCTX) {
229 WRITE_MSG(2, "vc_get_task_xid(");
232 WRITE_STR(2, strerror(err));
238 memcpy(buffer, "/proc/", 6); idx = 6;
239 memcpy(buffer+idx, pid, l); idx += l;
240 memcpy(buffer+idx, "/stat", 6);
242 // open the /proc/#/stat file
243 if ((fd = open(buffer, O_RDONLY, 0)) == -1)
245 // put the file in a buffer
246 if (read(fd, buffer, sizeof(buffer)) < 1)
251 p = strchr(buffer, ')'); // go after the PID (process_name)
252 for (idx = 0; idx<12 && *p!='\0'; ++p)
253 if ((*p)==' ') ++idx;
255 process.utime = strtol(p, &p, 10);
256 process.stime = strtol(p+1, &p, 10);
257 process.cutime = strtol(p+1, &p, 10);
258 process.cstime = strtol(p+1, &p, 10);
260 for (idx = 0; idx<5 && *p!='\0'; ++p)
261 if ((*p)==' ') ++idx;
263 process.start_time = strtol(p, &p, 10);
264 process.VmSize = strtol(p+1, &p, 10);
265 process.VmRSS = strtol(p+1, &p, 10);
271 fillUintZero(char *buf, unsigned long val, size_t cnt)
275 l = utilvserver_fmt_ulong(buf, val);
277 memmove(buf+cnt-l, buf, l);
278 memset(buf, '0', cnt-l);
286 shortenMem(char *buf, unsigned long val)
288 char const * SUFFIXES[] = { " ", "K", "M", "G", "T", "+" };
290 char const * suffix = "+";
292 unsigned int mod = 0;
294 for (i=0; i<6; ++i) {
296 suffix = SUFFIXES[i];
299 mod = 10*(val & 1023)/1024;
303 if (val >9999) val=9999;
304 if (val>=1000) mod=0;
306 l = utilvserver_fmt_ulong(tmp, val);
309 l += utilvserver_fmt_ulong(tmp+l, mod);
311 i = 7-l-strlen(suffix);
313 memcpy(buf+i, tmp, l);
314 memcpy(buf+i+l, suffix, strlen(suffix));
318 shortenTime(char *buf, uint64_t t)
323 unsigned long hh, mm, ss, ms;
336 ptr += utilvserver_fmt_ulong(ptr, t);
338 ptr += fillUintZero(ptr, hh, 2);
340 ptr += fillUintZero(ptr, mm, 2);
343 ptr += utilvserver_fmt_ulong(ptr, hh);
345 ptr += fillUintZero(ptr, mm, 2);
347 ptr += fillUintZero(ptr, ss, 2);
350 ptr += utilvserver_fmt_ulong(ptr, mm);
352 ptr += fillUintZero(ptr, ss, 2);
354 ptr += fillUintZero(ptr, ms, 2);
358 memcpy(buf+10-(ptr-tmp), tmp, ptr-tmp);
362 showContexts(struct Vector *vec)
364 uint64_t uptime = getUptime();
365 struct XidData const * ptr = Vector_begin_const(vec);
366 struct XidData const * const end_ptr = Vector_end_const(vec);
369 WRITE_MSG(1, "CTX PROC VSZ RSS userTIME sysTIME UPTIME NAME\n");
370 for (; ptr<end_ptr; ++ptr) {
371 char buf[sizeof(xid_t)*3 + 512];
372 char tmp[sizeof(int)*3 + 2];
375 memset(buf, ' ', sizeof(buf));
376 l = utilvserver_fmt_long(buf, ptr->xid);
377 l = utilvserver_fmt_long(tmp, ptr->process_count);
378 memcpy(buf+10-l, tmp, l);
380 shortenMem (buf+10, ptr->VmSize_total);
381 shortenMem (buf+17, ptr->VmRSS_total);
382 shortenTime(buf+24, ptr->utime_total);
383 shortenTime(buf+34, ptr->stime_total);
384 shortenTime(buf+44, uptime - ptr->start_time_oldest);
387 case 0 : strncpy(buf+55, "root server", 20); break;
388 case 1 : strncpy(buf+55, "monitoring server", 20); break;
392 vcCfgStyle cfgstyle = vcCFG_AUTO;
394 if ((cfgpath = vc_getVserverByCtx(ptr->xid, &cfgstyle, 0))!=0 &&
395 (name = vc_getVserverName(cfgpath, cfgstyle))!=0)
396 strncpy(buf+55, name, 20);
407 int main(int argc, char **argv)
410 struct dirent* dir_entry;
412 struct Vector xid_data;
415 if (strcmp(argv[1], "--help") ==0) showHelp(1, argv[0], 0);
416 if (strcmp(argv[1], "--version")==0) showVersion();
419 WRITE_MSG(2, "Unknown parameter, use '--help' for more information\n");
423 // do not include own stat
427 // try to switch in context 1
428 if (vc_get_task_xid(0)!=1)
429 Evc_new_s_context(1, 0,0);
431 # warning Compiling in debug-code
434 Vector_init(&xid_data, sizeof(struct XidData));
436 Echdir(PROC_DIR_NAME);
437 proc_dir = Eopendir(".");
438 while ((dir_entry = readdir(proc_dir)) != NULL)
440 // select only process file
441 if (!isdigit(*dir_entry->d_name))
444 if (atoi(dir_entry->d_name) != my_pid) {
445 struct process_info * info = get_process_info(dir_entry->d_name);
447 registerXid(&xid_data, info);
452 // output the ctx_list
453 showContexts(&xid_data);
456 Vector_free(&xid_data);