diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-09-25 10:48:06 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-09-25 10:48:06 +0000 |
commit | 17e7f04c8d144e0e0598464806dcb111ed5386d7 (patch) | |
tree | 002284cda156b2516c1d3a67352288741d7cd2e5 | |
parent | e0bcba18eb9c185cefbef2ef05b846f735bd133a (diff) | |
download | busybox-w32-17e7f04c8d144e0e0598464806dcb111ed5386d7.tar.gz busybox-w32-17e7f04c8d144e0e0598464806dcb111ed5386d7.tar.bz2 busybox-w32-17e7f04c8d144e0e0598464806dcb111ed5386d7.zip |
top: optional SMP support by Vineet Gupta (vineetg76 AT gmail.com)
-rw-r--r-- | include/libbb.h | 15 | ||||
-rw-r--r-- | libbb/procps.c | 33 | ||||
-rw-r--r-- | procps/Config.in | 17 | ||||
-rw-r--r-- | procps/top.c | 344 |
4 files changed, 312 insertions, 97 deletions
diff --git a/include/libbb.h b/include/libbb.h index 3b4715e33..951ff2f1a 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1225,6 +1225,9 @@ typedef struct procps_status_t { | |||
1225 | * by link target or interpreter name) */ | 1225 | * by link target or interpreter name) */ |
1226 | char comm[COMM_LEN]; | 1226 | char comm[COMM_LEN]; |
1227 | /* user/group? - use passwd/group parsing functions */ | 1227 | /* user/group? - use passwd/group parsing functions */ |
1228 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
1229 | int last_seen_on_cpu; | ||
1230 | #endif | ||
1228 | } procps_status_t; | 1231 | } procps_status_t; |
1229 | enum { | 1232 | enum { |
1230 | PSSCAN_PID = 1 << 0, | 1233 | PSSCAN_PID = 1 << 0, |
@@ -1246,12 +1249,16 @@ enum { | |||
1246 | PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP || ENABLE_PKILL || ENABLE_PIDOF), | 1249 | PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP || ENABLE_PKILL || ENABLE_PIDOF), |
1247 | USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,) | 1250 | USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,) |
1248 | PSSCAN_START_TIME = 1 << 18, | 1251 | PSSCAN_START_TIME = 1 << 18, |
1252 | PSSCAN_CPU = 1 << 19, | ||
1249 | /* These are all retrieved from proc/NN/stat in one go: */ | 1253 | /* These are all retrieved from proc/NN/stat in one go: */ |
1250 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID | 1254 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID |
1251 | | PSSCAN_COMM | PSSCAN_STATE | 1255 | /**/ | PSSCAN_COMM | PSSCAN_STATE |
1252 | | PSSCAN_VSZ | PSSCAN_RSS | 1256 | /**/ | PSSCAN_VSZ | PSSCAN_RSS |
1253 | | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME | 1257 | /**/ | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME |
1254 | | PSSCAN_TTY, | 1258 | /**/ | PSSCAN_TTY |
1259 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
1260 | /**/ | PSSCAN_CPU | ||
1261 | #endif | ||
1255 | }; | 1262 | }; |
1256 | //procps_status_t* alloc_procps_scan(void) FAST_FUNC; | 1263 | //procps_status_t* alloc_procps_scan(void) FAST_FUNC; |
1257 | void free_procps_scan(procps_status_t* sp) FAST_FUNC; | 1264 | void free_procps_scan(procps_status_t* sp) FAST_FUNC; |
diff --git a/libbb/procps.c b/libbb/procps.c index fd19621db..4d9a95b4f 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -219,7 +219,6 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
219 | #if !ENABLE_FEATURE_FAST_TOP | 219 | #if !ENABLE_FEATURE_FAST_TOP |
220 | unsigned long vsz, rss; | 220 | unsigned long vsz, rss; |
221 | #endif | 221 | #endif |
222 | |||
223 | /* see proc(5) for some details on this */ | 222 | /* see proc(5) for some details on this */ |
224 | strcpy(filename_tail, "/stat"); | 223 | strcpy(filename_tail, "/stat"); |
225 | n = read_to_buf(filename, buf); | 224 | n = read_to_buf(filename, buf); |
@@ -247,9 +246,12 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
247 | "%lu " /* start_time */ | 246 | "%lu " /* start_time */ |
248 | "%lu " /* vsize */ | 247 | "%lu " /* vsize */ |
249 | "%lu " /* rss */ | 248 | "%lu " /* rss */ |
250 | /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 249 | #if ENABLE_FEATURE_TOP_SMP_PROCESS |
251 | /* "%u %u %u %u " signal, blocked, sigignore, sigcatch */ | 250 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
252 | /* "%lu %lu %lu" wchan, nswap, cnswap */ | 251 | "%*s %*s %*s %*s " /*signal, blocked, sigignore, sigcatch */ |
252 | "%*s %*s %*s %*s " /*wchan, nswap, cnswap, exit_signal */ | ||
253 | "%d" /*cpu last seen on*/ | ||
254 | #endif | ||
253 | , | 255 | , |
254 | sp->state, &sp->ppid, | 256 | sp->state, &sp->ppid, |
255 | &sp->pgid, &sp->sid, &tty, | 257 | &sp->pgid, &sp->sid, &tty, |
@@ -257,9 +259,19 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
257 | &tasknice, | 259 | &tasknice, |
258 | &sp->start_time, | 260 | &sp->start_time, |
259 | &vsz, | 261 | &vsz, |
260 | &rss); | 262 | &rss |
261 | if (n != 11) | 263 | #if ENABLE_FEATURE_TOP_SMP_PROCESS |
264 | , &sp->last_seen_on_cpu | ||
265 | #endif | ||
266 | ); | ||
267 | |||
268 | if (n < 11) | ||
262 | break; | 269 | break; |
270 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
271 | if (n < 11+15) | ||
272 | sp->last_seen_on_cpu = 0; | ||
273 | #endif | ||
274 | |||
263 | /* vsz is in bytes and we want kb */ | 275 | /* vsz is in bytes and we want kb */ |
264 | sp->vsz = vsz >> 10; | 276 | sp->vsz = vsz >> 10; |
265 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 277 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
@@ -288,7 +300,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
288 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 300 | sp->vsz = fast_strtoul_10(&cp) >> 10; |
289 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 301 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
290 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; | 302 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; |
303 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
304 | /* (6): rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | ||
305 | /* (4): signal, blocked, sigignore, sigcatch */ | ||
306 | /* (4): wchan, nswap, cnswap, exit_signal */ | ||
307 | cp = skip_fields(cp, 14); | ||
308 | //FIXME: is it safe to assume this field exists? | ||
309 | sp->last_seen_on_cpu = fast_strtoul_10(&cp); | ||
291 | #endif | 310 | #endif |
311 | #endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */ | ||
292 | 312 | ||
293 | if (sp->vsz == 0 && sp->state[0] != 'Z') | 313 | if (sp->vsz == 0 && sp->state[0] != 'Z') |
294 | sp->state[1] = 'W'; | 314 | sp->state[1] = 'W'; |
@@ -300,7 +320,6 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
300 | sp->state[2] = 'N'; | 320 | sp->state[2] = 'N'; |
301 | else | 321 | else |
302 | sp->state[2] = ' '; | 322 | sp->state[2] = ' '; |
303 | |||
304 | } | 323 | } |
305 | 324 | ||
306 | #if ENABLE_FEATURE_TOPMEM | 325 | #if ENABLE_FEATURE_TOPMEM |
diff --git a/procps/Config.in b/procps/Config.in index 642ebd015..548463c67 100644 --- a/procps/Config.in +++ b/procps/Config.in | |||
@@ -148,6 +148,13 @@ config FEATURE_TOP_CPU_GLOBAL_PERCENTS | |||
148 | help | 148 | help |
149 | Makes top display "CPU: NN% usr NN% sys..." line. | 149 | Makes top display "CPU: NN% usr NN% sys..." line. |
150 | 150 | ||
151 | config FEATURE_TOP_SMP_CPU | ||
152 | bool "SMP CPU usage display ('c' key) (adds 0.5kb)" | ||
153 | default n | ||
154 | depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS | ||
155 | help | ||
156 | Allos 'c' key to switch between individual/cumulative CPU stats | ||
157 | |||
151 | config FEATURE_TOP_DECIMALS | 158 | config FEATURE_TOP_DECIMALS |
152 | bool "Show 1/10th of a percent in CPU/mem statistics (adds 0.3k bytes)" | 159 | bool "Show 1/10th of a percent in CPU/mem statistics (adds 0.3k bytes)" |
153 | default n | 160 | default n |
@@ -155,8 +162,15 @@ config FEATURE_TOP_DECIMALS | |||
155 | help | 162 | help |
156 | Show 1/10th of a percent in CPU/mem statistics. | 163 | Show 1/10th of a percent in CPU/mem statistics. |
157 | 164 | ||
165 | config FEATURE_TOP_SMP_PROCESS | ||
166 | bool "Show CPU process runs on (adds <0.1k bytes)" | ||
167 | default n | ||
168 | depends on TOP | ||
169 | help | ||
170 | Show CPU where process was last found running on | ||
171 | |||
158 | config FEATURE_TOPMEM | 172 | config FEATURE_TOPMEM |
159 | bool "topmem" | 173 | bool "Topmem command ('s' key)" |
160 | default n | 174 | default n |
161 | depends on TOP | 175 | depends on TOP |
162 | help | 176 | help |
@@ -180,4 +194,3 @@ config WATCH | |||
180 | 194 | ||
181 | 195 | ||
182 | endmenu | 196 | endmenu |
183 | |||
diff --git a/procps/top.c b/procps/top.c index 663eac674..c881ad419 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -16,6 +16,12 @@ | |||
16 | * (C) Eero Tamminen <oak at welho dot com> | 16 | * (C) Eero Tamminen <oak at welho dot com> |
17 | * | 17 | * |
18 | * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru> | 18 | * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru> |
19 | * | ||
20 | * Sept 2008: Vineet Gupta <vineet.gupta@arc.com> | ||
21 | * Added Support for reporting SMP Information | ||
22 | * - CPU where Process was last seen running | ||
23 | * (to see effect of sched_setaffinity() etc) | ||
24 | * - CPU Time Split (idle/IO/wait etc) PER CPU | ||
19 | */ | 25 | */ |
20 | 26 | ||
21 | /* Original code Copyrights */ | 27 | /* Original code Copyrights */ |
@@ -41,6 +47,9 @@ typedef struct top_status_t { | |||
41 | unsigned uid; | 47 | unsigned uid; |
42 | char state[4]; | 48 | char state[4]; |
43 | char comm[COMM_LEN]; | 49 | char comm[COMM_LEN]; |
50 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
51 | int last_seen_on_cpu; | ||
52 | #endif | ||
44 | } top_status_t; | 53 | } top_status_t; |
45 | 54 | ||
46 | typedef struct jiffy_counts_t { | 55 | typedef struct jiffy_counts_t { |
@@ -69,6 +78,9 @@ struct globals { | |||
69 | smallint sort_field; | 78 | smallint sort_field; |
70 | smallint inverted; | 79 | smallint inverted; |
71 | #endif | 80 | #endif |
81 | #if ENABLE_FEATURE_TOP_SMP_CPU | ||
82 | smallint smp_cpu_info; /* one/many cpu info lines? */ | ||
83 | #endif | ||
72 | #if ENABLE_FEATURE_USE_TERMIOS | 84 | #if ENABLE_FEATURE_USE_TERMIOS |
73 | struct termios initial_settings; | 85 | struct termios initial_settings; |
74 | #endif | 86 | #endif |
@@ -83,6 +95,11 @@ struct globals { | |||
83 | unsigned total_pcpu; | 95 | unsigned total_pcpu; |
84 | /* unsigned long total_vsz; */ | 96 | /* unsigned long total_vsz; */ |
85 | #endif | 97 | #endif |
98 | #if ENABLE_FEATURE_TOP_SMP_CPU | ||
99 | /* Per CPU samples: current and last */ | ||
100 | jiffy_counts_t *cpu_jif, *cpu_prev_jif; | ||
101 | int num_cpus; | ||
102 | #endif | ||
86 | char line_buf[80]; | 103 | char line_buf[80]; |
87 | }; | 104 | }; |
88 | 105 | ||
@@ -98,12 +115,16 @@ enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; | |||
98 | #define ntop (G.ntop ) | 115 | #define ntop (G.ntop ) |
99 | #define sort_field (G.sort_field ) | 116 | #define sort_field (G.sort_field ) |
100 | #define inverted (G.inverted ) | 117 | #define inverted (G.inverted ) |
118 | #define smp_cpu_info (G.smp_cpu_info ) | ||
101 | #define initial_settings (G.initial_settings ) | 119 | #define initial_settings (G.initial_settings ) |
102 | #define sort_function (G.sort_function ) | 120 | #define sort_function (G.sort_function ) |
103 | #define prev_hist (G.prev_hist ) | 121 | #define prev_hist (G.prev_hist ) |
104 | #define prev_hist_count (G.prev_hist_count ) | 122 | #define prev_hist_count (G.prev_hist_count ) |
105 | #define jif (G.jif ) | 123 | #define jif (G.jif ) |
106 | #define prev_jif (G.prev_jif ) | 124 | #define prev_jif (G.prev_jif ) |
125 | #define cpu_jif (G.cpu_jif ) | ||
126 | #define cpu_prev_jif (G.cpu_prev_jif ) | ||
127 | #define num_cpus (G.num_cpus ) | ||
107 | #define total_pcpu (G.total_pcpu ) | 128 | #define total_pcpu (G.total_pcpu ) |
108 | #define line_buf (G.line_buf ) | 129 | #define line_buf (G.line_buf ) |
109 | 130 | ||
@@ -161,24 +182,94 @@ static int mult_lvl_cmp(void* a, void* b) | |||
161 | return 0; | 182 | return 0; |
162 | } | 183 | } |
163 | 184 | ||
185 | /* NOINLINE so that complier doesn't unfold the call | ||
186 | * causing multiple copies of the arithmatic instrns | ||
187 | */ | ||
188 | static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) | ||
189 | { | ||
190 | #if !ENABLE_FEATURE_TOP_SMP_CPU | ||
191 | static const char fmt[] = "cpu %lld %lld %lld %lld %lld %lld %lld %lld"; | ||
192 | #else | ||
193 | static const char fmt[] = "cp%*s %lld %lld %lld %lld %lld %lld %lld %lld"; | ||
194 | #endif | ||
195 | int ret; | ||
196 | |||
197 | if (!fgets(line_buf, LINE_BUF_SIZE, fp) || line_buf[0] != 'c' /* not "cpu" */) | ||
198 | return 0; | ||
199 | ret = sscanf(line_buf, fmt, | ||
200 | &p_jif->usr, &p_jif->nic, &p_jif->sys, &p_jif->idle, | ||
201 | &p_jif->iowait, &p_jif->irq, &p_jif->softirq, | ||
202 | &p_jif->steal); | ||
203 | if (ret > 4) { | ||
204 | p_jif->total = p_jif->usr + p_jif->nic + p_jif->sys + p_jif->idle | ||
205 | + p_jif->iowait + p_jif->irq + p_jif->softirq + p_jif->steal; | ||
206 | /* procps 2.x does not count iowait as busy time */ | ||
207 | p_jif->busy = p_jif->total - p_jif->idle - p_jif->iowait; | ||
208 | } | ||
209 | |||
210 | return ret; | ||
211 | } | ||
164 | 212 | ||
165 | static void get_jiffy_counts(void) | 213 | static void get_jiffy_counts(void) |
166 | { | 214 | { |
167 | FILE* fp = xfopen_for_read("stat"); | 215 | FILE* fp = xfopen_for_read("stat"); |
216 | |||
217 | #if !ENABLE_FEATURE_TOP_SMP_CPU | ||
168 | prev_jif = jif; | 218 | prev_jif = jif; |
169 | if (fscanf(fp, "cpu %lld %lld %lld %lld %lld %lld %lld %lld", | 219 | if (read_cpu_jiffy(fp, &jif) < 4) |
170 | &jif.usr,&jif.nic,&jif.sys,&jif.idle, | ||
171 | &jif.iowait,&jif.irq,&jif.softirq,&jif.steal) < 4) { | ||
172 | bb_error_msg_and_die("can't read /proc/stat"); | 220 | bb_error_msg_and_die("can't read /proc/stat"); |
221 | fclose(fp); | ||
222 | return; | ||
223 | #else | ||
224 | if (!smp_cpu_info) { /* user wants to see cumulative cpu info */ | ||
225 | prev_jif = jif; | ||
226 | if (read_cpu_jiffy(fp, &jif) < 4) | ||
227 | bb_error_msg_and_die("can't read /proc/stat"); | ||
228 | fclose(fp); | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | /* Discard first "cpu ..." line */ | ||
233 | fgets(line_buf, LINE_BUF_SIZE, fp); | ||
234 | |||
235 | if (!num_cpus) { | ||
236 | /* First time here. How many CPUs? | ||
237 | * There will be at least 1 /proc/stat line with cpu%d | ||
238 | */ | ||
239 | while (1) { | ||
240 | cpu_jif = xrealloc_vector(cpu_jif, 1, num_cpus); | ||
241 | if (read_cpu_jiffy(fp, &cpu_jif[num_cpus]) <= 4) | ||
242 | break; | ||
243 | num_cpus++; | ||
244 | } | ||
245 | if (num_cpus == 0) /* /proc/stat with only "cpu ..." line?! */ | ||
246 | smp_cpu_info = 0; | ||
247 | |||
248 | /* TODO: need to cap num_cpus to a reasonable num | ||
249 | * on massively paralle machines so that we dont | ||
250 | * swamp the terminal with cpu "only" info | ||
251 | */ | ||
252 | cpu_prev_jif = xzalloc(sizeof(cpu_prev_jif[0]) * num_cpus); | ||
253 | |||
254 | /* Otherwise the first per cpu display shows all 100% idles */ | ||
255 | usleep(50000); | ||
256 | } else { /* Non first time invocation */ | ||
257 | jiffy_counts_t *tmp; | ||
258 | int i; | ||
259 | |||
260 | /* First switch the sample pointers: no need to copy */ | ||
261 | tmp = cpu_prev_jif; | ||
262 | cpu_prev_jif = cpu_jif; | ||
263 | cpu_jif = tmp; | ||
264 | |||
265 | /* Get the new samples */ | ||
266 | for (i = 0; i < num_cpus; i++) | ||
267 | read_cpu_jiffy(fp, &cpu_jif[i]); | ||
173 | } | 268 | } |
269 | #endif | ||
174 | fclose(fp); | 270 | fclose(fp); |
175 | jif.total = jif.usr + jif.nic + jif.sys + jif.idle | ||
176 | + jif.iowait + jif.irq + jif.softirq + jif.steal; | ||
177 | /* procps 2.x does not count iowait as busy time */ | ||
178 | jif.busy = jif.total - jif.idle - jif.iowait; | ||
179 | } | 271 | } |
180 | 272 | ||
181 | |||
182 | static void do_stats(void) | 273 | static void do_stats(void) |
183 | { | 274 | { |
184 | top_status_t *cur; | 275 | top_status_t *cur; |
@@ -189,7 +280,7 @@ static void do_stats(void) | |||
189 | get_jiffy_counts(); | 280 | get_jiffy_counts(); |
190 | total_pcpu = 0; | 281 | total_pcpu = 0; |
191 | /* total_vsz = 0; */ | 282 | /* total_vsz = 0; */ |
192 | new_hist = xmalloc(sizeof(struct save_hist)*ntop); | 283 | new_hist = xmalloc(sizeof(new_hist[0]) * ntop); |
193 | /* | 284 | /* |
194 | * Make a pass through the data to get stats. | 285 | * Make a pass through the data to get stats. |
195 | */ | 286 | */ |
@@ -230,6 +321,7 @@ static void do_stats(void) | |||
230 | prev_hist = new_hist; | 321 | prev_hist = new_hist; |
231 | prev_hist_count = ntop; | 322 | prev_hist_count = ntop; |
232 | } | 323 | } |
324 | |||
233 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 325 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
234 | 326 | ||
235 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS | 327 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS |
@@ -257,15 +349,92 @@ static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total) | |||
257 | } | 349 | } |
258 | #endif | 350 | #endif |
259 | 351 | ||
260 | static unsigned long display_header(int scr_width) | 352 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS |
353 | static void display_cpus(int scr_width, char *scrbuf, int *lines_rem_p) | ||
354 | { | ||
355 | /* | ||
356 | * xxx% = (jif.xxx - prev_jif.xxx) / (jif.total - prev_jif.total) * 100% | ||
357 | */ | ||
358 | unsigned total_diff; | ||
359 | jiffy_counts_t *p_jif, *p_prev_jif; | ||
360 | int i; | ||
361 | |||
362 | #if ENABLE_FEATURE_TOP_SMP_CPU | ||
363 | int n_cpu_lines; | ||
364 | #endif | ||
365 | |||
366 | /* using (unsigned) casts to make operations cheaper */ | ||
367 | #define CALC_TOT_DIFF ((unsigned)(p_jif->total - p_prev_jif->total) ? : 1) | ||
368 | |||
369 | #if ENABLE_FEATURE_TOP_DECIMALS | ||
370 | #define CALC_STAT(xxx) char xxx[8] | ||
371 | #define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(p_jif->xxx - p_prev_jif->xxx), total_diff) | ||
372 | #define FMT "%s" | ||
373 | #else | ||
374 | #define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(p_jif->xxx - p_prev_jif->xxx) / total_diff | ||
375 | #define SHOW_STAT(xxx) xxx | ||
376 | #define FMT "%4u%% " | ||
377 | #endif | ||
378 | |||
379 | #if !ENABLE_FEATURE_TOP_SMP_CPU | ||
380 | { | ||
381 | i = 1; | ||
382 | p_jif = &jif; | ||
383 | p_prev_jif = &prev_jif; | ||
384 | #else | ||
385 | /* Loop thru CPU(s) */ | ||
386 | n_cpu_lines = smp_cpu_info ? num_cpus : 1; | ||
387 | if (n_cpu_lines > *lines_rem_p) | ||
388 | n_cpu_lines = *lines_rem_p; | ||
389 | |||
390 | for (i = 0; i < n_cpu_lines; i++) { | ||
391 | /* set the real loop end */ | ||
392 | p_jif = &cpu_jif[i]; | ||
393 | p_prev_jif = &cpu_prev_jif[i]; | ||
394 | #endif | ||
395 | total_diff = CALC_TOT_DIFF; | ||
396 | |||
397 | { /* Need block: CALC_STAT are declarations */ | ||
398 | CALC_STAT(usr); | ||
399 | CALC_STAT(sys); | ||
400 | CALC_STAT(nic); | ||
401 | CALC_STAT(idle); | ||
402 | CALC_STAT(iowait); | ||
403 | CALC_STAT(irq); | ||
404 | CALC_STAT(softirq); | ||
405 | /*CALC_STAT(steal);*/ | ||
406 | |||
407 | snprintf(scrbuf, scr_width, | ||
408 | /* Barely fits in 79 chars when in "decimals" mode. */ | ||
409 | #if ENABLE_FEATURE_TOP_SMP_CPU | ||
410 | "CPU%s:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq", | ||
411 | (smp_cpu_info ? utoa(i) : ""), | ||
412 | #else | ||
413 | "CPU:"FMT"usr"FMT"sys"FMT"nic"FMT"idle"FMT"io"FMT"irq"FMT"sirq", | ||
414 | #endif | ||
415 | SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle), | ||
416 | SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq) | ||
417 | /*, SHOW_STAT(steal) - what is this 'steal' thing? */ | ||
418 | /* I doubt anyone wants to know it */ | ||
419 | ); | ||
420 | puts(scrbuf); | ||
421 | } | ||
422 | } | ||
423 | #undef SHOW_STAT | ||
424 | #undef CALC_STAT | ||
425 | #undef FMT | ||
426 | *lines_rem_p -= i; | ||
427 | } | ||
428 | #else /* !ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS */ | ||
429 | #define display_cpus(scr_width, scrbuf, lines_rem) ((void)0) | ||
430 | #endif | ||
431 | |||
432 | static unsigned long display_header(int scr_width, int *lines_rem_p) | ||
261 | { | 433 | { |
262 | FILE *fp; | 434 | FILE *fp; |
263 | char buf[80]; | 435 | char buf[80]; |
264 | char scrbuf[80]; | 436 | char scrbuf[80]; |
265 | unsigned long total, used, mfree, shared, buffers, cached; | 437 | unsigned long total, used, mfree, shared, buffers, cached; |
266 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS | ||
267 | unsigned total_diff; | ||
268 | #endif | ||
269 | 438 | ||
270 | /* read memory info */ | 439 | /* read memory info */ |
271 | fp = xfopen_for_read("meminfo"); | 440 | fp = xfopen_for_read("meminfo"); |
@@ -298,7 +467,6 @@ static unsigned long display_header(int scr_width) | |||
298 | * sizes in kilobytes. This should be safe for both 2.4 and | 467 | * sizes in kilobytes. This should be safe for both 2.4 and |
299 | * 2.6. | 468 | * 2.6. |
300 | */ | 469 | */ |
301 | |||
302 | fscanf(fp, "MemFree: %lu %s\n", &mfree, buf); | 470 | fscanf(fp, "MemFree: %lu %s\n", &mfree, buf); |
303 | 471 | ||
304 | /* | 472 | /* |
@@ -323,47 +491,12 @@ static unsigned long display_header(int scr_width) | |||
323 | used, mfree, shared, buffers, cached); | 491 | used, mfree, shared, buffers, cached); |
324 | /* clear screen & go to top */ | 492 | /* clear screen & go to top */ |
325 | printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf); | 493 | printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf); |
494 | (*lines_rem_p)--; | ||
326 | 495 | ||
327 | #if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS | 496 | /* Display CPU time split as percentage of total time |
328 | /* | 497 | * This displays either a cumulative line or one line per CPU |
329 | * xxx% = (jif.xxx - prev_jif.xxx) / (jif.total - prev_jif.total) * 100% | ||
330 | */ | 498 | */ |
331 | /* using (unsigned) casts to make operations cheaper */ | 499 | display_cpus(scr_width, scrbuf, lines_rem_p); |
332 | total_diff = ((unsigned)(jif.total - prev_jif.total) ? : 1); | ||
333 | #if ENABLE_FEATURE_TOP_DECIMALS | ||
334 | /* Generated code is approx +0.3k */ | ||
335 | #define CALC_STAT(xxx) char xxx[8] | ||
336 | #define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(jif.xxx - prev_jif.xxx), total_diff) | ||
337 | #define FMT "%s" | ||
338 | #else | ||
339 | #define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(jif.xxx - prev_jif.xxx) / total_diff | ||
340 | #define SHOW_STAT(xxx) xxx | ||
341 | #define FMT "%4u%% " | ||
342 | #endif | ||
343 | { /* need block: CALC_STAT are declarations */ | ||
344 | CALC_STAT(usr); | ||
345 | CALC_STAT(sys); | ||
346 | CALC_STAT(nic); | ||
347 | CALC_STAT(idle); | ||
348 | CALC_STAT(iowait); | ||
349 | CALC_STAT(irq); | ||
350 | CALC_STAT(softirq); | ||
351 | //CALC_STAT(steal); | ||
352 | |||
353 | snprintf(scrbuf, scr_width, | ||
354 | /* Barely fits in 79 chars when in "decimals" mode. */ | ||
355 | "CPU:"FMT"usr"FMT"sys"FMT"nice"FMT"idle"FMT"io"FMT"irq"FMT"softirq", | ||
356 | SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle), | ||
357 | SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq) | ||
358 | //, SHOW_STAT(steal) - what is this 'steal' thing? | ||
359 | // I doubt anyone wants to know it | ||
360 | ); | ||
361 | } | ||
362 | puts(scrbuf); | ||
363 | #undef SHOW_STAT | ||
364 | #undef CALC_STAT | ||
365 | #undef FMT | ||
366 | #endif | ||
367 | 500 | ||
368 | /* read load average as a string */ | 501 | /* read load average as a string */ |
369 | buf[0] = '\0'; | 502 | buf[0] = '\0'; |
@@ -371,35 +504,39 @@ static unsigned long display_header(int scr_width) | |||
371 | buf[sizeof("N.NN N.NN N.NN")-1] = '\0'; | 504 | buf[sizeof("N.NN N.NN N.NN")-1] = '\0'; |
372 | snprintf(scrbuf, scr_width, "Load average: %s", buf); | 505 | snprintf(scrbuf, scr_width, "Load average: %s", buf); |
373 | puts(scrbuf); | 506 | puts(scrbuf); |
507 | (*lines_rem_p)--; | ||
374 | 508 | ||
375 | return total; | 509 | return total; |
376 | } | 510 | } |
377 | 511 | ||
378 | static NOINLINE void display_process_list(int count, int scr_width) | 512 | static NOINLINE void display_process_list(int lines_rem, int scr_width) |
379 | { | 513 | { |
380 | enum { | 514 | enum { |
381 | BITS_PER_INT = sizeof(int)*8 | 515 | BITS_PER_INT = sizeof(int) * 8 |
382 | }; | 516 | }; |
383 | 517 | ||
384 | top_status_t *s = top; | 518 | top_status_t *s; |
385 | char vsz_str_buf[8]; | 519 | char vsz_str_buf[8]; |
386 | unsigned long total_memory = display_header(scr_width); /* or use total_vsz? */ | 520 | unsigned long total_memory = display_header(scr_width, &lines_rem); /* or use total_vsz? */ |
387 | /* xxx_shift and xxx_scale variables allow us to replace | 521 | /* xxx_shift and xxx_scale variables allow us to replace |
388 | * expensive divides with multiply and shift */ | 522 | * expensive divides with multiply and shift */ |
389 | unsigned pmem_shift, pmem_scale, pmem_half; | 523 | unsigned pmem_shift, pmem_scale, pmem_half; |
390 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 524 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
391 | unsigned pcpu_shift, pcpu_scale, pcpu_half; | 525 | unsigned pcpu_shift, pcpu_scale, pcpu_half; |
392 | unsigned busy_jifs; | 526 | unsigned busy_jifs; |
527 | #endif | ||
393 | 528 | ||
394 | /* what info of the processes is shown */ | 529 | /* what info of the processes is shown */ |
395 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, | 530 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, |
396 | " PID PPID USER STAT VSZ %MEM %CPU COMMAND"); | 531 | " PID PPID USER STAT VSZ %MEM" |
397 | #else | 532 | #if ENABLE_FEATURE_TOP_SMP_PROCESS |
398 | 533 | " CPU" | |
399 | /* !CPU_USAGE_PERCENTAGE */ | 534 | #endif |
400 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, | 535 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
401 | " PID PPID USER STAT VSZ %MEM COMMAND"); | 536 | " %CPU" |
402 | #endif | 537 | #endif |
538 | " COMMAND"); | ||
539 | lines_rem--; | ||
403 | 540 | ||
404 | #if ENABLE_FEATURE_TOP_DECIMALS | 541 | #if ENABLE_FEATURE_TOP_DECIMALS |
405 | #define UPSCALE 1000 | 542 | #define UPSCALE 1000 |
@@ -453,9 +590,12 @@ static NOINLINE void display_process_list(int count, int scr_width) | |||
453 | /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ | 590 | /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ |
454 | #endif | 591 | #endif |
455 | 592 | ||
456 | scr_width += 2; /* account for leading '\n' and trailing NUL */ | ||
457 | /* Ok, all preliminary data is ready, go through the list */ | 593 | /* Ok, all preliminary data is ready, go through the list */ |
458 | while (count-- > 0) { | 594 | scr_width += 2; /* account for leading '\n' and trailing NUL */ |
595 | if (lines_rem > ntop) | ||
596 | lines_rem = ntop; | ||
597 | s = top; | ||
598 | while (--lines_rem >= 0) { | ||
459 | unsigned col; | 599 | unsigned col; |
460 | CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); | 600 | CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); |
461 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 601 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
@@ -466,9 +606,12 @@ static NOINLINE void display_process_list(int count, int scr_width) | |||
466 | sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); | 606 | sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); |
467 | else | 607 | else |
468 | sprintf(vsz_str_buf, "%7ld", s->vsz); | 608 | sprintf(vsz_str_buf, "%7ld", s->vsz); |
469 | // PID PPID USER STAT VSZ %MEM [%CPU] COMMAND | 609 | /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */ |
470 | col = snprintf(line_buf, scr_width, | 610 | col = snprintf(line_buf, scr_width, |
471 | "\n" "%5u%6u %-8.8s %s%s" FMT | 611 | "\n" "%5u%6u %-8.8s %s%s" FMT |
612 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
613 | " %3d" | ||
614 | #endif | ||
472 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 615 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
473 | FMT | 616 | FMT |
474 | #endif | 617 | #endif |
@@ -476,6 +619,9 @@ static NOINLINE void display_process_list(int count, int scr_width) | |||
476 | s->pid, s->ppid, get_cached_username(s->uid), | 619 | s->pid, s->ppid, get_cached_username(s->uid), |
477 | s->state, vsz_str_buf, | 620 | s->state, vsz_str_buf, |
478 | SHOW_STAT(pmem) | 621 | SHOW_STAT(pmem) |
622 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
623 | , s->last_seen_on_cpu | ||
624 | #endif | ||
479 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 625 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
480 | , SHOW_STAT(pcpu) | 626 | , SHOW_STAT(pcpu) |
481 | #endif | 627 | #endif |
@@ -580,7 +726,7 @@ static char *grab_number(char *str, const char *match, unsigned sz) | |||
580 | } | 726 | } |
581 | 727 | ||
582 | /* display header info (meminfo / loadavg) */ | 728 | /* display header info (meminfo / loadavg) */ |
583 | static void display_topmem_header(int scr_width) | 729 | static void display_topmem_header(int scr_width, int *lines_rem_p) |
584 | { | 730 | { |
585 | char linebuf[128]; | 731 | char linebuf[128]; |
586 | unsigned i; | 732 | unsigned i; |
@@ -655,6 +801,8 @@ static void display_topmem_header(int scr_width) | |||
655 | "Swap %stotal %sfree", // TODO: % used? | 801 | "Swap %stotal %sfree", // TODO: % used? |
656 | S(swaptotal), S(swapfree)); | 802 | S(swaptotal), S(swapfree)); |
657 | printf("%.*s\n", scr_width, linebuf); | 803 | printf("%.*s\n", scr_width, linebuf); |
804 | |||
805 | (*lines_rem_p) -= 3; | ||
658 | #undef S | 806 | #undef S |
659 | 807 | ||
660 | for (i = 0; i < ARRAY_SIZE(str); i++) | 808 | for (i = 0; i < ARRAY_SIZE(str); i++) |
@@ -680,19 +828,22 @@ static void ulltoa6_and_space(unsigned long long ul, char buf[6]) | |||
680 | buf[5] = ' '; | 828 | buf[5] = ' '; |
681 | } | 829 | } |
682 | 830 | ||
683 | static NOINLINE void display_topmem_process_list(int count, int scr_width) | 831 | static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) |
684 | { | 832 | { |
685 | #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" | 833 | #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" |
686 | #define MIN_WIDTH sizeof(HDR_STR) | 834 | #define MIN_WIDTH sizeof(HDR_STR) |
687 | const topmem_status_t *s = topmem; | 835 | const topmem_status_t *s = topmem; |
688 | 836 | ||
689 | display_topmem_header(scr_width); | 837 | display_topmem_header(scr_width, &lines_rem); |
690 | strcpy(line_buf, HDR_STR " COMMAND"); | 838 | strcpy(line_buf, HDR_STR " COMMAND"); |
691 | line_buf[5 + sort_field * 6] = '*'; | 839 | line_buf[5 + sort_field * 6] = '*'; |
692 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); | 840 | printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); |
841 | lines_rem--; | ||
693 | 842 | ||
694 | while (--count >= 0) { | 843 | if (lines_rem > ntop) |
695 | // PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND | 844 | lines_rem = ntop; |
845 | while (--lines_rem >= 0) { | ||
846 | /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ | ||
696 | ulltoa6_and_space(s->pid , &line_buf[0*6]); | 847 | ulltoa6_and_space(s->pid , &line_buf[0*6]); |
697 | ulltoa6_and_space(s->vsz , &line_buf[1*6]); | 848 | ulltoa6_and_space(s->vsz , &line_buf[1*6]); |
698 | ulltoa6_and_space(s->vszrw , &line_buf[2*6]); | 849 | ulltoa6_and_space(s->vszrw , &line_buf[2*6]); |
@@ -714,7 +865,7 @@ static NOINLINE void display_topmem_process_list(int count, int scr_width) | |||
714 | #undef MIN_WIDTH | 865 | #undef MIN_WIDTH |
715 | } | 866 | } |
716 | #else | 867 | #else |
717 | void display_topmem_process_list(int count, int scr_width); | 868 | void display_topmem_process_list(int lines_rem, int scr_width); |
718 | int topmem_sort(char *a, char *b); | 869 | int topmem_sort(char *a, char *b); |
719 | #endif /* TOPMEM */ | 870 | #endif /* TOPMEM */ |
720 | 871 | ||
@@ -731,6 +882,9 @@ enum { | |||
731 | | PSSCAN_UTIME | 882 | | PSSCAN_UTIME |
732 | | PSSCAN_STATE | 883 | | PSSCAN_STATE |
733 | | PSSCAN_COMM | 884 | | PSSCAN_COMM |
885 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
886 | | PSSCAN_CPU | ||
887 | #endif | ||
734 | | PSSCAN_UIDGID, | 888 | | PSSCAN_UIDGID, |
735 | TOPMEM_MASK = 0 | 889 | TOPMEM_MASK = 0 |
736 | | PSSCAN_PID | 890 | | PSSCAN_PID |
@@ -741,9 +895,9 @@ enum { | |||
741 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 895 | int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
742 | int top_main(int argc UNUSED_PARAM, char **argv) | 896 | int top_main(int argc UNUSED_PARAM, char **argv) |
743 | { | 897 | { |
744 | int count; | ||
745 | int iterations; | 898 | int iterations; |
746 | unsigned lines, col; | 899 | unsigned lines, col; |
900 | int lines_rem; | ||
747 | unsigned interval; | 901 | unsigned interval; |
748 | char *sinterval; | 902 | char *sinterval; |
749 | SKIP_FEATURE_TOPMEM(const) unsigned scan_mask = TOP_MASK; | 903 | SKIP_FEATURE_TOPMEM(const) unsigned scan_mask = TOP_MASK; |
@@ -760,12 +914,18 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
760 | 914 | ||
761 | interval = 5; /* default update interval is 5 seconds */ | 915 | interval = 5; /* default update interval is 5 seconds */ |
762 | iterations = 0; /* infinite */ | 916 | iterations = 0; /* infinite */ |
917 | #if ENABLE_FEATURE_TOP_SMP_CPU | ||
918 | /*num_cpus = 0;*/ | ||
919 | /*smp_cpu_info = 0;*/ /* to start with show aggregate */ | ||
920 | cpu_jif = &jif; | ||
921 | cpu_prev_jif = &prev_jif; | ||
922 | #endif | ||
763 | 923 | ||
764 | /* all args are options; -n NUM */ | 924 | /* all args are options; -n NUM */ |
765 | opt_complementary = "-:n+"; | 925 | opt_complementary = "-:n+"; |
766 | if (getopt32(argv, "d:n:b", &sinterval, &iterations) & OPT_d) { | 926 | if (getopt32(argv, "d:n:b", &sinterval, &iterations) & OPT_d) { |
767 | /* Need to limit it to not overflow poll timeout */ | 927 | /* Need to limit it to not overflow poll timeout */ |
768 | interval = xatou16(sinterval); // -d | 928 | interval = xatou16(sinterval); /* -d */ |
769 | } | 929 | } |
770 | 930 | ||
771 | /* change to /proc */ | 931 | /* change to /proc */ |
@@ -803,10 +963,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
803 | #endif /* FEATURE_USE_TERMIOS */ | 963 | #endif /* FEATURE_USE_TERMIOS */ |
804 | if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ | 964 | if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ |
805 | col = LINE_BUF_SIZE-2; | 965 | col = LINE_BUF_SIZE-2; |
806 | if (!ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && scan_mask == TOP_MASK) | ||
807 | lines -= 3; | ||
808 | else | ||
809 | lines -= 4; | ||
810 | 966 | ||
811 | /* read process IDs & status for all the processes */ | 967 | /* read process IDs & status for all the processes */ |
812 | while ((p = procps_scan(p, scan_mask)) != NULL) { | 968 | while ((p = procps_scan(p, scan_mask)) != NULL) { |
@@ -823,6 +979,9 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
823 | top[n].uid = p->uid; | 979 | top[n].uid = p->uid; |
824 | strcpy(top[n].state, p->state); | 980 | strcpy(top[n].state, p->state); |
825 | strcpy(top[n].comm, p->comm); | 981 | strcpy(top[n].comm, p->comm); |
982 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | ||
983 | top[n].last_seen_on_cpu = p->last_seen_on_cpu; | ||
984 | #endif | ||
826 | } else { /* TOPMEM */ | 985 | } else { /* TOPMEM */ |
827 | #if ENABLE_FEATURE_TOPMEM | 986 | #if ENABLE_FEATURE_TOPMEM |
828 | if (!(p->mapped_ro | p->mapped_rw)) | 987 | if (!(p->mapped_ro | p->mapped_rw)) |
@@ -856,7 +1015,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
856 | continue; | 1015 | continue; |
857 | } | 1016 | } |
858 | do_stats(); | 1017 | do_stats(); |
859 | /* TODO: we don't need to sort all 10000 processes, we need to find top 24! */ | 1018 | /* TODO: we don't need to sort all 10000 processes, we need to find top 24! */ |
860 | qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp); | 1019 | qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp); |
861 | #else | 1020 | #else |
862 | qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0])); | 1021 | qsort(top, ntop, sizeof(top_status_t), (void*)(sort_function[0])); |
@@ -867,15 +1026,15 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
867 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); | 1026 | qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); |
868 | } | 1027 | } |
869 | #endif | 1028 | #endif |
870 | count = lines; | 1029 | lines_rem = lines; |
871 | if (OPT_BATCH_MODE || count > ntop) { | 1030 | if (OPT_BATCH_MODE) { |
872 | count = ntop; | 1031 | lines_rem = INT_MAX; |
873 | } | 1032 | } |
874 | if (scan_mask == TOP_MASK) | 1033 | if (scan_mask == TOP_MASK) |
875 | display_process_list(count, col); | 1034 | display_process_list(lines_rem, col); |
876 | #if ENABLE_FEATURE_TOPMEM | 1035 | #if ENABLE_FEATURE_TOPMEM |
877 | else | 1036 | else |
878 | display_topmem_process_list(count, col); | 1037 | display_topmem_process_list(lines_rem, col); |
879 | #endif | 1038 | #endif |
880 | clearmems(); | 1039 | clearmems(); |
881 | if (iterations >= 0 && !--iterations) | 1040 | if (iterations >= 0 && !--iterations) |
@@ -932,6 +1091,23 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
932 | if (c == 'r') | 1091 | if (c == 'r') |
933 | inverted ^= 1; | 1092 | inverted ^= 1; |
934 | #endif | 1093 | #endif |
1094 | #if ENABLE_FEATURE_TOP_SMP_CPU | ||
1095 | if (c == 'c') { /* procps-2.0.18 uses 'C' */ | ||
1096 | /* User wants to toggle per cpu <> aggregate */ | ||
1097 | if (smp_cpu_info) { | ||
1098 | free(cpu_prev_jif); | ||
1099 | free(cpu_jif); | ||
1100 | cpu_jif = &jif; | ||
1101 | cpu_prev_jif = &prev_jif; | ||
1102 | } else { | ||
1103 | /* Prepare for xrealloc() */ | ||
1104 | cpu_jif = cpu_prev_jif = NULL; | ||
1105 | } | ||
1106 | num_cpus = 0; | ||
1107 | smp_cpu_info = !smp_cpu_info; | ||
1108 | get_jiffy_counts(); | ||
1109 | } | ||
1110 | #endif | ||
935 | #endif | 1111 | #endif |
936 | } | 1112 | } |
937 | #endif /* FEATURE_USE_TERMIOS */ | 1113 | #endif /* FEATURE_USE_TERMIOS */ |