home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / unix / bsd / 10165 < prev    next >
Encoding:
Text File  |  1992-12-13  |  20.0 KB  |  773 lines

  1. Newsgroups: comp.unix.bsd
  2. Path: sparky!uunet!munnari.oz.au!bunyip.cc.uq.oz.au!citec!sgccseh
  3. From: sgccseh@citec.oz.au (Steve Hocking)
  4. Subject: Top modules for 386bsd
  5. Organization: CITEC
  6. Date: Mon, 14 Dec 1992 01:33:53 GMT
  7. Message-ID: <1992Dec14.013353.16568@citec.oz.au>
  8. Summary: come & get it
  9. Keywords: here - NOW
  10. Lines: 761
  11.  
  12.  
  13.     OK, here it is after a deluge of requests (well, 3 anyway) for it,
  14. the all new sing & dancing top machine.c module for 386bsd. Get the top
  15. sources from your local comp.sources.* archive.
  16.  
  17.  
  18.     Cheers,
  19.  
  20.  
  21.     Stephen
  22.  
  23. #!/bin/sh
  24. # shar:    Shell Archiver  (v1.22)
  25. #
  26. #    Run the following text with /bin/sh to create:
  27. #      m_386bsd.c
  28. #      m_386bsd.desc
  29. #      m_386bsd.man
  30. #      386bsd-top.README
  31. #
  32. sed 's/^X//' << 'SHAR_EOF' > m_386bsd.c &&
  33. X/*
  34. X * top - a top users display for Unix
  35. X *
  36. X * SYNOPSIS:  For a 386BSD system
  37. X *          Note memory statistisc and process sizes could be wrong,
  38. X *          by ps gets them wrong too...
  39. X *
  40. X * DESCRIPTION:
  41. X * This is the machine-dependent module for BSD4.3  NET/2 386bsd
  42. X * Works for:
  43. X *    i386 PC
  44. X *
  45. X * LIBS: -lutil
  46. X *
  47. X * AUTHOR:  Steve Hocking (adapted from Christos Zoulas <christos@ee.cornell.edu>)
  48. X */
  49. X
  50. X#include <sys/types.h>
  51. X#include <sys/signal.h>
  52. X#include <sys/param.h>
  53. X
  54. X#include <stdio.h>
  55. X#include <nlist.h>
  56. X#include <math.h>
  57. X#include <kvm.h>
  58. X#include <sys/errno.h>
  59. X#include <sys/kinfo.h>
  60. X#include <sys/kinfo_proc.h>
  61. X#ifdef notyet
  62. X#define time __time
  63. X#define hz __hz
  64. X#include <sys/kernel.h>
  65. X#undef time
  66. X#undef hz
  67. X#endif
  68. X#include <sys/dir.h>
  69. X#include <sys/dkstat.h>
  70. X#include <sys/file.h>
  71. X#include <sys/time.h>
  72. X#include <sys/vmmeter.h>
  73. X
  74. X
  75. X#define PATCHED_KVM        /* define this if you have a kvm.c */
  76. X                /* that has been patched not to freshly */
  77. X                /* alloc an array of procs each time */
  78. X                /* kvm_getprocs is called, but to do a */
  79. X                /* realloc when the no. of processes inc. */
  80. X/* #define TOTAL_WORKING */    /* Uncomment when the total structure in */
  81. X                /* the kernel actually works */
  82. X#define DOSWAP
  83. X
  84. X#include "top.h"
  85. X#include "machine.h"
  86. X
  87. X#define VMUNIX    "/386bsd"
  88. X#define KMEM    "/dev/kmem"
  89. X#define MEM    "/dev/mem"
  90. X#ifdef DOSWAP
  91. X#define SWAP    "/dev/drum"
  92. X#endif
  93. X
  94. Xtypedef struct _kinfo {
  95. X        struct proc ki_p;      /* proc structure */
  96. X        struct eproc ki_e;     /* extra stuff */
  97. X} KINFO;
  98. X
  99. X/* get_process_info passes back a handle.  This is what it looks like: */
  100. X
  101. Xstruct handle
  102. X{
  103. X    KINFO **next_proc;    /* points to next valid proc pointer */
  104. X    int remaining;        /* number of pointers remaining */
  105. X};
  106. X
  107. X/* declarations for load_avg */
  108. X#include "loadavg.h"
  109. X
  110. X#define PP(pp, field) ((pp)->ki_p . field)
  111. X#define EP(pp, field) ((pp)->ki_e . field)
  112. X#define VP(pp, field) ((pp)->ki_e.e_vm . field)
  113. X
  114. X/* define what weighted cpu is.  */
  115. X#define weighted_cpu(pct, pp) (PP((pp), p_time) == 0 ? 0.0 : \
  116. X             ((pct) / (1.0 - exp(PP((pp), p_time) * logcpu))))
  117. X
  118. X/* what we consider to be process size: */
  119. X#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
  120. X
  121. X/* definitions for indices in the nlist array */
  122. X#define X_CCPU        0
  123. X#define X_CP_TIME    1
  124. X#define X_HZ        2
  125. X#define X_AVENRUN    3
  126. X#define X_TOTAL        4
  127. X#define X_PG_FREE    5
  128. X#define X_PG_ACTIVE    6
  129. X#define X_PG_INACTIVE    7
  130. X#define X_PG_WIRED    8
  131. X
  132. Xstatic struct nlist nlst[] = {
  133. X    { "_ccpu" },        /* 0 */
  134. X    { "_cp_time" },        /* 1 */
  135. X    { "_hz" },            /* 2 */
  136. X    { "_averunnable" },        /* 3 */
  137. X    { "_total"},        /* 4 */
  138. X    { "_vm_page_free_count" },    /* 5 */
  139. X    { "_vm_page_active_count" },    /* 6 */
  140. X    { "_vm_page_inactive_count" },/* 7 */
  141. X    { "_vm_page_wire_count" },    /* 8 */
  142. X    { 0 }
  143. X};
  144. X
  145. X/*
  146. X *  These definitions control the format of the per-process area
  147. X */
  148. X
  149. Xstatic char header[] =
  150. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  151. X/* 0123456   -- field to fill in starts at header+6 */
  152. X#define UNAME_START 6
  153. X
  154. X#define Proc_format \
  155. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  156. X
  157. X
  158. X/* process state names for the "STATE" column of the display */
  159. X/* the extra nulls in the string "run" are for adding a slash and
  160. X   the processor number when needed */
  161. X
  162. Xchar *state_abbrev[] =
  163. X{
  164. X    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  165. X};
  166. X
  167. X
  168. X/* values that we stash away in _init and use in later routines */
  169. X
  170. Xstatic double logcpu;
  171. X
  172. X/* these are retrieved from the kernel in _init */
  173. X
  174. Xstatic          long hz;
  175. Xstatic load_avg  ccpu;
  176. Xstatic          int  ncpu = 0;
  177. X
  178. X/* these are offsets obtained via nlist and used in the get_ functions */
  179. X
  180. Xstatic unsigned long cp_time_offset;
  181. Xstatic unsigned long avenrun_offset;
  182. X
  183. X/* these are for calculating cpu state percentages */
  184. X
  185. Xstatic long cp_time[CPUSTATES];
  186. Xstatic long cp_old[CPUSTATES];
  187. Xstatic long cp_diff[CPUSTATES];
  188. X
  189. X/* these are for detailing the process states */
  190. X
  191. Xint process_states[7];
  192. Xchar *procstatenames[] = {
  193. X    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  194. X    " zombie, ", " stopped, ",
  195. X    NULL
  196. X};
  197. X
  198. X/* these are for detailing the cpu states */
  199. X
  200. Xint cpu_states[4];
  201. Xchar *cpustatenames[] = {
  202. X    "user", "nice", "system", "idle", NULL
  203. X};
  204. X
  205. X/* these are for detailing the memory statistics */
  206. X
  207. Xint memory_stats[8];
  208. Xchar *memorynames[] = {
  209. X#ifdef    TOTAL_WORKING
  210. X    "Real: ", "K/", "K ", "Virt: ", "K/",
  211. X    "K ", "Free: ", "K", NULL
  212. X#else
  213. X    " Free: ", "K ", " Active: ", "K ", " Inactive: ",
  214. X    "K ", " Wired: ", "K ", NULL
  215. X#endif
  216. X};
  217. X
  218. X/* these are for keeping track of the proc array */
  219. X
  220. Xstatic int bytes;
  221. Xstatic int nproc;
  222. Xstatic int onproc = -1;
  223. Xstatic KINFO *pbase;
  224. Xstatic KINFO **pref;
  225. X
  226. X/* these are for getting the memory statistics */
  227. X
  228. Xstatic int pageshift;        /* log base 2 of the pagesize */
  229. X
  230. X/* define pagetok in terms of pageshift */
  231. X
  232. X#define pagetok(size) ((size) << pageshift)
  233. X
  234. X/* useful externals */
  235. Xlong percentages();
  236. X
  237. Xmachine_init(statics)
  238. X
  239. Xstruct statics *statics;
  240. X
  241. X{
  242. X    register int i = 0;
  243. X    register int pagesize;
  244. X    char buf[1024];
  245. X
  246. X#if 0        /* some funny stuff going on here */
  247. X    if (kvm_openfiles(NULL, NULL, NULL) == -1);
  248. X    return -1;
  249. X#else
  250. X    kvm_openfiles(VMUNIX, NULL, NULL);
  251. X#endif
  252. X
  253. X    /* get the list of symbols we want to access in the kernel */
  254. X    (void) kvm_nlist(nlst);
  255. X    if (nlst[0].n_type == 0)
  256. X    {
  257. X    fprintf(stderr, "top: nlist failed\n");
  258. X    return(-1);
  259. X    }
  260. X
  261. X    /* make sure they were all found */
  262. X    if (i > 0 && check_nlist(nlst) > 0)
  263. X    {
  264. X    return(-1);
  265. X    }
  266. X
  267. X    /* get the symbol values out of kmem */
  268. X    (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),    sizeof(hz),
  269. X        nlst[X_HZ].n_name);
  270. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  271. X        nlst[X_CCPU].n_name);
  272. X
  273. X    /* stash away certain offsets for later use */
  274. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  275. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  276. X
  277. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  278. X    logcpu = log(loaddouble(ccpu));
  279. X
  280. X    pbase = NULL;
  281. X    pref = NULL;
  282. X    nproc = 0;
  283. X    onproc = -1;
  284. X    /* get the page size with "getpagesize" and calculate pageshift from it */
  285. X    pagesize = getpagesize();
  286. X    pageshift = 0;
  287. X    while (pagesize > 1)
  288. X    {
  289. X    pageshift++;
  290. X    pagesize >>= 1;
  291. X    }
  292. X
  293. X    /* we only need the amount of log(2)1024 for our conversion */
  294. X    pageshift -= LOG1024;
  295. X
  296. X    /* fill in the statics information */
  297. X    statics->procstate_names = procstatenames;
  298. X    statics->cpustate_names = cpustatenames;
  299. X    statics->memory_names = memorynames;
  300. X
  301. X    /* all done! */
  302. X    return(0);
  303. X}
  304. X
  305. Xchar *format_header(uname_field)
  306. X
  307. Xregister char *uname_field;
  308. X
  309. X{
  310. X    register char *ptr;
  311. X
  312. X    ptr = header + UNAME_START;
  313. X    while (*uname_field != '\0')
  314. X    {
  315. X    *ptr++ = *uname_field++;
  316. X    }
  317. X
  318. X    return(header);
  319. X}
  320. X
  321. Xget_system_info(si)
  322. X
  323. Xstruct system_info *si;
  324. X
  325. X{
  326. X    long total;
  327. X    load_avg avenrun[3];
  328. X
  329. X    /* get the cp_time array */
  330. X    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  331. X           "_cp_time");
  332. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  333. X           "_avenrun");
  334. X
  335. X    /* convert load averages to doubles */
  336. X    {
  337. X    register int i;
  338. X    register double *infoloadp;
  339. X    load_avg *avenrunp;
  340. X
  341. X#ifdef KINFO_LOADAVG
  342. X    struct loadavg sysload;
  343. X    int size;
  344. X    getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
  345. X#endif
  346. X
  347. X    infoloadp = si->load_avg;
  348. X    avenrunp = avenrun;
  349. X    for (i = 0; i < 3; i++)
  350. X    {
  351. X#ifdef KINFO_LOADAVG
  352. X        *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
  353. X#endif
  354. X        *infoloadp++ = loaddouble(*avenrunp++);
  355. X    }
  356. X    }
  357. X
  358. X    /* convert cp_time counts to percentages */
  359. X    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  360. X
  361. X    /* sum memory statistics */
  362. X    {
  363. X#ifdef TOTAL_WORKING
  364. X    static struct vmtotal total;
  365. X    int size;
  366. X
  367. X    /* get total -- systemwide main memory usage structure */
  368. X#ifdef KINFO_METER
  369. X    getkerninfo(KINFO_METER, &total, &size, 0);
  370. X#else
  371. X    (void) getkval(nlst[X_TOTAL].n_value, (int *)(&total), sizeof(total),
  372. X        nlst[X_TOTAL].n_name);
  373. X#endif
  374. X    /* convert memory stats to Kbytes */
  375. X    memory_stats[0] = -1;
  376. X    memory_stats[1] = pagetok(total.t_arm);
  377. X    memory_stats[2] = pagetok(total.t_rm);
  378. X    memory_stats[3] = -1;
  379. X    memory_stats[4] = pagetok(total.t_avm);
  380. X    memory_stats[5] = pagetok(total.t_vm);
  381. X    memory_stats[6] = -1;
  382. X    memory_stats[7] = pagetok(total.t_free);
  383. X#else
  384. X        static int free, active, inactive, wired;
  385. X
  386. X    (void) getkval(nlst[X_PG_FREE].n_value, (int *)(&free), sizeof(free),
  387. X                nlst[X_PG_FREE].n_name);
  388. X    (void) getkval(nlst[X_PG_ACTIVE].n_value, (int *)(&active), sizeof(active),
  389. X                nlst[X_PG_ACTIVE].n_name);
  390. X    (void) getkval(nlst[X_PG_INACTIVE].n_value, (int *)(&inactive), sizeof(inactive),
  391. X                nlst[X_PG_INACTIVE].n_name);
  392. X    (void) getkval(nlst[X_PG_WIRED].n_value, (int *)(&wired), sizeof(wired),
  393. X                nlst[X_PG_WIRED].n_name);
  394. X    memory_stats[0] = -1;
  395. X    memory_stats[1] = pagetok(free);
  396. X    memory_stats[2] = -1;
  397. X    memory_stats[3] = pagetok(active);
  398. X    memory_stats[4] = -1;
  399. X    memory_stats[5] = pagetok(inactive);
  400. X    memory_stats[6] = -1;
  401. X    memory_stats[7] = pagetok(wired);
  402. X#endif
  403. X    }
  404. X
  405. X    /* set arrays and strings */
  406. X    si->cpustates = cpu_states;
  407. X    si->memory = memory_stats;
  408. X    si->last_pid = -1;
  409. X}
  410. X
  411. Xstatic struct handle handle;
  412. X
  413. Xcaddr_t get_process_info(si, sel, compare)
  414. X
  415. Xstruct system_info *si;
  416. Xstruct process_select *sel;
  417. Xint (*compare)();
  418. X
  419. X{
  420. X    register int i;
  421. X    register int total_procs;
  422. X    register int active_procs;
  423. X    register KINFO **prefp;
  424. X    KINFO *pp;
  425. X    struct proc *pr;
  426. X    struct eproc *epr;
  427. X
  428. X    /* these are copied out of sel for speed */
  429. X    int show_idle;
  430. X    int show_system;
  431. X    int show_uid;
  432. X    int show_command;
  433. X
  434. X    
  435. X    nproc = kvm_getprocs(KINFO_PROC_ALL, 0);
  436. X    if (nproc > onproc)
  437. X    {
  438. X    pref = (KINFO **) realloc(pref, sizeof(KINFO *)
  439. X        * nproc);
  440. X        pbase = (KINFO *) realloc(pbase, sizeof(KINFO)
  441. X                * (nproc + 2));
  442. X        onproc = nproc;
  443. X    }
  444. X    if (pref == NULL || pbase == NULL) {
  445. X    (void) fprintf(stderr, "top: Out of memory.\n");
  446. X    quit(23);
  447. X    }
  448. X    /* get a pointer to the states summary array */
  449. X    si->procstates = process_states;
  450. X
  451. X    /* set up flags which define what we are going to select */
  452. X    show_idle = sel->idle;
  453. X    show_system = sel->system;
  454. X    show_uid = sel->uid != -1;
  455. X    show_command = sel->command != NULL;
  456. X
  457. X    /* count up process states and get pointers to interesting procs */
  458. X    total_procs = 0;
  459. X    active_procs = 0;
  460. X    memset((char *)process_states, 0, sizeof(process_states));
  461. X    prefp = pref;
  462. X    for (pp = pbase, i = 0; pr = kvm_nextproc(); pp++, i++)
  463. X    {
  464. X    /*
  465. X     *  Place pointers to each valid proc structure in pref[].
  466. X     *  Process slots that are actually in use have a non-zero
  467. X     *  status field.  Processes with SSYS set are system
  468. X     *  processes---these get ignored unless show_sysprocs is set.
  469. X     */
  470. X        epr = kvm_geteproc(pr);
  471. X        pp->ki_p = *pr;
  472. X        pp->ki_e = *epr;
  473. X    if (PP(pp, p_stat) != 0 &&
  474. X        (show_system || ((PP(pp, p_flag) & SSYS) == 0)))
  475. X    {
  476. X        total_procs++;
  477. X        process_states[PP(pp, p_stat)]++;
  478. X        if ((PP(pp, p_stat) != SZOMB) &&
  479. X        (show_idle || (PP(pp, p_pctcpu) != 0) || 
  480. X         (PP(pp, p_stat) == SRUN)) &&
  481. X        (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
  482. X        {
  483. X        *prefp++ = pp;
  484. X        active_procs++;
  485. X        }
  486. X    }
  487. X    }
  488. X
  489. X    /* if requested, sort the "interesting" processes */
  490. X    if (compare != NULL)
  491. X    {
  492. X    qsort((char *)pref, active_procs, sizeof(KINFO *), compare);
  493. X    }
  494. X
  495. X    /* remember active and total counts */
  496. X    si->p_total = total_procs;
  497. X    si->p_active = active_procs;
  498. X
  499. X    /* pass back a handle */
  500. X    handle.next_proc = pref;
  501. X    handle.remaining = active_procs;
  502. X#ifndef PATCHED_KVM
  503. X    kvm_freeprocs();
  504. X#endif
  505. X    return((caddr_t)&handle);
  506. X}
  507. X
  508. Xchar fmt[128];        /* static area where result is built */
  509. X
  510. Xchar *format_next_process(handle, get_userid)
  511. X
  512. Xcaddr_t handle;
  513. Xchar *(*get_userid)();
  514. X
  515. X{
  516. X    register KINFO *pp;
  517. X    register long cputime;
  518. X    register double pct;
  519. X    int where;
  520. X    struct handle *hp;
  521. X
  522. X    /* find and remember the next proc structure */
  523. X    hp = (struct handle *)handle;
  524. X    pp = *(hp->next_proc++);
  525. X    hp->remaining--;
  526. X    
  527. X
  528. X    /* get the process's user struct and set cputime */
  529. X    if ((PP(pp, p_flag) & SLOAD) == 0) {
  530. X    /*
  531. X     * Print swapped processes as <pname>
  532. X     */
  533. X    char *comm = PP(pp, p_comm);
  534. X#define COMSIZ sizeof(PP(pp, p_comm))
  535. X    char buf[COMSIZ];
  536. X    (void) strncpy(buf, comm, COMSIZ);
  537. X    comm[0] = '<';
  538. X    (void) strncpy(&comm[1], buf, COMSIZ - 2);
  539. X    comm[COMSIZ - 2] = '\0';
  540. X    (void) strncat(comm, ">", COMSIZ - 1);
  541. X    comm[COMSIZ - 1] = '\0';
  542. X    }
  543. X
  544. X    cputime = PP(pp, p_utime.tv_sec) + PP(pp, p_stime.tv_sec);
  545. X
  546. X    /* calculate the base for cpu percentages */
  547. X    pct = pctdouble(PP(pp, p_pctcpu));
  548. X
  549. X    /* format this entry */
  550. X    sprintf(fmt,
  551. X        Proc_format,
  552. X        PP(pp, p_pid),
  553. X        (*get_userid)(EP(pp, e_pcred.p_ruid)),
  554. X        PP(pp, p_pri) - PZERO,
  555. X        PP(pp, p_nice) - NZERO,
  556. X        pagetok(PROCSIZE(pp)),
  557. X#ifdef notyet
  558. X        pagetok(VP(pp, vm_rssize)),
  559. X#else
  560. X            pagetok(pp->ki_e.e_vm.vm_pmap.pm_stats.resident_count),
  561. X#endif
  562. X        state_abbrev[PP(pp, p_stat)],
  563. X        cputime / 60l,
  564. X        cputime % 60l,
  565. X        100.0 * weighted_cpu(pct, pp),
  566. X        100.0 * pct,
  567. X        printable(PP(pp, p_comm)));
  568. X
  569. X    /* return the result */
  570. X    return(fmt);
  571. X}
  572. X
  573. X
  574. X/*
  575. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  576. X *        found.  For every symbol that was not found, a one-line
  577. X *        message is printed to stderr.  The routine returns the
  578. X *        number of symbols NOT found.
  579. X */
  580. X
  581. Xint check_nlist(nlst)
  582. X
  583. Xregister struct nlist *nlst;
  584. X
  585. X{
  586. X    register int i;
  587. X
  588. X    /* check to see if we got ALL the symbols we requested */
  589. X    /* this will write one line to stderr for every symbol not found */
  590. X
  591. X    i = 0;
  592. X    while (nlst->n_name != NULL)
  593. X    {
  594. X    if (nlst->n_type == 0)
  595. X    {
  596. X        /* this one wasn't found */
  597. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  598. X        i = 1;
  599. X    }
  600. X    nlst++;
  601. X    }
  602. X
  603. X    return(i);
  604. X}
  605. X
  606. X
  607. X/*
  608. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  609. X *    "offset" is the byte offset into the kernel for the desired value,
  610. X *      "ptr" points to a buffer into which the value is retrieved,
  611. X *      "size" is the size of the buffer (and the object to retrieve),
  612. X *      "refstr" is a reference string used when printing error meessages,
  613. X *        if "refstr" starts with a '!', then a failure on read will not
  614. X *          be fatal (this may seem like a silly way to do things, but I
  615. X *          really didn't want the overhead of another argument).
  616. X *      
  617. X */
  618. X
  619. Xgetkval(offset, ptr, size, refstr)
  620. X
  621. Xunsigned long offset;
  622. Xint *ptr;
  623. Xint size;
  624. Xchar *refstr;
  625. X
  626. X{
  627. X    if (kvm_read(offset, (char *) ptr, size) != size)
  628. X    {
  629. X    if (*refstr == '!')
  630. X    {
  631. X        return(0);
  632. X    }
  633. X    else
  634. X    {
  635. X        fprintf(stderr, "top: kvm_read for %s: %s\n",
  636. X        refstr, strerror(errno));
  637. X        quit(23);
  638. X    }
  639. X    }
  640. X    return(1);
  641. X}
  642. X    
  643. X/* comparison routine for qsort */
  644. X
  645. X/*
  646. X *  proc_compare - comparison function for "qsort"
  647. X *    Compares the resource consumption of two processes using five
  648. X *      distinct keys.  The keys (in descending order of importance) are:
  649. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  650. X *      memory usage.  The process states are ordered as follows (from least
  651. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  652. X *      array declaration below maps a process state index into a number
  653. X *      that reflects this ordering.
  654. X */
  655. X
  656. Xstatic unsigned char sorted_state[] =
  657. X{
  658. X    0,    /* not used        */
  659. X    3,    /* sleep        */
  660. X    1,    /* ABANDONED (WAIT)    */
  661. X    6,    /* run            */
  662. X    5,    /* start        */
  663. X    2,    /* zombie        */
  664. X    4    /* stop            */
  665. X};
  666. Xproc_compare(pp1, pp2)
  667. X
  668. XKINFO **pp1;
  669. XKINFO **pp2;
  670. X
  671. X{
  672. X    register KINFO *p1;
  673. X    register KINFO *p2;
  674. X    register int result;
  675. X    register pctcpu lresult;
  676. X
  677. X    /* remove one level of indirection */
  678. X    p1 = *pp1;
  679. X    p2 = *pp2;
  680. X
  681. X    /* compare percent cpu (pctcpu) */
  682. X    if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
  683. X    {
  684. X    /* use cpticks to break the tie */
  685. X    if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
  686. X    {
  687. X        /* use process state to break the tie */
  688. X        if ((result = sorted_state[PP(p2, p_stat)] -
  689. X              sorted_state[PP(p1, p_stat)])  == 0)
  690. X        {
  691. X        /* use priority to break the tie */
  692. X        if ((result = PP(p2, p_pri) - PP(p1, p_pri)) == 0)
  693. X        {
  694. X            /* use resident set size (rssize) to break the tie */
  695. X            if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
  696. X            {
  697. X            /* use total memory to break the tie */
  698. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  699. X            }
  700. X        }
  701. X        }
  702. X    }
  703. X    }
  704. X    else
  705. X    {
  706. X    result = lresult < 0 ? -1 : 1;
  707. X    }
  708. X
  709. X    return(result);
  710. X}
  711. SHAR_EOF
  712. chmod 0644 m_386bsd.c || echo "restore of m_386bsd.c fails"
  713. sed 's/^X//' << 'SHAR_EOF' > m_386bsd.desc &&
  714. X
  715. Xtop - a top users display for Unix
  716. X
  717. XSYNOPSIS:  For a pre-release 4.4BSD system
  718. X          Note memory statistisc and process sizes could be wrong,
  719. X          by ps gets them wrong too...
  720. X
  721. XDESCRIPTION:
  722. XThis is the machine-dependent module for BSD4.3  NET/2 386bsd
  723. XWorks for:
  724. X    i386 PC
  725. X
  726. XLIBS: -lkvm
  727. X
  728. XAUTHOR:  Steve Hocking (adapted from Christos Zoulas <christos@ee.cornell.edu>)
  729. X
  730. SHAR_EOF
  731. chmod 0644 m_386bsd.desc || echo "restore of m_386bsd.desc fails"
  732. sed 's/^X//' << 'SHAR_EOF' > m_386bsd.man &&
  733. X.SH "386 BSD DIFFERENCES"
  734. XThe 386 BSD port is said to work at least as well as ps does.
  735. X
  736. XThe 386 BSD port was written by Steve Hocking
  737. SHAR_EOF
  738. chmod 0644 m_386bsd.man || echo "restore of m_386bsd.man fails"
  739. sed 's/^X//' << 'SHAR_EOF' > 386bsd-top.README &&
  740. X
  741. X    Find enclosed a module for 386bsd. A couple of notes -
  742. XFirstly I recently posted a patch to kvm.c in the util library which proved
  743. Xstrictly unneccessary, as there was a routine that allowed one to free up
  744. Xthe memory used by the kvm_getprocs routine. (Humph, all the doco for the
  745. Xkvm library was, as usual, in the source). There is a #define which should
  746. Xbe set if you have not applied my patches to kvm.c,
  747. X    Secondly there appears to be a subtle bug somewhere which was causing
  748. Xthe kvm routines to not properly initialise. I suspect something was treading on
  749. Xa stack frame early in the top code proper, but am unable to trace it owing
  750. Xto lack of time. This caused me some problems in obtaining the resident set
  751. Xsize of a process, even using a method which works for ps. I did find
  752. X(largely owing to GDB, a debugger for whom I have an increasing amount of
  753. Xaffection) another place where the relevant information was kept in the
  754. Xstructure, and used it.
  755. X    Thridly, the total structure that contains the information about the
  756. Xsystem memory in traditional BSD form was not being fully updated by
  757. Xvm_meter.c, probably because of all the changes to the VM subsystem. I opted
  758. Xto report some of the stuff regarding free, active & wired  down pages.
  759. X
  760. X
  761. X    (un)shar & enjoy
  762. X
  763. X    Stephen
  764. SHAR_EOF
  765. chmod 0644 386bsd-top.README || echo "restore of 386bsd-top.README fails"
  766. exit 0
  767. -- 
  768. -----------------------------------------------------------------------------
  769.           "Toddlers are the stormtroopers of the Lord of Entropy"
  770.  
  771. Stephen Hocking                                    sgccseh@citecuc.citec.oz.au
  772.