1 1.1 christos /* 2 1.1 christos * Copyright (c) 1984 through 2008, William LeFebvre 3 1.1 christos * All rights reserved. 4 1.1 christos * 5 1.1 christos * Redistribution and use in source and binary forms, with or without 6 1.1 christos * modification, are permitted provided that the following conditions are met: 7 1.1 christos * 8 1.1 christos * * Redistributions of source code must retain the above copyright 9 1.1 christos * notice, this list of conditions and the following disclaimer. 10 1.1 christos * 11 1.1 christos * * Redistributions in binary form must reproduce the above 12 1.1 christos * copyright notice, this list of conditions and the following disclaimer 13 1.1 christos * in the documentation and/or other materials provided with the 14 1.1 christos * distribution. 15 1.1 christos * 16 1.1 christos * * Neither the name of William LeFebvre nor the names of other 17 1.1 christos * contributors may be used to endorse or promote products derived from 18 1.1 christos * this software without specific prior written permission. 19 1.1 christos * 20 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 1.1 christos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 1.1 christos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 1.1 christos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 1.1 christos * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 1.1 christos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 1.1 christos * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 1.1 christos * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 christos */ 32 1.1 christos 33 1.1 christos /* 34 1.1 christos * top - a top users display for Unix 35 1.1 christos * 36 1.1 christos * SYNOPSIS: PowerPC running AIX 5.1 or higher 37 1.1 christos * 38 1.1 christos * DESCRIPTION: 39 1.1 christos * This is the machine-dependent module for AIX 5.1 and higher (may work on 40 1.1 christos * older releases too). It is currently only tested on PowerPC 41 1.1 christos * architectures. 42 1.1 christos * 43 1.1 christos * TERMCAP: -lcurses 44 1.1 christos * 45 1.1 christos * CFLAGS: -DORDER -DHAVE_GETOPT -DHAVE_STRERROR -DMAXPROCS=10240 46 1.1 christos * 47 1.1 christos * LIBS: -lperfstat 48 1.1 christos * 49 1.1 christos * AUTHOR: Joep Vesseur <joep (at) fwi.uva.nl> 50 1.1 christos * 51 1.1 christos * PATCHES: Antoine Tabary <tabary (at) bruyeres.cea.fr>, Dan Nelson <dnelson (at) allantgroup.com> 52 1.1 christos */ 53 1.1 christos 54 1.1 christos #define MAXPROCS 10240 55 1.1 christos 56 1.1 christos #include "config.h" 57 1.1 christos 58 1.1 christos #include <time.h> 59 1.1 christos #include <stdlib.h> 60 1.1 christos #include <string.h> 61 1.1 christos #include <stdio.h> 62 1.1 christos #include <fcntl.h> 63 1.1 christos #include <nlist.h> 64 1.1 christos #include <procinfo.h> 65 1.1 christos #include <sys/types.h> 66 1.1 christos #include <sys/proc.h> 67 1.1 christos #include <sys/sysinfo.h> 68 1.1 christos #include <sys/sysconfig.h> 69 1.1 christos #include <pwd.h> 70 1.1 christos #include <errno.h> 71 1.1 christos #include <libperfstat.h> 72 1.1 christos #include "top.h" 73 1.1 christos #include "machine.h" 74 1.1 christos #include "utils.h" 75 1.1 christos 76 1.1 christos 77 1.1 christos #define PROCRESS(p) (((p)->pi_trss + (p)->pi_drss)*4) 78 1.1 christos #define PROCSIZE(p) (((p)->pi_tsize/1024+(p)->pi_dvm)*4) 79 1.1 christos #define PROCTIME(pi) (pi->pi_ru.ru_utime.tv_sec + pi->pi_ru.ru_stime.tv_sec) 80 1.1 christos 81 1.1 christos #ifdef OLD 82 1.1 christos /* 83 1.1 christos * structure definition taken from 'monitor' by Jussi Maki (jmaki (at) hut.fi) 84 1.1 christos */ 85 1.1 christos struct vmker { 86 1.1 christos uint n0,n1,n2,n3,n4,n5,n6,n7,n8; 87 1.1 christos uint totalmem; 88 1.1 christos uint badmem; /* this is used in RS/6000 model 220 */ 89 1.1 christos uint freemem; 90 1.1 christos uint n12; 91 1.1 christos uint numperm; /* this seems to keep other than text and data segment 92 1.1 christos usage; name taken from /usr/lpp/bos/samples/vmtune.c */ 93 1.1 christos uint totalvmem,freevmem; 94 1.1 christos uint n15, n16, n17, n18, n19; 95 1.1 christos }; 96 1.1 christos 97 1.1 christos #define KMEM "/dev/kmem" 98 1.1 christos 99 1.1 christos /* Indices in the nlist array */ 100 1.1 christos #define X_AVENRUN 0 101 1.1 christos #define X_SYSINFO 1 102 1.1 christos #define X_VMKER 2 103 1.1 christos #define X_V 3 104 1.1 christos 105 1.1 christos static struct nlist nlst[] = { 106 1.1 christos { "avenrun", 0, 0, 0, 0, 0 }, /* 0 */ 107 1.1 christos { "sysinfo", 0, 0, 0, 0, 0 }, /* 1 */ 108 1.1 christos { "vmker", 0, 0, 0, 0, 0 }, /* 2 */ 109 1.1 christos { "v", 0, 0, 0, 0, 0 }, /* 3 */ 110 1.1 christos { NULL, 0, 0, 0, 0, 0 } 111 1.1 christos }; 112 1.1 christos 113 1.1 christos #endif 114 1.1 christos 115 1.1 christos /* get_process_info returns handle. definition is here */ 116 1.1 christos struct handle 117 1.1 christos { 118 1.1 christos struct procentry64 **next_proc; 119 1.1 christos int remaining; 120 1.1 christos }; 121 1.1 christos 122 1.1 christos /* 123 1.1 christos * These definitions control the format of the per-process area 124 1.1 christos */ 125 1.1 christos static char header[] = 126 1.1 christos " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 127 1.1 christos /* 0123456 -- field to fill in starts at header+6 */ 128 1.1 christos #define UNAME_START 7 129 1.1 christos 130 1.1 christos #define Proc_format \ 131 1.1 christos "%6d %-8.8s %3d %4d %5d%c %4d%c %-5s %6s %5.2f%% %5.2f%% %.14s%s" 132 1.1 christos 133 1.1 christos 134 1.1 christos /* these are for detailing the process states */ 135 1.1 christos int process_states[9]; 136 1.1 christos char *procstatenames[] = { 137 1.1 christos " none, ", " sleeping, ", " state2, ", " runnable, ", 138 1.1 christos " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ", 139 1.1 christos NULL 140 1.1 christos }; 141 1.1 christos 142 1.1 christos /* these are for detailing the cpu states */ 143 1.1 christos int cpu_states[CPU_NTIMES]; 144 1.1 christos char *cpustatenames[] = { 145 1.1 christos "idle", "user", "kernel", "wait", 146 1.1 christos NULL 147 1.1 christos }; 148 1.1 christos 149 1.1 christos /* these are for detailing the memory statistics */ 150 1.1 christos long memory_stats[7]; 151 1.1 christos char *memorynames[] = { 152 1.1 christos "K total, ", "K buf, ", "K sys, ", "K free", NULL 153 1.1 christos }; 154 1.1 christos #define M_REAL 0 155 1.1 christos #define M_BUFFERS 1 156 1.1 christos #define M_SYSTEM 2 157 1.1 christos #define M_REALFREE 3 158 1.1 christos 159 1.1 christos long swap_stats[3]; 160 1.1 christos char *swapnames[] = { 161 1.1 christos "K total, ", "K free", NULL 162 1.1 christos }; 163 1.1 christos #define M_VIRTUAL 0 164 1.1 christos #define M_VIRTFREE 1 165 1.1 christos 166 1.1 christos char *state_abbrev[] = { 167 1.1 christos NULL, NULL, NULL, NULL, "idle", "zomb", "stop", "run", "swap" 168 1.1 christos }; 169 1.1 christos 170 1.1 christos /* sorting orders. first is default */ 171 1.1 christos char *ordernames[] = { 172 1.1 christos "cpu", "size", "res", "time", "pri", NULL 173 1.1 christos }; 174 1.1 christos 175 1.1 christos /* compare routines */ 176 1.1 christos int compare_cpu(), compare_size(), compare_res(), compare_time(), 177 1.1 christos compare_prio(); 178 1.1 christos 179 1.1 christos int (*proc_compares[])() = { 180 1.1 christos compare_cpu, 181 1.1 christos compare_size, 182 1.1 christos compare_res, 183 1.1 christos compare_time, 184 1.1 christos compare_prio, 185 1.1 christos NULL 186 1.1 christos }; 187 1.1 christos 188 1.1 christos /* useful externals */ 189 1.1 christos long percentages(int cnt, int *out, long *new, long *old, long *diffs); 190 1.1 christos char *format_time(long seconds); 191 1.1 christos 192 1.1 christos #ifdef OLD 193 1.1 christos /* useful globals */ 194 1.1 christos int kmem; /* file descriptor */ 195 1.1 christos 196 1.1 christos /* offsets in kernel */ 197 1.1 christos static unsigned long avenrun_offset; 198 1.1 christos static unsigned long sysinfo_offset; 199 1.1 christos static unsigned long vmker_offset; 200 1.1 christos static unsigned long v_offset; 201 1.1 christos #endif 202 1.1 christos 203 1.1 christos /* used for calculating cpu state percentages */ 204 1.1 christos static long cp_time[CPU_NTIMES]; 205 1.1 christos static long cp_old[CPU_NTIMES]; 206 1.1 christos static long cp_diff[CPU_NTIMES]; 207 1.1 christos 208 1.1 christos /* the runqueue length is a cumulative value. keep old value */ 209 1.1 christos long old_runque; 210 1.1 christos 211 1.1 christos /* process info */ 212 1.1 christos struct kernvars v_info; /* to determine nprocs */ 213 1.1 christos int nprocs; /* maximum nr of procs in proctab */ 214 1.1 christos int ncpus; /* nr of cpus installed */ 215 1.1 christos 216 1.1 christos struct procentry64 *p_info; /* needed for vm and ru info */ 217 1.1 christos struct procentry64 **pref; /* processes selected for display */ 218 1.1 christos struct timeval64 *cpu_proc, *old_cpu_proc; /* total cpu used by each process */ 219 1.1 christos int pref_len; /* number of processes selected */ 220 1.1 christos 221 1.1 christos /* needed to calculate WCPU */ 222 1.1 christos unsigned long curtime; 223 1.1 christos 224 1.1 christos /* needed to calculate CPU */ 225 1.1 christos struct timeval curtimeval; 226 1.1 christos struct timeval lasttimeval; 227 1.1 christos 228 1.1 christos #ifdef OLD 229 1.1 christos int getkval(unsigned long offset, caddr_t ptr, int size, char *refstr); 230 1.1 christos #endif 231 1.1 christos 232 1.1 christos void *xmalloc(long size) 233 1.1 christos { 234 1.1 christos void *p = malloc(size); 235 1.1 christos if (!p) 236 1.1 christos { 237 1.1 christos fprintf(stderr,"Could not allocate %ld bytes: %s\n", size, strerror(errno)); 238 1.1 christos exit(1); 239 1.1 christos } 240 1.1 christos return p; 241 1.1 christos } 242 1.1 christos 243 1.1 christos /* 244 1.1 christos * Initialize globals, get kernel offsets and stuff... 245 1.1 christos */ 246 1.1 christos int machine_init(statics) 247 1.1 christos struct statics *statics; 248 1.1 christos { 249 1.1 christos #ifdef OLD 250 1.1 christos if ((kmem = open(KMEM, O_RDONLY)) == -1) { 251 1.1 christos perror(KMEM); 252 1.1 christos return -1; 253 1.1 christos } 254 1.1 christos 255 1.1 christos /* get kernel symbol offsets */ 256 1.1 christos if (knlist(nlst, 4, sizeof(struct nlist)) != 0) { 257 1.1 christos perror("knlist"); 258 1.1 christos return -1; 259 1.1 christos } 260 1.1 christos avenrun_offset = nlst[X_AVENRUN].n_value; 261 1.1 christos sysinfo_offset = nlst[X_SYSINFO].n_value; 262 1.1 christos vmker_offset = nlst[X_VMKER].n_value; 263 1.1 christos v_offset = nlst[X_V].n_value; 264 1.1 christos 265 1.1 christos getkval(v_offset, (caddr_t)&v_info, sizeof v_info, "v"); 266 1.1 christos #else 267 1.1 christos sysconfig(SYS_GETPARMS, &v_info, sizeof v_info); 268 1.1 christos #endif 269 1.1 christos ncpus = v_info.v_ncpus; /* number of cpus */ 270 1.1 christos 271 1.1 christos /* procentry64 is 4912 bytes, and PROCMASK(PIDMAX) is 262144. That'd 272 1.1 christos require 1.2gb for the p_info array, which is way overkill. Raise 273 1.1 christos MAXPROCS if you have more than 10240 active processes in the system. 274 1.1 christos */ 275 1.1 christos 276 1.1 christos #if 0 277 1.1 christos nprocs = PROCMASK(PIDMAX); 278 1.1 christos #else 279 1.1 christos nprocs = MAXPROCS; 280 1.1 christos #endif 281 1.1 christos 282 1.1 christos cpu_proc = (struct timeval64 *)xmalloc(PROCMASK(PIDMAX) * sizeof (struct timeval64)); 283 1.1 christos old_cpu_proc = (struct timeval64 *)xmalloc(PROCMASK(PIDMAX) * sizeof (struct timeval64)); 284 1.1 christos p_info = (struct procentry64 *)xmalloc(nprocs * sizeof (struct procentry64)); 285 1.1 christos pref = (struct procentry64 **)xmalloc(nprocs * sizeof (struct procentry64 *)); 286 1.1 christos 287 1.1 christos statics->procstate_names = procstatenames; 288 1.1 christos statics->cpustate_names = cpustatenames; 289 1.1 christos statics->memory_names = memorynames; 290 1.1 christos statics->swap_names = swapnames; 291 1.1 christos statics->order_names = ordernames; 292 1.1 christos 293 1.1 christos return(0); 294 1.1 christos } 295 1.1 christos 296 1.1 christos char *format_header(uname_field) 297 1.1 christos register char *uname_field; 298 1.1 christos { 299 1.1 christos register char *ptr; 300 1.1 christos 301 1.1 christos ptr = header + UNAME_START; 302 1.1 christos while (*uname_field != '\0') 303 1.1 christos { 304 1.1 christos *ptr++ = *uname_field++; 305 1.1 christos } 306 1.1 christos 307 1.1 christos return(header); 308 1.1 christos } 309 1.1 christos 310 1.1 christos 311 1.1 christos 312 1.1 christos 313 1.1 christos void get_system_info(si) 314 1.1 christos struct system_info *si; 315 1.1 christos { 316 1.1 christos #ifdef OLD 317 1.1 christos long long load_avg[3]; 318 1.1 christos struct sysinfo64 s_info; 319 1.1 christos struct vmker m_info; 320 1.1 christos #else 321 1.1 christos perfstat_memory_total_t m_info1; 322 1.1 christos perfstat_cpu_total_t s_info1; 323 1.1 christos #endif 324 1.1 christos int i; 325 1.1 christos int total = 0; 326 1.1 christos 327 1.1 christos #ifdef OLD 328 1.1 christos /* get the load avarage array */ 329 1.1 christos getkval(avenrun_offset, (caddr_t)load_avg, sizeof load_avg, "avenrun"); 330 1.1 christos 331 1.1 christos /* get the sysinfo structure */ 332 1.1 christos getkval(sysinfo_offset, (caddr_t)&s_info, sizeof s_info, "sysinfo64"); 333 1.1 christos 334 1.1 christos /* get vmker structure */ 335 1.1 christos getkval(vmker_offset, (caddr_t)&m_info, sizeof m_info, "vmker"); 336 1.1 christos #else 337 1.1 christos /* cpu stats */ 338 1.1 christos perfstat_cpu_total(NULL, &s_info1, sizeof s_info1, 1); 339 1.1 christos 340 1.1 christos /* memory stats */ 341 1.1 christos perfstat_memory_total(NULL, &m_info1, sizeof m_info1, 1); 342 1.1 christos #endif 343 1.1 christos 344 1.1 christos 345 1.1 christos #ifdef OLD 346 1.1 christos /* convert load avarages to doubles */ 347 1.1 christos for (i = 0; i < 3; i++) 348 1.1 christos si->load_avg[i] = (double)load_avg[i]/65536.0; 349 1.1 christos 350 1.1 christos /* calculate cpu state in percentages */ 351 1.1 christos for (i = 0; i < CPU_NTIMES; i++) { 352 1.1 christos cp_old[i] = cp_time[i]; 353 1.1 christos cp_time[i] = s_info.cpu[i]; 354 1.1 christos cp_diff[i] = cp_time[i] - cp_old[i]; 355 1.1 christos total += cp_diff[i]; 356 1.1 christos } 357 1.1 christos 358 1.1 christos #else 359 1.1 christos /* convert load avarages to doubles */ 360 1.1 christos for (i = 0; i < 3; i++) 361 1.1 christos si->load_avg[i] = (double)s_info1.loadavg[i]/(1<<SBITS); 362 1.1 christos 363 1.1 christos /* calculate cpu state in percentages */ 364 1.1 christos for (i = 0; i < CPU_NTIMES; i++) { 365 1.1 christos cp_old[i] = cp_time[i]; 366 1.1 christos cp_time[i] = ( i==CPU_IDLE?s_info1.idle: 367 1.1 christos i==CPU_USER?s_info1.user: 368 1.1 christos i==CPU_KERNEL?s_info1.sys: 369 1.1 christos i==CPU_WAIT?s_info1.wait:0); 370 1.1 christos cp_diff[i] = cp_time[i] - cp_old[i]; 371 1.1 christos total += cp_diff[i]; 372 1.1 christos } 373 1.1 christos #endif 374 1.1 christos for (i = 0; i < CPU_NTIMES; i++) { 375 1.1 christos cpu_states[i] = 1000 * cp_diff[i] / total; 376 1.1 christos } 377 1.1 christos 378 1.1 christos /* calculate memory statistics, scale 4K pages */ 379 1.1 christos #ifdef OLD 380 1.1 christos #define PAGE_TO_MB(a) ((a)*4/1024) 381 1.1 christos memory_stats[M_TOTAL] = PAGE_TO_MB(m_info.totalmem+m_info.totalvmem); 382 1.1 christos memory_stats[M_REAL] = PAGE_TO_MB(m_info.totalmem); 383 1.1 christos memory_stats[M_REALFREE] = PAGE_TO_MB(m_info.freemem); 384 1.1 christos memory_stats[M_BUFFERS] = PAGE_TO_MB(m_info.numperm); 385 1.1 christos swap_stats[M_VIRTUAL] = PAGE_TO_MB(m_info.totalvmem); 386 1.1 christos swap_stats[M_VIRTFREE] = PAGE_TO_MB(m_info.freevmem); 387 1.1 christos #else 388 1.1 christos #define PAGE_TO_KB(a) ((a)*4) 389 1.1 christos memory_stats[M_REAL] = PAGE_TO_KB(m_info1.real_total); 390 1.1 christos memory_stats[M_BUFFERS] = PAGE_TO_KB(m_info1.numperm); 391 1.1 christos #ifdef _AIXVERSION_520 392 1.1 christos memory_stats[M_SYSTEM] = PAGE_TO_KB(m_info1.real_system); 393 1.1 christos #endif 394 1.1 christos memory_stats[M_REALFREE] = PAGE_TO_KB(m_info1.real_free); 395 1.1 christos swap_stats[M_VIRTUAL] = PAGE_TO_KB(m_info1.pgsp_total); 396 1.1 christos swap_stats[M_VIRTFREE] = PAGE_TO_KB(m_info1.pgsp_free); 397 1.1 christos #endif 398 1.1 christos 399 1.1 christos /* runnable processes */ 400 1.1 christos #ifdef OLD 401 1.1 christos process_states[0] = s_info.runque - old_runque; 402 1.1 christos old_runque = s_info.runque; 403 1.1 christos #else 404 1.1 christos process_states[0] = s_info1.runque - old_runque; 405 1.1 christos old_runque = s_info1.runque; 406 1.1 christos #endif 407 1.1 christos 408 1.1 christos si->cpustates = cpu_states; 409 1.1 christos si->memory = memory_stats; 410 1.1 christos si->swap = swap_stats; 411 1.1 christos } 412 1.1 christos 413 1.1 christos static struct handle handle; 414 1.1 christos 415 1.1 christos caddr_t get_process_info(si, sel, compare_index) 416 1.1 christos struct system_info *si; 417 1.1 christos struct process_select *sel; 418 1.1 christos int compare_index; 419 1.1 christos { 420 1.1 christos int i, nproc; 421 1.1 christos int active_procs = 0, total_procs = 0; 422 1.1 christos struct procentry64 *pp, **p_pref = pref; 423 1.1 christos struct timeval64 *cpu_proc_temp; 424 1.1 christos double timediff; 425 1.1 christos pid_t procsindex = 0; 426 1.1 christos 427 1.1 christos si->procstates = process_states; 428 1.1 christos 429 1.1 christos curtime = time(0); 430 1.1 christos lasttimeval = curtimeval; 431 1.1 christos gettimeofday(&curtimeval, NULL); 432 1.1 christos 433 1.1 christos /* get the procentry64 structures of all running processes */ 434 1.1 christos nproc = getprocs64(p_info, sizeof (struct procentry64), NULL, 0, 435 1.1 christos &procsindex, nprocs); 436 1.1 christos if (nproc < 0) { 437 1.1 christos perror("getprocs64"); 438 1.1 christos quit(1); 439 1.1 christos } 440 1.1 christos 441 1.1 christos /* the swapper has no cmd-line attached */ 442 1.1 christos strcpy(p_info[0].pi_comm, "swapper"); 443 1.1 christos 444 1.1 christos if (lasttimeval.tv_sec) 445 1.1 christos { 446 1.1 christos timediff = (curtimeval.tv_sec - lasttimeval.tv_sec) + 447 1.1 christos 1.0*(curtimeval.tv_usec - lasttimeval.tv_usec) / uS_PER_SECOND; 448 1.1 christos } 449 1.1 christos 450 1.1 christos /* The pi_cpu value is wildly inaccurate. The maximum value is 120, but 451 1.1 christos when the scheduling timer fires, the field is zeroed for all 452 1.1 christos processes and ramps up over a short period of time. Instead of using 453 1.1 christos this weird number, manually calculate an accurate value from the 454 1.1 christos rusage data. Store this run's rusage in cpu_proc[pid], and subtract 455 1.1 christos from old_cpu_proc. 456 1.1 christos */ 457 1.1 christos for (pp = p_info, i = 0; i < nproc; pp++, i++) { 458 1.1 christos pid_t pid = PROCMASK(pp->pi_pid); 459 1.1 christos 460 1.1 christos /* total system and user time into cpu_proc */ 461 1.1 christos cpu_proc[pid] = pp->pi_ru.ru_utime; 462 1.1 christos cpu_proc[pid].tv_sec += pp->pi_ru.ru_stime.tv_sec; 463 1.1 christos cpu_proc[pid].tv_usec += pp->pi_ru.ru_stime.tv_usec; 464 1.1 christos if (cpu_proc[pid].tv_usec > NS_PER_SEC) { 465 1.1 christos cpu_proc[pid].tv_sec++; 466 1.1 christos cpu_proc[pid].tv_usec -= NS_PER_SEC; 467 1.1 christos } 468 1.1 christos 469 1.1 christos /* If this process was around during the previous update, calculate 470 1.1 christos a true %CPU. If not, convert the kernel's cpu value from its 471 1.1 christos 120-max value to a 10000-max one. 472 1.1 christos */ 473 1.1 christos if (old_cpu_proc[pid].tv_sec == 0 && old_cpu_proc[pid].tv_usec == 0) 474 1.1 christos pp->pi_cpu = pp->pi_cpu * 10000 / 120; 475 1.1 christos else 476 1.1 christos pp->pi_cpu = ((cpu_proc[pid].tv_sec - old_cpu_proc[pid].tv_sec) + 477 1.1 christos 1.0*(cpu_proc[pid].tv_usec - old_cpu_proc[pid].tv_usec) / NS_PER_SEC) / timediff * 10000; 478 1.1 christos } 479 1.1 christos 480 1.1 christos /* remember our current values as old_cpu_proc, and zero out cpu_proc 481 1.1 christos for the next update cycle */ 482 1.1 christos memset(old_cpu_proc, 0, sizeof(struct timeval64) * nprocs); 483 1.1 christos cpu_proc_temp = cpu_proc; 484 1.1 christos cpu_proc = old_cpu_proc; 485 1.1 christos old_cpu_proc = cpu_proc_temp; 486 1.1 christos 487 1.1 christos memset(process_states, 0, sizeof process_states); 488 1.1 christos 489 1.1 christos /* build a list of pointers to processes to show. */ 490 1.1 christos for (pp = p_info, i = 0; i < nproc; pp++, i++) { 491 1.1 christos 492 1.1 christos /* AIX marks all runnable processes as ACTIVE. We want to know 493 1.1 christos which processes are sleeping, so check used cpu and adjust status 494 1.1 christos field accordingly 495 1.1 christos */ 496 1.1 christos if (pp->pi_state == SACTIVE && pp->pi_cpu == 0) 497 1.1 christos pp->pi_state = SIDL; 498 1.1 christos 499 1.1 christos if (pp->pi_state && (sel->system || ((pp->pi_flags & SKPROC) == 0))) { 500 1.1 christos total_procs++; 501 1.1 christos process_states[pp->pi_state]++; 502 1.1 christos if ( (pp->pi_state != SZOMB) && 503 1.1 christos (sel->idle || pp->pi_cpu != 0 || (pp->pi_state == SACTIVE)) 504 1.1 christos && (sel->uid == -1 || pp->pi_uid == (uid_t)sel->uid)) { 505 1.1 christos *p_pref++ = pp; 506 1.1 christos active_procs++; 507 1.1 christos } 508 1.1 christos } 509 1.1 christos } 510 1.1 christos 511 1.1 christos /* the pref array now holds pointers to the procentry64 structures in 512 1.1 christos * the p_info array that were selected for display 513 1.1 christos */ 514 1.1 christos 515 1.1 christos /* sort if requested */ 516 1.1 christos if ( proc_compares[compare_index] != NULL) 517 1.1 christos qsort((char *)pref, active_procs, sizeof (struct procentry64 *), 518 1.1 christos proc_compares[compare_index]); 519 1.1 christos 520 1.1 christos si->last_pid = -1; /* no way to figure out last used pid */ 521 1.1 christos si->p_total = total_procs; 522 1.1 christos si->p_active = pref_len = active_procs; 523 1.1 christos 524 1.1 christos handle.next_proc = pref; 525 1.1 christos handle.remaining = active_procs; 526 1.1 christos 527 1.1 christos return((caddr_t)&handle); 528 1.1 christos } 529 1.1 christos 530 1.1 christos char fmt[128]; /* static area where result is built */ 531 1.1 christos 532 1.1 christos /* define what weighted cpu is. use definition of %CPU from 'man ps(1)' */ 533 1.1 christos #define weighted_cpu(pp) (PROCTIME(pp) == 0 ? 0.0 : \ 534 1.1 christos (((PROCTIME(pp)*100.0)/(curtime-pi->pi_start)))) 535 1.1 christos 536 1.1 christos char *format_next_process(handle, get_userid) 537 1.1 christos caddr_t handle; 538 1.1 christos char *(*get_userid)(); 539 1.1 christos { 540 1.1 christos register struct handle *hp; 541 1.1 christos register struct procentry64 *pi; 542 1.1 christos long cpu_time; 543 1.1 christos int proc_size, proc_ress; 544 1.1 christos char size_unit = 'K'; 545 1.1 christos char ress_unit = 'K'; 546 1.1 christos 547 1.1 christos hp = (struct handle *)handle; 548 1.1 christos if (hp->remaining == 0) { /* safe guard */ 549 1.1 christos fmt[0] = '\0'; 550 1.1 christos return fmt; 551 1.1 christos } 552 1.1 christos pi = *(hp->next_proc++); 553 1.1 christos hp->remaining--; 554 1.1 christos 555 1.1 christos cpu_time = PROCTIME(pi); 556 1.1 christos 557 1.1 christos /* we disply sizes up to 10M in KiloBytes, beyond 10M in MegaBytes */ 558 1.1 christos if ((proc_size = (pi->pi_tsize/1024+pi->pi_dvm)*4) > 10240) { 559 1.1 christos proc_size /= 1024; 560 1.1 christos size_unit = 'M'; 561 1.1 christos } 562 1.1 christos if ((proc_ress = (pi->pi_trss + pi->pi_drss)*4) > 10240) { 563 1.1 christos proc_ress /= 1024; 564 1.1 christos ress_unit = 'M'; 565 1.1 christos } 566 1.1 christos 567 1.1 christos sprintf(fmt, Proc_format , 568 1.1 christos pi->pi_pid, /* PID */ 569 1.1 christos (*get_userid)(pi->pi_uid), /* login name */ 570 1.1 christos pi->pi_nice, /* fixed or vari */ 571 1.1 christos getpriority(PRIO_PROCESS, pi->pi_pid), 572 1.1 christos proc_size, /* size */ 573 1.1 christos size_unit, /* K or M */ 574 1.1 christos proc_ress, /* resident */ 575 1.1 christos ress_unit, /* K or M */ 576 1.1 christos state_abbrev[pi->pi_state], /* process state */ 577 1.1 christos format_time(cpu_time), /* time used */ 578 1.1 christos weighted_cpu(pi), /* WCPU */ 579 1.1 christos pi->pi_cpu / 100.0, /* CPU */ 580 1.1 christos printable(pi->pi_comm), /* COMM */ 581 1.1 christos (pi->pi_flags & SKPROC) == 0 ? "" : " (sys)" /* kernel process? */ 582 1.1 christos ); 583 1.1 christos return(fmt); 584 1.1 christos } 585 1.1 christos 586 1.1 christos #ifdef OLD 587 1.1 christos /* 588 1.1 christos * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 589 1.1 christos * "offset" is the byte offset into the kernel for the desired value, 590 1.1 christos * "ptr" points to a buffer into which the value is retrieved, 591 1.1 christos * "size" is the size of the buffer (and the object to retrieve), 592 1.1 christos * "refstr" is a reference string used when printing error meessages, 593 1.1 christos * if "refstr" starts with a '!', then a failure on read will not 594 1.1 christos * be fatal (this may seem like a silly way to do things, but I 595 1.1 christos * really didn't want the overhead of another argument). 596 1.1 christos * 597 1.1 christos */ 598 1.1 christos int getkval(offset, ptr, size, refstr) 599 1.1 christos unsigned long offset; 600 1.1 christos caddr_t ptr; 601 1.1 christos int size; 602 1.1 christos char *refstr; 603 1.1 christos { 604 1.1 christos int upper_2gb = 0; 605 1.1 christos 606 1.1 christos /* reads above 2Gb are done by seeking to offset%2Gb, and supplying 607 1.1 christos * 1 (opposed to 0) as fourth parameter to readx (see 'man kmem') 608 1.1 christos */ 609 1.1 christos if (offset > 1<<31) { 610 1.1 christos upper_2gb = 1; 611 1.1 christos offset &= 0x7fffffff; 612 1.1 christos } 613 1.1 christos 614 1.1 christos if (lseek(kmem, offset, SEEK_SET) != offset) { 615 1.1 christos fprintf(stderr, "top: lseek failed\n"); 616 1.1 christos quit(2); 617 1.1 christos } 618 1.1 christos 619 1.1 christos if (readx(kmem, ptr, size, upper_2gb) != size) { 620 1.1 christos if (*refstr == '!') 621 1.1 christos return 0; 622 1.1 christos else { 623 1.1 christos fprintf(stderr, "top: kvm_read for %s: %s\n", refstr, 624 1.1 christos sys_errlist[errno]); 625 1.1 christos quit(2); 626 1.1 christos } 627 1.1 christos } 628 1.1 christos 629 1.1 christos return 1 ; 630 1.1 christos } 631 1.1 christos #endif 632 1.1 christos 633 1.1 christos /* comparison routine for qsort */ 634 1.1 christos /* 635 1.1 christos * The following code is taken from the solaris module and adjusted 636 1.1 christos * for AIX -- JV . 637 1.1 christos */ 638 1.1 christos 639 1.1 christos #define ORDERKEY_PCTCPU \ 640 1.1 christos if ((result = pi2->pi_cpu - pi1->pi_cpu) == 0) 641 1.1 christos 642 1.1 christos #define ORDERKEY_CPTICKS \ 643 1.1 christos if ((result = PROCTIME(pi2) - PROCTIME(pi1)) == 0) 644 1.1 christos 645 1.1 christos #define ORDERKEY_STATE \ 646 1.1 christos if ((result = sorted_state[pi2->pi_state] \ 647 1.1 christos - sorted_state[pi1->pi_state]) == 0) 648 1.1 christos 649 1.1 christos /* Nice values directly reflect the process' priority, and are always >0 ;-) */ 650 1.1 christos #define ORDERKEY_PRIO \ 651 1.1 christos if ((result = pi1->pi_nice - pi2->pi_nice) == 0) 652 1.1 christos #define ORDERKEY_RSSIZE \ 653 1.1 christos if ((result = PROCRESS(pi2) - PROCRESS(pi1)) == 0) 654 1.1 christos #define ORDERKEY_MEM \ 655 1.1 christos if ((result = PROCSIZE(pi2) - PROCSIZE(pi1)) == 0) 656 1.1 christos 657 1.1 christos static unsigned char sorted_state[] = 658 1.1 christos { 659 1.1 christos 0, /* not used */ 660 1.1 christos 0, 661 1.1 christos 0, 662 1.1 christos 0, 663 1.1 christos 3, /* sleep */ 664 1.1 christos 1, /* zombie */ 665 1.1 christos 4, /* stop */ 666 1.1 christos 6, /* run */ 667 1.1 christos 2, /* swap */ 668 1.1 christos }; 669 1.1 christos 670 1.1 christos /* compare_cpu - the comparison function for sorting by cpu percentage */ 671 1.1 christos 672 1.1 christos int 673 1.1 christos compare_cpu(ppi1, ppi2) 674 1.1 christos struct procentry64 **ppi1; 675 1.1 christos struct procentry64 **ppi2; 676 1.1 christos { 677 1.1 christos register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 678 1.1 christos register int result; 679 1.1 christos 680 1.1 christos ORDERKEY_PCTCPU 681 1.1 christos ORDERKEY_CPTICKS 682 1.1 christos ORDERKEY_STATE 683 1.1 christos ORDERKEY_PRIO 684 1.1 christos ORDERKEY_RSSIZE 685 1.1 christos ORDERKEY_MEM 686 1.1 christos ; 687 1.1 christos 688 1.1 christos return result; 689 1.1 christos } 690 1.1 christos 691 1.1 christos 692 1.1 christos /* compare_size - the comparison function for sorting by total memory usage */ 693 1.1 christos 694 1.1 christos int 695 1.1 christos compare_size(ppi1, ppi2) 696 1.1 christos struct procentry64 **ppi1; 697 1.1 christos struct procentry64 **ppi2; 698 1.1 christos { 699 1.1 christos register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 700 1.1 christos register int result; 701 1.1 christos 702 1.1 christos ORDERKEY_MEM 703 1.1 christos ORDERKEY_RSSIZE 704 1.1 christos ORDERKEY_PCTCPU 705 1.1 christos ORDERKEY_CPTICKS 706 1.1 christos ORDERKEY_STATE 707 1.1 christos ORDERKEY_PRIO 708 1.1 christos ; 709 1.1 christos 710 1.1 christos return result; 711 1.1 christos } 712 1.1 christos 713 1.1 christos 714 1.1 christos /* compare_res - the comparison function for sorting by resident set size */ 715 1.1 christos 716 1.1 christos int 717 1.1 christos compare_res(ppi1, ppi2) 718 1.1 christos struct procentry64 **ppi1; 719 1.1 christos struct procentry64 **ppi2; 720 1.1 christos { 721 1.1 christos register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 722 1.1 christos register int result; 723 1.1 christos 724 1.1 christos ORDERKEY_RSSIZE 725 1.1 christos ORDERKEY_MEM 726 1.1 christos ORDERKEY_PCTCPU 727 1.1 christos ORDERKEY_CPTICKS 728 1.1 christos ORDERKEY_STATE 729 1.1 christos ORDERKEY_PRIO 730 1.1 christos ; 731 1.1 christos 732 1.1 christos return result; 733 1.1 christos } 734 1.1 christos 735 1.1 christos 736 1.1 christos /* compare_time - the comparison function for sorting by total cpu time */ 737 1.1 christos 738 1.1 christos int 739 1.1 christos compare_time(ppi1, ppi2) 740 1.1 christos struct procentry64 **ppi1; 741 1.1 christos struct procentry64 **ppi2; 742 1.1 christos { 743 1.1 christos register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 744 1.1 christos register int result; 745 1.1 christos 746 1.1 christos ORDERKEY_CPTICKS 747 1.1 christos ORDERKEY_PCTCPU 748 1.1 christos ORDERKEY_STATE 749 1.1 christos ORDERKEY_PRIO 750 1.1 christos ORDERKEY_MEM 751 1.1 christos ORDERKEY_RSSIZE 752 1.1 christos ; 753 1.1 christos 754 1.1 christos return result; 755 1.1 christos } 756 1.1 christos 757 1.1 christos 758 1.1 christos /* compare_prio - the comparison function for sorting by cpu percentage */ 759 1.1 christos 760 1.1 christos int 761 1.1 christos compare_prio(ppi1, ppi2) 762 1.1 christos struct procentry64 **ppi1; 763 1.1 christos struct procentry64 **ppi2; 764 1.1 christos { 765 1.1 christos register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 766 1.1 christos register int result; 767 1.1 christos 768 1.1 christos ORDERKEY_PRIO 769 1.1 christos ORDERKEY_PCTCPU 770 1.1 christos ORDERKEY_CPTICKS 771 1.1 christos ORDERKEY_STATE 772 1.1 christos ORDERKEY_RSSIZE 773 1.1 christos ORDERKEY_MEM 774 1.1 christos ; 775 1.1 christos 776 1.1 christos return result; 777 1.1 christos } 778 1.1 christos 779 1.1 christos 780 1.1 christos int proc_owner(pid) 781 1.1 christos int pid; 782 1.1 christos { 783 1.1 christos register struct procentry64 **prefp = pref; 784 1.1 christos register int cnt = pref_len; 785 1.1 christos 786 1.1 christos while (--cnt >= 0) { 787 1.1 christos if ((*prefp)->pi_pid == pid) 788 1.1 christos return (*prefp)->pi_uid; 789 1.1 christos prefp++; 790 1.1 christos } 791 1.1 christos 792 1.1 christos return(-1); 793 1.1 christos } 794