Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/procps/top.c


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

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

    r821 r1765  
    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.