diff --git a/top/top.c b/top/top.c index ff701861..9a0ce86e 100644 --- a/top/top.c +++ b/top/top.c @@ -4412,6 +4412,7 @@ static void win_reset (WIN_t *q) { // NOHISEL_xxx is redundant (already turned off by osel_clear) OFFw(q, NOHIFND_xxx | NOHISEL_xxx); #endif + q->combine_cpus = 0; } // end: win_reset @@ -5224,6 +5225,15 @@ static void keys_summary (int ch) { WIN_t *w = Curwin; // avoid gcc bloat with a local copy switch (ch) { + case '!': + if (CHKw(w, View_CPUSUM) || CHKw(w, View_CPUNOD)) + show_msg(N_txt(XTRA_modebad_txt)); + else { + if (!w->combine_cpus) w->combine_cpus = 1; + else w->combine_cpus *= 2; + if (w->combine_cpus >= Cpu_faux_tot) w->combine_cpus = 0; + } + break; case '1': if (CHKw(w, View_CPUNOD)) OFFw(w, View_CPUSUM); else TOGw(w, View_CPUSUM); @@ -5673,6 +5683,136 @@ static void keys_xtra (int ch) { // show_msg(fmtmk("%s sort compatibility key honored", xmsg)); } // end: keys_xtra +/*###### Cpu Display Secondary support (summary_show helpers) ##########*/ + + /* + * Cpu *Helper* function to combine and or show the state + * percentages for 1 cpu or 2 adjacent cpus (one single line). */ +static inline int cpu_prt (const char *str, int nobuf) { + static char row[ROWMINSIZ]; + static int tog; + char *p; + + p = scat(row, str); + if (nobuf || !Curwin->double_up) + goto flush_it; + if (!tog) { + scat(p, Double_sp); + tog = 1; + return 0; + } +flush_it: + scat(p, "\n"); + show_special(0, row); + row[0] = '\0'; + tog = 0; + return 1; +} // end: cpu_prt + + + /* + * State display *Helper* function to calc and display the state + * percentages for a single cpu. In this way, we can support + * the following environments without the usual code bloat. + * 1) single cpu machines + * 2) modest smp boxes with room for each cpu's percentages + * 3) massive smp guys leaving little or no room for process + * display and thus requiring the cpu summary toggle */ +static int cpu_tics (CPU_t *cpu, const char *pfx, int nobuf) { + /* we'll trim to zero if we get negative time ticks, + which has happened with some SMP kernels (pre-2.4?) + and when cpus are dynamically added or removed */ + #define TRIMz(x) ((tz = (SIC_t)(x)) < 0 ? 0 : tz) + // user syst nice idle wait hirg sirq steal + SIC_t u_frme, s_frme, n_frme, i_frme, w_frme, x_frme, y_frme, z_frme, tot_frme, tz; + float scale; + int n; + + u_frme = TRIMz(cpu->cur.u - cpu->sav.u); + s_frme = TRIMz(cpu->cur.s - cpu->sav.s); + n_frme = TRIMz(cpu->cur.n - cpu->sav.n); + i_frme = TRIMz(cpu->cur.i - cpu->sav.i); + w_frme = TRIMz(cpu->cur.w - cpu->sav.w); + x_frme = TRIMz(cpu->cur.x - cpu->sav.x); + y_frme = TRIMz(cpu->cur.y - cpu->sav.y); + z_frme = TRIMz(cpu->cur.z - cpu->sav.z); + tot_frme = u_frme + s_frme + n_frme + i_frme + w_frme + x_frme + y_frme + z_frme; +#ifndef CPU_ZEROTICS + if (tot_frme < cpu->edge) + tot_frme = u_frme = s_frme = n_frme = i_frme = w_frme = x_frme = y_frme = z_frme = 0; +#endif + if (1 > tot_frme) i_frme = tot_frme = 1; + scale = 100.0 / (float)tot_frme; + + /* display some kinda' cpu state percentages + (who or what is explained by the passed prefix) */ + if (Curwin->rc.graph_cpus) { + static struct { + const char *user, *syst, *type; + } gtab[] = { + { "%-.*s~7", "%-.*s~8", Graph_bars }, + { "%-.*s~4", "%-.*s~6", Graph_blks } + }; + char user[SMLBUFSIZ], syst[SMLBUFSIZ], dual[MEDBUFSIZ]; + int ix = Curwin->rc.graph_cpus - 1; + float pct_user = (float)(u_frme + n_frme) * scale, + pct_syst = (float)(s_frme + x_frme + y_frme) * scale; +#ifndef QUICK_GRAPHS + int num_user = (int)((pct_user * Graph_adj) + .5), + num_syst = (int)((pct_syst * Graph_adj) + .5); + if (num_user + num_syst > Graph_len) num_syst = Graph_len - num_user; + snprintf(user, sizeof(user), gtab[ix].user, num_user, gtab[ix].type); + snprintf(syst, sizeof(syst), gtab[ix].syst, num_syst, gtab[ix].type); +#else + snprintf(user, sizeof(user), gtab[ix].user, (int)((pct_user * Graph_adj) + .5), gtab[ix].type); + snprintf(syst, sizeof(syst), gtab[ix].syst, (int)((pct_syst * Graph_adj) + .4), gtab[ix].type); +#endif + snprintf(dual, sizeof(dual), "%s%s", user, syst); + n = cpu_prt(fmtmk("%s ~3%#5.1f~2/%-#5.1f~3 %3.0f[~1%-*s]~1" + , pfx, pct_user, pct_syst, pct_user + pct_syst, Graph_len +4, dual), nobuf); + } else { + n = cpu_prt(fmtmk(Cpu_States_fmts, pfx + , (float)u_frme * scale, (float)s_frme * scale + , (float)n_frme * scale, (float)i_frme * scale + , (float)w_frme * scale, (float)x_frme * scale + , (float)y_frme * scale, (float)z_frme * scale), nobuf); + } + return n; + #undef TRIMz +} // end: cpu_tics + + + /* + * Cpu *Helper* function to combine adjacent cpu stats + * in an effort to reduce total number of processors shown */ +static int cpu_unify (CPU_t *cpu, int nobuf) { + static CPU_t accum; + static int ix, beg; + char pfx[16]; + int n; + + accum.cur.u += cpu->cur.u; accum.cur.s += cpu->cur.s; + accum.cur.n += cpu->cur.n; accum.cur.i += cpu->cur.i; + accum.cur.w += cpu->cur.w; accum.cur.x += cpu->cur.x; + accum.cur.y += cpu->cur.y; accum.cur.z += cpu->cur.z; + accum.sav.u += cpu->sav.u; accum.sav.s += cpu->sav.s; + accum.sav.n += cpu->sav.n; accum.sav.i += cpu->sav.i; + accum.sav.w += cpu->sav.w; accum.sav.x += cpu->sav.x; + accum.sav.y += cpu->sav.y; accum.sav.z += cpu->sav.z; + + if (!ix) beg = cpu->id; + if (nobuf || ix >= Curwin->combine_cpus) { + snprintf(pfx, sizeof(pfx), "%-7.7s:", fmtmk("%d-%d", beg, cpu->id)); + n = cpu_tics(&accum, pfx, nobuf); + memset(&accum, 0, sizeof(CPU_t)); + ix = beg = 0; + return n; + } + ++ix; + + return 0; +} // end: cpu_unify + /*###### Main Screen routines ##########################################*/ /* @@ -5687,7 +5827,7 @@ static void do_key (int ch) { , 'I', 'k', 'r', 's', 'X', 'Y', 'Z', '0' , kbd_ENTER, kbd_SPACE, '\0' } }, { keys_summary, - { '1', '2', '3', '4', 'C', 'l', 'm', 't', '\0' } }, + { '!', '1', '2', '3', '4', 'C', 'l', 'm', 't', '\0' } }, { keys_task, { '#', '<', '>', 'b', 'c', 'i', 'J', 'j', 'n', 'O', 'o' , 'R', 'S', 'U', 'u', 'V', 'v', 'x', 'y', 'z' @@ -5747,103 +5887,6 @@ all_done: } // end: do_key - /* - * Cpu *Helper* function to combine and or show the state - * percentages for 1 cpu or 2 adjacent cpus (one single line). */ -static inline int sum_cpu (const char *str, int nobuf) { - static char row[ROWMINSIZ]; - static int tog; - char *p; - - p = scat(row, str); - if (nobuf || !Curwin->double_up) - goto flush_it; - if (!tog) { - scat(p, Double_sp); - tog = 1; - return 0; - } -flush_it: - scat(p, "\n"); - show_special(0, row); - row[0] = '\0'; - tog = 0; - return 1; -} // end: sum_cpu - - - /* - * State display *Helper* function to calc and display the state - * percentages for a single cpu. In this way, we can support - * the following environments without the usual code bloat. - * 1) single cpu machines - * 2) modest smp boxes with room for each cpu's percentages - * 3) massive smp guys leaving little or no room for process - * display and thus requiring the cpu summary toggle */ -static int summary_hlp (CPU_t *cpu, const char *pfx, int nobuf) { - /* we'll trim to zero if we get negative time ticks, - which has happened with some SMP kernels (pre-2.4?) - and when cpus are dynamically added or removed */ - #define TRIMz(x) ((tz = (SIC_t)(x)) < 0 ? 0 : tz) - // user syst nice idle wait hirg sirq steal - SIC_t u_frme, s_frme, n_frme, i_frme, w_frme, x_frme, y_frme, z_frme, tot_frme, tz; - float scale; - int n; - - u_frme = TRIMz(cpu->cur.u - cpu->sav.u); - s_frme = TRIMz(cpu->cur.s - cpu->sav.s); - n_frme = TRIMz(cpu->cur.n - cpu->sav.n); - i_frme = TRIMz(cpu->cur.i - cpu->sav.i); - w_frme = TRIMz(cpu->cur.w - cpu->sav.w); - x_frme = TRIMz(cpu->cur.x - cpu->sav.x); - y_frme = TRIMz(cpu->cur.y - cpu->sav.y); - z_frme = TRIMz(cpu->cur.z - cpu->sav.z); - tot_frme = u_frme + s_frme + n_frme + i_frme + w_frme + x_frme + y_frme + z_frme; -#ifndef CPU_ZEROTICS - if (tot_frme < cpu->edge) - tot_frme = u_frme = s_frme = n_frme = i_frme = w_frme = x_frme = y_frme = z_frme = 0; -#endif - if (1 > tot_frme) i_frme = tot_frme = 1; - scale = 100.0 / (float)tot_frme; - - /* display some kinda' cpu state percentages - (who or what is explained by the passed prefix) */ - if (Curwin->rc.graph_cpus) { - static struct { - const char *user, *syst, *type; - } gtab[] = { - { "%-.*s~7", "%-.*s~8", Graph_bars }, - { "%-.*s~4", "%-.*s~6", Graph_blks } - }; - char user[SMLBUFSIZ], syst[SMLBUFSIZ], dual[MEDBUFSIZ]; - int ix = Curwin->rc.graph_cpus - 1; - float pct_user = (float)(u_frme + n_frme) * scale, - pct_syst = (float)(s_frme + x_frme + y_frme) * scale; -#ifndef QUICK_GRAPHS - int num_user = (int)((pct_user * Graph_adj) + .5), - num_syst = (int)((pct_syst * Graph_adj) + .5); - if (num_user + num_syst > Graph_len) num_syst = Graph_len - num_user; - snprintf(user, sizeof(user), gtab[ix].user, num_user, gtab[ix].type); - snprintf(syst, sizeof(syst), gtab[ix].syst, num_syst, gtab[ix].type); -#else - snprintf(user, sizeof(user), gtab[ix].user, (int)((pct_user * Graph_adj) + .5), gtab[ix].type); - snprintf(syst, sizeof(syst), gtab[ix].syst, (int)((pct_syst * Graph_adj) + .4), gtab[ix].type); -#endif - snprintf(dual, sizeof(dual), "%s%s", user, syst); - n = sum_cpu(fmtmk("%%%s ~3%#5.1f~2/%-#5.1f~3 %3.0f[~1%-*s]~1" - , pfx, pct_user, pct_syst, pct_user + pct_syst, Graph_len +4, dual), nobuf); - } else { - n = sum_cpu(fmtmk(Cpu_States_fmts, pfx - , (float)u_frme * scale, (float)s_frme * scale - , (float)n_frme * scale, (float)i_frme * scale - , (float)w_frme * scale, (float)x_frme * scale - , (float)y_frme * scale, (float)z_frme * scale), nobuf); - } - return n; - #undef TRIMz -} // end: summary_hlp - - /* * In support of a new frame: * 1) Display uptime and load average (maybe) @@ -5881,7 +5924,7 @@ static void summary_show (void) { if (CHKw(w, View_CPUNOD)) { if (Numa_node_sel < 0) { // display the 1st /proc/stat line, then the nodes (if room) - Msg_row += summary_hlp(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt), 1); + Msg_row += cpu_tics(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt), 1); // display each cpu node's states for (i = 0; i < Numa_node_tot; i++) { CPU_t *nod_ptr = &Cpu_tics[1 + smp_num_cpus + i]; @@ -5890,7 +5933,7 @@ static void summary_show (void) { if (nod_ptr->id) { #endif snprintf(tmp, sizeof(tmp), N_fmt(NUMA_nodenam_fmt), i); - Msg_row += summary_hlp(nod_ptr, tmp, 1); + Msg_row += cpu_tics(nod_ptr, tmp, 1); #ifndef OFF_NUMASKIP } #endif @@ -5898,12 +5941,12 @@ static void summary_show (void) { } else { // display the node summary, then the associated cpus (if room) snprintf(tmp, sizeof(tmp), N_fmt(NUMA_nodenam_fmt), Numa_node_sel); - Msg_row += summary_hlp(&Cpu_tics[1 + smp_num_cpus + Numa_node_sel], tmp, 1); + Msg_row += cpu_tics(&Cpu_tics[1 + smp_num_cpus + Numa_node_sel], tmp, 1); for (i = 0; i < Cpu_faux_tot; i++) { if (Numa_node_sel == Cpu_tics[i].node) { if (!isROOM(anyFLG, 1)) break; snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), Cpu_tics[i].id); - Msg_row += summary_hlp(&Cpu_tics[i], tmp, 1); + Msg_row += cpu_tics(&Cpu_tics[i], tmp, 1); } } } @@ -5911,13 +5954,20 @@ static void summary_show (void) { numa_nope: if (CHKw(w, View_CPUSUM)) { // display just the 1st /proc/stat line - Msg_row += summary_hlp(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt), 1); + Msg_row += cpu_tics(&Cpu_tics[smp_num_cpus], N_txt(WORD_allcpus_txt), 1); } else { // display each cpu's states separately, screen height permitting... - for (i = 0; i < Cpu_faux_tot; i++) { - snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), Cpu_tics[i].id); - Msg_row += summary_hlp(&Cpu_tics[i], tmp, (i+1 >= Cpu_faux_tot)); - if (!isROOM(anyFLG, 1)) break; + if (w->combine_cpus) { + for (i = 0; i < Cpu_faux_tot; i++) { + Msg_row += cpu_unify(&Cpu_tics[i], (i+1 >= Cpu_faux_tot)); + if (!isROOM(anyFLG, 1)) break; + } + } else { + for (i = 0; i < Cpu_faux_tot; i++) { + snprintf(tmp, sizeof(tmp), N_fmt(WORD_eachcpu_fmt), Cpu_tics[i].id); + Msg_row += cpu_tics(&Cpu_tics[i], tmp, (i+1 >= Cpu_faux_tot)); + if (!isROOM(anyFLG, 1)) break; + } } } } // end: View_STATES diff --git a/top/top.h b/top/top.h index 1f36957d..7ec39922 100644 --- a/top/top.h +++ b/top/top.h @@ -437,6 +437,7 @@ typedef struct WIN_t { char *findstr; // window's current/active search string int findlen; // above's strlen, without call overhead int double_up; // show individual cpus 2 abreast + int combine_cpus; // keep combining adjacent cpus proc_t **ppt; // this window's proc_t ptr array struct WIN_t *next, // next window in window stack *prev; // prior window in window stack @@ -804,10 +805,12 @@ typedef struct WIN_t { //atic void keys_task (int ch); //atic void keys_window (int ch); //atic void keys_xtra (int ch); +/*------ Cpu Display Secondary Support (summary_show helpers) ----------*/ +//atic inline int cpu_prt (const char *str, int nobuf); +//atic int cpu_tics (CPU_t *cpu, const char *pfx, int nobuf); +//atic int cpu_unify (CPU_t *cpu, int nobuf); /*------ Main Screen routines ------------------------------------------*/ //atic void do_key (int ch); -//atic inline int sum_cpu (const char *str, int nobuf); -//atic int summary_hlp (CPU_t *cpu, const char *pfx, int nobuf); //atic void summary_show (void); //atic const char *task_show (const WIN_t *q, const int idx); //atic void window_hlp (void); diff --git a/top/top_nls.c b/top/top_nls.c index 32f9a569..51b7a0c6 100644 --- a/top/top_nls.c +++ b/top/top_nls.c @@ -413,11 +413,11 @@ static void build_norm_nlstab (void) { Norm_nlstab[WORD_process_txt] = _("Tasks"); /* Translation Hint: The following "word" is meant to represent either a single . cpu or all of the processors in a multi-processor computer - . (should be exactly 6 characters, not counting the colon)*/ - Norm_nlstab[WORD_allcpus_txt] = _("Cpu(s):"); + . (should be exactly 6 characters, excluding leading % & colon) */ + Norm_nlstab[WORD_allcpus_txt] = _("%Cpu(s):"); /* Translation Hint: The following "word" is meant to represent a single processor - . (should be exactly 3 characters) */ - Norm_nlstab[WORD_eachcpu_fmt] = _("Cpu%-3d:"); + . (should be exactly 3 characters, excluding leading %%, fmt chars & colon) */ + Norm_nlstab[WORD_eachcpu_fmt] = _("%%Cpu%-3d:"); /* Translation Hint: The following word "another" must have 1 trailing space */ Norm_nlstab[WORD_another_txt] = _("another "); Norm_nlstab[FIND_no_next_txt] = _("Locate next inactive, use \"L\""); @@ -487,8 +487,9 @@ static void build_norm_nlstab (void) { Norm_nlstab[WORD_exclude_txt] = _("exclude"); Norm_nlstab[OSEL_statlin_fmt] = _(" to resume, filters: %s"); Norm_nlstab[WORD_noneone_txt] = _("none"); -/* Translation Hint: The following word 'Node' should be exactly 4 characters */ - Norm_nlstab[NUMA_nodenam_fmt] = _("Node%-2d:"); +/* Translation Hint: The following word 'Node' should be exactly + 4 characters, excluding leading %%, fmt chars & colon) */ + Norm_nlstab[NUMA_nodenam_fmt] = _("%%Node%-2d:"); Norm_nlstab[NUMA_nodeget_fmt] = _("expand which node (0-%d)"); Norm_nlstab[NUMA_nodebad_txt] = _("invalid node"); Norm_nlstab[NUMA_nodenot_txt] = _("sorry, NUMA extensions unavailable"); @@ -501,6 +502,7 @@ static void build_norm_nlstab (void) { Norm_nlstab[BAD_memscale_fmt] = _("bad memory scaling arg '%c'"); Norm_nlstab[XTRA_vforest_fmt] = _("PID to collapse/expand [default pid = %d]"); Norm_nlstab[XTRA_size2up_txt] = _("terminal is not wide enough"); + Norm_nlstab[XTRA_modebad_txt] = _("wrong mode, command inactive"); } @@ -564,7 +566,7 @@ static void build_uniq_nlstab (void) { " V,v . Toggle: '~1V~2' forest view; '~1v~2' hide/show forest view children\n" "\n" "%s" - " W,Y Write configuration file '~1W~2'; Inspect other output '~1Y~2'\n" + " W,Y,! Write config file '~1W~2'; Inspect other output '~1Y~2'; Combine Cpus '~1!~2'\n" " q Quit\n" " ( commands shown with '.' require a ~1visible~2 task display ~1window~2 ) \n" "Press '~1h~2' or '~1?~2' for help with ~1Windows~2,\n" @@ -654,22 +656,22 @@ static void build_uniq_nlstab (void) { Uniq_nlstab[STATE_line_1_fmt] = _("%s:~3" " %3u ~2total,~3 %3u ~2running,~3 %3u ~2sleeping,~3 %3u ~2stopped,~3 %3u ~2zombie~3\n"); - Uniq_nlstab[STATE_lin2x4_fmt] = _("%%%s~3" + Uniq_nlstab[STATE_lin2x4_fmt] = _("%s~3" " %#5.1f ~2user,~3 %#5.1f ~2system,~3 %#5.1f ~2nice,~3 %#5.1f ~2idle~3"); - Uniq_nlstab[STATE_lin2x5_fmt] = _("%%%s~3" + Uniq_nlstab[STATE_lin2x5_fmt] = _("%s~3" " %#5.1f ~2user,~3 %#5.1f ~2system,~3 %#5.1f ~2nice,~3 %#5.1f ~2idle,~3 %#5.1f ~2IO-wait~3"); /* Translation Hint: Only the following abbreviations need be translated . us = user, sy = system, ni = nice, id = idle, wa = wait, . hi hardware interrupt, si = software interrupt */ - Uniq_nlstab[STATE_lin2x6_fmt] = _("%%%s~3" + Uniq_nlstab[STATE_lin2x6_fmt] = _("%s~3" " %#5.1f ~2us,~3 %#5.1f ~2sy,~3 %#5.1f ~2ni,~3 %#5.1f ~2id,~3 %#5.1f ~2wa,~3 %#5.1f ~2hi,~3 %#5.1f ~2si~3"); /* Translation Hint: Only the following abbreviations need be translated . us = user, sy = system, ni = nice, id = idle, wa = wait, . hi hardware interrupt, si = software interrupt, st = steal time */ - Uniq_nlstab[STATE_lin2x7_fmt] = _("%%%s~3" + Uniq_nlstab[STATE_lin2x7_fmt] = _("%s~3" "%#5.1f ~2us,~3%#5.1f ~2sy,~3%#5.1f ~2ni,~3%#5.1f ~2id,~3%#5.1f ~2wa,~3%#5.1f ~2hi,~3%#5.1f ~2si,~3%#5.1f ~2st~3"); /* Translation Hint: this must be translated as 2 lines with words above & below aligned */ diff --git a/top/top_nls.h b/top/top_nls.h index cf5207de..2783368b 100644 --- a/top/top_nls.h +++ b/top/top_nls.h @@ -82,8 +82,8 @@ enum norm_nls { WORD_abv_mem_txt, WORD_abv_swp_txt, WORD_allcpus_txt, WORD_another_txt, WORD_eachcpu_fmt, WORD_exclude_txt, WORD_include_txt, WORD_noneone_txt, WORD_process_txt, WORD_threads_txt, WRITE_rcfile_fmt, WRONG_switch_fmt, - XTRA_badflds_fmt, XTRA_fixwide_fmt, XTRA_size2up_txt, XTRA_vforest_fmt, - XTRA_warncfg_txt, XTRA_winsize_txt, + XTRA_badflds_fmt, XTRA_fixwide_fmt, XTRA_modebad_txt, XTRA_size2up_txt, + XTRA_vforest_fmt, XTRA_warncfg_txt, XTRA_winsize_txt, #ifndef INSP_OFFDEMO YINSP_demo01_txt, YINSP_demo02_txt, YINSP_demo03_txt, YINSP_deqfmt_txt, YINSP_deqtyp_txt, YINSP_dstory_txt,