Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/procps/top.c


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/procps/top.c

    r821 r1770  
    2929 */
    3030
    31 #include "busybox.h"
    32 #include <sys/types.h>
    33 #include <stdio.h>
    34 #include <stdlib.h>
    35 #include <unistd.h>
    36 #include <string.h>
    37 #include <sys/ioctl.h>
    38 
    39 //#define CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE  /* + 2k */
    40 
    41 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    42 #include <time.h>
    43 #include <fcntl.h>
    44 #include <netinet/in.h>  /* htons */
    45 #endif
    46 
    47 
    48 typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q);
    49 
    50 static procps_status_t *top;   /* Hehe */
    51 static int ntop;
    52 
    53 #ifdef CONFIG_FEATURE_USE_TERMIOS
    54 static int pid_sort(procps_status_t *P, procps_status_t *Q)
    55 {
     31#include "libbb.h"
     32
     33
     34typedef struct top_status_t {
     35    unsigned long vsz;
     36#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     37    unsigned long ticks;
     38    unsigned pcpu; /* delta of ticks */
     39#endif
     40    unsigned pid, ppid;
     41    unsigned uid;
     42    char state[4];
     43    char comm[COMM_LEN];
     44} top_status_t;
     45
     46typedef struct jiffy_counts_t {
     47    unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
     48    unsigned long long total;
     49    unsigned long long busy;
     50} jiffy_counts_t;
     51
     52/* This structure stores some critical information from one frame to
     53   the next. Used for finding deltas. */
     54typedef struct save_hist {
     55    unsigned long ticks;
     56    unsigned pid;
     57} save_hist;
     58
     59typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
     60
     61enum { SORT_DEPTH = 3 };
     62
     63struct globals {
     64    top_status_t *top;
     65    int ntop;
     66#if ENABLE_FEATURE_USE_TERMIOS
     67    struct termios initial_settings;
     68#endif
     69#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     70    cmp_funcp sort_function;
     71#else
     72    cmp_funcp sort_function[SORT_DEPTH];
     73    struct save_hist *prev_hist;
     74    int prev_hist_count;
     75    jiffy_counts_t jif, prev_jif;
     76    /* int hist_iterations; */
     77    unsigned total_pcpu;
     78    /* unsigned long total_vsz; */
     79#endif
     80};
     81#define G (*(struct globals*)&bb_common_bufsiz1)
     82#define top              (G.top               )
     83#define ntop             (G.ntop              )
     84#if ENABLE_FEATURE_USE_TERMIOS
     85#define initial_settings (G. initial_settings )
     86#endif
     87#define sort_function    (G.sort_function     )
     88#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     89#define prev_hist        (G.prev_hist         )
     90#define prev_hist_count  (G.prev_hist_count   )
     91#define jif              (G.jif               )
     92#define prev_jif         (G.prev_jif          )
     93#define total_pcpu       (G.total_pcpu        )
     94#endif
     95
     96#define OPT_BATCH_MODE (option_mask32 & 0x4)
     97
     98
     99#if ENABLE_FEATURE_USE_TERMIOS
     100static int pid_sort(top_status_t *P, top_status_t *Q)
     101{
     102    /* Buggy wrt pids with high bit set */
     103    /* (linux pids are in [1..2^15-1]) */
    56104    return (Q->pid - P->pid);
    57105}
    58106#endif
    59107
    60 static int mem_sort(procps_status_t *P, procps_status_t *Q)
    61 {
    62     return (int)(Q->rss - P->rss);
    63 }
    64 
    65 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    66 
    67 #define sort_depth 3
    68 static cmp_t sort_function[sort_depth];
    69 
    70 static int pcpu_sort(procps_status_t *P, procps_status_t *Q)
    71 {
    72     return (Q->pcpu - P->pcpu);
    73 }
    74 
    75 static int time_sort(procps_status_t *P, procps_status_t *Q)
    76 {
    77     return (int)((Q->stime + Q->utime) - (P->stime + P->utime));
    78 }
    79 
    80 static int mult_lvl_cmp(void* a, void* b) {
     108static int mem_sort(top_status_t *P, top_status_t *Q)
     109{
     110    /* We want to avoid unsigned->signed and truncation errors */
     111    if (Q->vsz < P->vsz) return -1;
     112    return Q->vsz != P->vsz; /* 0 if ==, 1 if > */
     113}
     114
     115
     116#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     117
     118static int pcpu_sort(top_status_t *P, top_status_t *Q)
     119{
     120    /* Buggy wrt ticks with high bit set */
     121    /* Affects only processes for which ticks overflow */
     122    return (int)Q->pcpu - (int)P->pcpu;
     123}
     124
     125static int time_sort(top_status_t *P, top_status_t *Q)
     126{
     127    /* We want to avoid unsigned->signed and truncation errors */
     128    if (Q->ticks < P->ticks) return -1;
     129    return Q->ticks != P->ticks; /* 0 if ==, 1 if > */
     130}
     131
     132static int mult_lvl_cmp(void* a, void* b)
     133{
    81134    int i, cmp_val;
    82135
    83     for (i = 0; i < sort_depth; i++) {
     136    for (i = 0; i < SORT_DEPTH; i++) {
    84137        cmp_val = (*sort_function[i])(a, b);
    85138        if (cmp_val != 0)
     
    89142}
    90143
    91 /* This structure stores some critical information from one frame to
    92    the next. mostly used for sorting. Added cumulative and resident fields. */
    93 struct save_hist {
    94     int ticks;
    95     int pid;
    96 };
    97 
    98 /*
    99  * Calculates percent cpu usage for each task.
    100  */
    101 
    102 static struct save_hist *prev_hist;
    103 static int prev_hist_count;
    104 /* static int hist_iterations; */
    105 
    106 
    107 static unsigned total_pcpu;
    108 /* static unsigned long total_rss; */
    109 
    110 struct jiffy_counts {
    111     unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
    112     unsigned long long total;
    113     unsigned long long busy;
    114 };
    115 static struct jiffy_counts jif, prev_jif;
    116144
    117145static void get_jiffy_counts(void)
    118146{
    119     FILE* fp = bb_xfopen("stat", "r");
     147    FILE* fp = xfopen("stat", "r");
    120148    prev_jif = jif;
    121149    if (fscanf(fp, "cpu  %lld %lld %lld %lld %lld %lld %lld %lld",
    122150            &jif.usr,&jif.nic,&jif.sys,&jif.idle,
    123151            &jif.iowait,&jif.irq,&jif.softirq,&jif.steal) < 4) {
    124         bb_error_msg_and_die("failed to read 'stat'");
     152        bb_error_msg_and_die("failed to read /proc/stat");
    125153    }
    126154    fclose(fp);
     
    131159}
    132160
     161
    133162static void do_stats(void)
    134163{
    135     procps_status_t *cur;
    136     int pid, total_time, i, last_i, n;
     164    top_status_t *cur;
     165    pid_t pid;
     166    int i, last_i, n;
    137167    struct save_hist *new_hist;
    138168
    139169    get_jiffy_counts();
    140170    total_pcpu = 0;
    141     /* total_rss = 0; */
     171    /* total_vsz = 0; */
    142172    new_hist = xmalloc(sizeof(struct save_hist)*ntop);
    143173    /*
     
    154184         */
    155185        pid = cur->pid;
    156         total_time = cur->stime + cur->utime;
    157         new_hist[n].ticks = total_time;
     186        new_hist[n].ticks = cur->ticks;
    158187        new_hist[n].pid = pid;
    159188
     
    165194        if (prev_hist_count) do {
    166195            if (prev_hist[i].pid == pid) {
    167                 cur->pcpu = total_time - prev_hist[i].ticks;
     196                cur->pcpu = cur->ticks - prev_hist[i].ticks;
     197                total_pcpu += cur->pcpu;
    168198                break;
    169199            }
     
    171201            /* hist_iterations++; */
    172202        } while (i != last_i);
    173         total_pcpu += cur->pcpu;
    174         /* total_rss += cur->rss; */
     203        /* total_vsz += cur->vsz; */
    175204    }
    176205
     
    182211    prev_hist_count = ntop;
    183212}
    184 #else
    185 static cmp_t sort_function;
    186 #endif /* CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE */
     213#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
     214
     215#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS
     216/* formats 7 char string (8 with terminating NUL) */
     217static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total)
     218{
     219    unsigned t;
     220    if (value >= total) { /* 100% ? */
     221        strcpy(pbuf, "  100% ");
     222        return pbuf;
     223    }
     224    /* else generate " [N/space]N.N% " string */
     225    value = 1000 * value / total;
     226    t = value / 100;
     227    value = value % 100;
     228    pbuf[0] = ' ';
     229    pbuf[1] = t ? t + '0' : ' ';
     230    pbuf[2] = '0' + (value / 10);
     231    pbuf[3] = '.';
     232    pbuf[4] = '0' + (value % 10);
     233    pbuf[5] = '%';
     234    pbuf[6] = ' ';
     235    pbuf[7] = '\0';
     236    return pbuf;
     237}
     238#endif
    187239
    188240/* display generic info (meminfo / loadavg) */
     
    192244    char buf[80];
    193245    char scrbuf[80];
    194     char *end;
    195246    unsigned long total, used, mfree, shared, buffers, cached;
    196     unsigned int needs_conversion = 1;
     247#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
     248    unsigned total_diff;
     249#endif
    197250
    198251    /* read memory info */
    199     fp = bb_xfopen("meminfo", "r");
     252    fp = xfopen("meminfo", "r");
    200253
    201254    /*
     
    213266
    214267        fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
    215            &total, &used, &mfree, &shared, &buffers, &cached);
    216     } else {
    217         /*
    218          * Revert to manual parsing, which incidentally already has the
    219          * sizes in kilobytes. This should be safe for both 2.4 and
    220          * 2.6.
    221          */
    222         needs_conversion = 0;
    223 
    224         fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
    225 
    226         /*
    227          * MemShared: is no longer present in 2.6. Report this as 0,
    228          * to maintain consistent behavior with normal procps.
    229          */
    230         if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
    231             shared = 0;
    232 
    233         fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
    234         fscanf(fp, "Cached: %lu %s\n", &cached, buf);
    235 
    236         used = total - mfree;
    237     }
    238     fclose(fp);
    239 
    240     /* read load average as a string */
    241     fp = bb_xfopen("loadavg", "r");
    242     buf[0] = '\0';
    243     fgets(buf, sizeof(buf), fp);
    244     end = strchr(buf, ' ');
    245     if (end) end = strchr(end+1, ' ');
    246     if (end) end = strchr(end+1, ' ');
    247     if (end) *end = '\0';
    248     fclose(fp);
    249 
    250     if (needs_conversion) {
     268            &total, &used, &mfree, &shared, &buffers, &cached);
    251269        /* convert to kilobytes */
    252270        used /= 1024;
     
    256274        cached /= 1024;
    257275        total /= 1024;
    258     }
    259 
    260     /* output memory info and load average */
    261     /* clear screen & go to top */
     276    } else {
     277        /*
     278         * Revert to manual parsing, which incidentally already has the
     279         * sizes in kilobytes. This should be safe for both 2.4 and
     280         * 2.6.
     281         */
     282
     283        fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
     284
     285        /*
     286         * MemShared: is no longer present in 2.6. Report this as 0,
     287         * to maintain consistent behavior with normal procps.
     288         */
     289        if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
     290            shared = 0;
     291
     292        fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
     293        fscanf(fp, "Cached: %lu %s\n", &cached, buf);
     294
     295        used = total - mfree;
     296    }
     297    fclose(fp);
     298
     299    /* output memory info */
    262300    if (scr_width > sizeof(scrbuf))
    263301        scr_width = sizeof(scrbuf);
    264302    snprintf(scrbuf, scr_width,
    265         "Mem: %ldK used, %ldK free, %ldK shrd, %ldK buff, %ldK cached",
     303        "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
    266304        used, mfree, shared, buffers, cached);
    267     printf("\e[H\e[J%s\n", scrbuf);
    268     snprintf(scrbuf, scr_width,
    269         "Load average: %s  (Status: S=sleeping R=running, W=waiting)", buf);
    270     printf("%s\n", scrbuf);
     305    /* clear screen & go to top */
     306    printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf);
     307
     308#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
     309    /*
     310     * xxx% = (jif.xxx - prev_jif.xxx) / (jif.total - prev_jif.total) * 100%
     311     */
     312    /* using (unsigned) casts to make operations cheaper */
     313    total_diff = ((unsigned)(jif.total - prev_jif.total) ? : 1);
     314#if ENABLE_FEATURE_TOP_DECIMALS
     315/* Generated code is approx +0.3k */
     316#define CALC_STAT(xxx) char xxx[8]
     317#define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(jif.xxx - prev_jif.xxx), total_diff)
     318#define FMT "%s"
     319#else
     320#define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(jif.xxx - prev_jif.xxx) / total_diff
     321#define SHOW_STAT(xxx) xxx
     322#define FMT "%4u%% "
     323#endif
     324    { /* need block: CALC_STAT are declarations */
     325        CALC_STAT(usr);
     326        CALC_STAT(sys);
     327        CALC_STAT(nic);
     328        CALC_STAT(idle);
     329        CALC_STAT(iowait);
     330        CALC_STAT(irq);
     331        CALC_STAT(softirq);
     332        //CALC_STAT(steal);
     333
     334        snprintf(scrbuf, scr_width,
     335            /* Barely fits in 79 chars when in "decimals" mode. */
     336            "CPU:"FMT"usr"FMT"sys"FMT"nice"FMT"idle"FMT"io"FMT"irq"FMT"softirq",
     337            SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle),
     338            SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq)
     339            //, SHOW_STAT(steal) - what is this 'steal' thing?
     340            // I doubt anyone wants to know it
     341        );
     342    }
     343    puts(scrbuf);
     344#undef SHOW_STAT
     345#undef CALC_STAT
     346#undef FMT
     347#endif
     348
     349    /* read load average as a string */
     350    buf[0] = '\0';
     351    open_read_close("loadavg", buf, sizeof("N.NN N.NN N.NN")-1);
     352    buf[sizeof("N.NN N.NN N.NN")-1] = '\0';
     353    snprintf(scrbuf, scr_width, "Load average: %s", buf);
     354    puts(scrbuf);
    271355
    272356    return total;
    273357}
    274 
    275358
    276359/* display process statuses */
     
    278361{
    279362    enum {
    280         bits_per_int = sizeof(int)*8
     363        BITS_PER_INT = sizeof(int)*8
    281364    };
    282365
    283     procps_status_t *s = top;
    284     char rss_str_buf[8];
    285     unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */
    286     unsigned pmem_shift, pmem_scale;
    287 
    288 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    289     unsigned pcpu_shift, pcpu_scale;
     366    top_status_t *s = top;
     367    char vsz_str_buf[8];
     368    unsigned long total_memory = display_generic(scr_width); /* or use total_vsz? */
     369    /* xxx_shift and xxx_scale variables allow us to replace
     370     * expensive divides with multiply and shift */
     371    unsigned pmem_shift, pmem_scale, pmem_half;
     372#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     373    unsigned pcpu_shift, pcpu_scale, pcpu_half;
     374    unsigned busy_jifs;
    290375
    291376    /* what info of the processes is shown */
    292     printf("\e[7m%.*s\e[0m", scr_width,
    293         "  PID USER     STATUS   RSS  PPID %CPU %MEM COMMAND");
     377    printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
     378        "  PID  PPID USER     STAT   VSZ %MEM %CPU COMMAND");
    294379#define MIN_WIDTH \
    295     sizeof( "  PID USER     STATUS   RSS  PPID %CPU %MEM C")
    296 #else
    297     printf("\e[7m%.*s\e[0m", scr_width,
    298         "  PID USER     STATUS   RSS  PPID %MEM COMMAND");
     380    sizeof( "  PID  PPID USER     STAT   VSZ %MEM %CPU C")
     381#else
     382
     383    /* !CPU_USAGE_PERCENTAGE */
     384    printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
     385        "  PID  PPID USER     STAT   VSZ %MEM COMMAND");
    299386#define MIN_WIDTH \
    300     sizeof( "  PID USER     STATUS   RSS  PPID %MEM C")
    301 #endif
    302 
     387    sizeof( "  PID  PPID USER     STAT   VSZ %MEM C")
     388#endif
     389
     390#if ENABLE_FEATURE_TOP_DECIMALS
     391#define UPSCALE 1000
     392#define CALC_STAT(name, val) div_t name = div((val), 10)
     393#define SHOW_STAT(name) name.quot, '0'+name.rem
     394#define FMT "%3u.%c"
     395#else
     396#define UPSCALE 100
     397#define CALC_STAT(name, val) unsigned name = (val)
     398#define SHOW_STAT(name) name
     399#define FMT "%4u%%"
     400#endif
    303401    /*
    304      * MEM% = s->rss/MemTotal
     402     * MEM% = s->vsz/MemTotal
    305403     */
    306     pmem_shift = bits_per_int-11;
    307     pmem_scale = 1000*(1U<<(bits_per_int-11)) / total_memory;
    308     /* s->rss is in kb. we want (s->rss * pmem_scale) to never overflow */
     404    pmem_shift = BITS_PER_INT-11;
     405    pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory;
     406    /* s->vsz is in kb. we want (s->vsz * pmem_scale) to never overflow */
    309407    while (pmem_scale >= 512) {
    310408        pmem_scale /= 4;
    311409        pmem_shift -= 2;
    312410    }
    313 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     411    pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
     412#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     413    busy_jifs = jif.busy - prev_jif.busy;
     414    /* This happens if there were lots of short-lived processes
     415     * between two top updates (e.g. compilation) */
     416    if (total_pcpu < busy_jifs) total_pcpu = busy_jifs;
     417
    314418    /*
    315419     * CPU% = s->pcpu/sum(s->pcpu) * busy_cpu_ticks/total_cpu_ticks
     
    321425     */
    322426    pcpu_shift = 6;
    323     pcpu_scale = (1000*64*(uint16_t)(jif.busy-prev_jif.busy) ? : 1);
    324     while (pcpu_scale < (1U<<(bits_per_int-2))) {
     427    pcpu_scale = (UPSCALE*64*(uint16_t)busy_jifs ? : 1);
     428    while (pcpu_scale < (1U<<(BITS_PER_INT-2))) {
    325429        pcpu_scale *= 4;
    326430        pcpu_shift += 2;
     
    332436        pcpu_shift -= 2;
    333437    }
     438    pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
    334439    /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */
    335440#endif
    336441
    337     while (count--) {
    338         div_t pmem = div( (s->rss*pmem_scale) >> pmem_shift, 10);
    339         int col = scr_width+1;
    340         USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(div_t pcpu;)
    341 
    342         if (s->rss >= 100*1024)
    343             sprintf(rss_str_buf, "%6ldM", s->rss/1024);
     442    /* Ok, all prelim data is ready, go thru the list */
     443    while (count-- > 0) {
     444        int col = scr_width;
     445        CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
     446#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     447        CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift);
     448#endif
     449
     450        if (s->vsz >= 100*1024)
     451            sprintf(vsz_str_buf, "%6ldM", s->vsz/1024);
    344452        else
    345             sprintf(rss_str_buf, "%7ld", s->rss);
    346         USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);)
    347         col -= printf("\n%5d %-8s %s  %s%6d%3u.%c" \
    348                 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") " ",
    349                 s->pid, s->user, s->state, rss_str_buf, s->ppid,
    350                 USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,)
    351                 pmem.quot, '0'+pmem.rem);
    352         if (col>0)
    353             printf("%.*s", col, s->short_cmd);
     453            sprintf(vsz_str_buf, "%7ld", s->vsz);
     454        // PID PPID USER STAT VSZ %MEM [%CPU] COMMAND
     455        col -= printf("\n" "%5u%6u %-8.8s %s%s" FMT
     456#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     457                FMT
     458#endif
     459                " ",
     460                s->pid, s->ppid, get_cached_username(s->uid),
     461                s->state, vsz_str_buf,
     462                SHOW_STAT(pmem)
     463#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     464                , SHOW_STAT(pcpu)
     465#endif
     466        );
     467        if (col > 0) {
     468            char buf[col + 1];
     469            read_cmdline(buf, col, s->pid, s->comm);
     470            fputs(buf, stdout);
     471        }
    354472        /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
    355473            jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
     
    357475    }
    358476    /* printf(" %d", hist_iterations); */
    359     putchar('\r');
     477    putchar(OPT_BATCH_MODE ? '\n' : '\r');
    360478    fflush(stdout);
    361479}
     480#undef UPSCALE
     481#undef SHOW_STAT
     482#undef CALC_STAT
     483#undef FMT
     484
    362485
    363486static void clearmems(void)
    364487{
     488    clear_username_cache();
    365489    free(top);
    366490    top = 0;
     
    368492}
    369493
    370 #ifdef CONFIG_FEATURE_USE_TERMIOS
     494
     495#if ENABLE_FEATURE_USE_TERMIOS
    371496#include <termios.h>
    372497#include <signal.h>
    373498
    374 
    375 static struct termios initial_settings;
    376 
    377499static void reset_term(void)
    378500{
    379501    tcsetattr(0, TCSANOW, (void *) &initial_settings);
    380 #ifdef CONFIG_FEATURE_CLEAN_UP
     502#if ENABLE_FEATURE_CLEAN_UP
    381503    clearmems();
    382 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     504#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    383505    free(prev_hist);
    384506#endif
    385 #endif /* CONFIG_FEATURE_CLEAN_UP */
     507#endif /* FEATURE_CLEAN_UP */
    386508}
    387509
     
    391513    exit(1);
    392514}
    393 #endif /* CONFIG_FEATURE_USE_TERMIOS */
    394 
    395 
     515#endif /* FEATURE_USE_TERMIOS */
     516
     517
     518int top_main(int argc, char **argv);
    396519int top_main(int argc, char **argv)
    397520{
    398     int opt, interval, lines, col;
    399     char *sinterval;
    400 #ifdef CONFIG_FEATURE_USE_TERMIOS
     521    int count, lines, col;
     522    unsigned interval = 5; /* default update rate is 5 seconds */
     523    unsigned iterations = UINT_MAX; /* 2^32 iterations by default :) */
     524    char *sinterval, *siterations;
     525#if ENABLE_FEATURE_USE_TERMIOS
    401526    struct termios new_settings;
    402527    struct timeval tv;
    403528    fd_set readfds;
    404529    unsigned char c;
    405 #endif /* CONFIG_FEATURE_USE_TERMIOS */
     530#endif /* FEATURE_USE_TERMIOS */
     531
     532    interval = 5;
    406533
    407534    /* do normal option parsing */
    408     opt = bb_getopt_ulflags(argc, argv, "d:", &sinterval);
    409     if ((opt & 1)) {
    410         interval = atoi(sinterval);
    411     } else {
    412         /* Default update rate is 5 seconds */
    413         interval = 5;
    414     }
     535    opt_complementary = "-";
     536    getopt32(argv, "d:n:b", &sinterval, &siterations);
     537    if (option_mask32 & 0x1) interval = xatou(sinterval); // -d
     538    if (option_mask32 & 0x2) iterations = xatou(siterations); // -n
     539    //if (option_mask32 & 0x4) // -b
    415540
    416541    /* change to /proc */
    417     bb_xchdir("/proc");
    418 #ifdef CONFIG_FEATURE_USE_TERMIOS
     542    xchdir("/proc");
     543#if ENABLE_FEATURE_USE_TERMIOS
    419544    tcgetattr(0, (void *) &initial_settings);
    420545    memcpy(&new_settings, &initial_settings, sizeof(struct termios));
    421     new_settings.c_lflag &= ~(ISIG | ICANON); /* unbuffered input */
    422     /* Turn off echoing */
    423     new_settings.c_lflag &= ~(ECHO | ECHONL);
     546    /* unbuffered input, turn off echo */
     547    new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
    424548
    425549    signal(SIGTERM, sig_catcher);
     
    427551    tcsetattr(0, TCSANOW, (void *) &new_settings);
    428552    atexit(reset_term);
    429 #endif /* CONFIG_FEATURE_USE_TERMIOS */
    430 
    431 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     553#endif /* FEATURE_USE_TERMIOS */
     554
     555#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    432556    sort_function[0] = pcpu_sort;
    433557    sort_function[1] = mem_sort;
     
    435559#else
    436560    sort_function = mem_sort;
    437 #endif /* CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE */
     561#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
    438562
    439563    while (1) {
    440         procps_status_t *p;
     564        procps_status_t *p = NULL;
    441565
    442566        /* Default to 25 lines - 5 lines for status */
    443         lines = 24 - 3;
     567        lines = 24 - 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( - 1);
    444568        col = 79;
    445 #ifdef CONFIG_FEATURE_USE_TERMIOS
     569#if ENABLE_FEATURE_USE_TERMIOS
    446570        get_terminal_width_height(0, &col, &lines);
    447571        if (lines < 5 || col < MIN_WIDTH) {
     
    449573            continue;
    450574        }
    451         lines -= 3;
    452 #endif /* CONFIG_FEATURE_USE_TERMIOS */
     575        lines -= 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( + 1);
     576#endif /* FEATURE_USE_TERMIOS */
    453577
    454578        /* read process IDs & status for all the processes */
    455         while ((p = procps_scan(0)) != 0) {
     579        while ((p = procps_scan(p, 0
     580                | PSSCAN_PID
     581                | PSSCAN_PPID
     582                | PSSCAN_VSZ
     583                | PSSCAN_STIME
     584                | PSSCAN_UTIME
     585                | PSSCAN_STATE
     586                | PSSCAN_COMM
     587                | PSSCAN_SID
     588                | PSSCAN_UIDGID
     589        ))) {
    456590            int n = ntop;
    457 
    458             top = xrealloc(top, (++ntop)*sizeof(procps_status_t));
    459             memcpy(top + n, p, sizeof(procps_status_t));
     591            top = xrealloc(top, (++ntop) * sizeof(*top));
     592            top[n].pid = p->pid;
     593            top[n].ppid = p->ppid;
     594            top[n].vsz = p->vsz;
     595#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     596            top[n].ticks = p->stime + p->utime;
     597#endif
     598            top[n].uid = p->uid;
     599            strcpy(top[n].state, p->state);
     600            strcpy(top[n].comm, p->comm);
    460601        }
    461602        if (ntop == 0) {
    462             bb_error_msg_and_die("Can't find process info in /proc");
     603            bb_error_msg_and_die("no process info in /proc");
    463604        }
    464 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     605#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    465606        if (!prev_hist_count) {
    466607            do_stats();
     
    470611        }
    471612        do_stats();
    472         qsort(top, ntop, sizeof(procps_status_t), (void*)mult_lvl_cmp);
    473 #else
    474         qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function);
    475 #endif /* CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE */
    476         opt = lines;
    477         if (opt > ntop) {
    478             opt = ntop;
     613/* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
     614        qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
     615#else
     616        qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);
     617#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
     618        count = lines;
     619        if (OPT_BATCH_MODE || count > ntop) {
     620            count = ntop;
    479621        }
    480622        /* show status for each of the processes */
    481         display_status(opt, col);
    482 #ifdef CONFIG_FEATURE_USE_TERMIOS
     623        display_status(count, col);
     624#if ENABLE_FEATURE_USE_TERMIOS
    483625        tv.tv_sec = interval;
    484626        tv.tv_usec = 0;
     
    493635                break;
    494636            if (c == 'M') {
    495 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     637#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    496638                sort_function[0] = mem_sort;
    497639                sort_function[1] = pcpu_sort;
     
    501643#endif
    502644            }
    503 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     645#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    504646            if (c == 'P') {
    505647                sort_function[0] = pcpu_sort;
     
    514656#endif
    515657            if (c == 'N') {
    516 #ifdef CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE
     658#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
    517659                sort_function[0] = pid_sort;
    518660#else
     
    521663            }
    522664        }
     665        if (!--iterations)
     666            break;
    523667#else
    524668        sleep(interval);
    525 #endif /* CONFIG_FEATURE_USE_TERMIOS */
     669#endif /* FEATURE_USE_TERMIOS */
    526670        clearmems();
    527671    }
Note: See TracChangeset for help on using the changeset viewer.