aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/procps.c130
1 files changed, 48 insertions, 82 deletions
diff --git a/libbb/procps.c b/libbb/procps.c
index 2cdfce42a..3256fafc5 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -109,7 +109,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp)
109} 109}
110 110
111#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 111#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
112static unsigned long long fast_strtoull_16(char **endptr) 112unsigned long long FAST_FUNC fast_strtoull_16(char **endptr)
113{ 113{
114 unsigned char c; 114 unsigned char c;
115 char *str = *endptr; 115 char *str = *endptr;
@@ -130,7 +130,7 @@ static unsigned long long fast_strtoull_16(char **endptr)
130 130
131#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 131#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
132/* We cut a lot of corners here for speed */ 132/* We cut a lot of corners here for speed */
133static unsigned long fast_strtoul_10(char **endptr) 133unsigned long FAST_FUNC fast_strtoul_10(char **endptr)
134{ 134{
135 unsigned char c; 135 unsigned char c;
136 char *str = *endptr; 136 char *str = *endptr;
@@ -159,7 +159,7 @@ static unsigned long long fast_strtoull_10(char **endptr)
159 return n; 159 return n;
160} 160}
161# else 161# else
162# define fast_strtoull_10(endptr) fast_strtoul_10(endptr) 162# define fast_strtoull_10(endptr) fast_strtoul_10(endptr)
163# endif 163# endif
164 164
165# if ENABLE_FEATURE_FAST_TOP 165# if ENABLE_FEATURE_FAST_TOP
@@ -173,7 +173,7 @@ static long fast_strtol_10(char **endptr)
173} 173}
174# endif 174# endif
175 175
176static char *skip_fields(char *str, int count) 176char* FAST_FUNC skip_fields(char *str, int count)
177{ 177{
178 do { 178 do {
179 while (*str++ != ' ') 179 while (*str++ != ' ')
@@ -184,35 +184,25 @@ static char *skip_fields(char *str, int count)
184} 184}
185#endif 185#endif
186 186
187#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 187#if ENABLE_FEATURE_TOPMEM
188static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) 188static NOINLINE void procps_read_smaps(pid_t pid, procps_status_t *sp)
189{ 189{
190 char *tp = is_prefixed_with(buf, prefix); 190 // There is A LOT of /proc/PID/smaps data on a big system.
191 if (tp) { 191 // Optimize this for speed, makes "top -m" faster.
192 tp = skip_whitespace(tp); 192//TODO large speedup:
193 } 193//read /proc/PID/smaps_rollup (cumulative stats of all mappings, much faster)
194 return tp; 194//and /proc/PID/maps to get mapped_ro and mapped_rw (IOW: VSZ,VSZRW)
195}
196 195
197int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
198 void (*cb)(struct smaprec *, void *), void *data)
199{
200 FILE *file; 196 FILE *file;
201 struct smaprec currec;
202 char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; 197 char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3];
203 char buf[PROCPS_BUFSIZE]; 198 char buf[PROCPS_BUFSIZE];
204#if !ENABLE_PMAP
205 void (*cb)(struct smaprec *, void *) = NULL;
206 void *data = NULL;
207#endif
208 199
209 sprintf(filename, "/proc/%u/smaps", (int)pid); 200 sprintf(filename, "/proc/%u/smaps", (int)pid);
210 201
211 file = fopen_for_read(filename); 202 file = fopen_for_read(filename);
212 if (!file) 203 if (!file)
213 return 1; 204 return;
214 205
215 memset(&currec, 0, sizeof(currec));
216 while (fgets(buf, PROCPS_BUFSIZE, file)) { 206 while (fgets(buf, PROCPS_BUFSIZE, file)) {
217 // Each mapping datum has this form: 207 // Each mapping datum has this form:
218 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME 208 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
@@ -220,80 +210,53 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
220 // Rss: nnn kB 210 // Rss: nnn kB
221 // ..... 211 // .....
222 212
223 char *tp, *p; 213 char *tp;
224 214
215 if (buf[0] == 'S' || buf[0] == 'P') {
225#define SCAN(S, X) \ 216#define SCAN(S, X) \
226 if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \ 217 if (memcmp(buf, S, sizeof(S)-1) == 0) { \
227 total->X += currec.X = fast_strtoul_10(&tp); \ 218 tp = skip_whitespace(buf + sizeof(S)-1); \
228 continue; \ 219 sp->X += fast_strtoul_10(&tp); \
229 } 220 continue; \
230 if (cb) { 221 }
231 SCAN("Pss:" , smap_pss ); 222 SCAN("Private_Dirty:", private_dirty)
232 SCAN("Swap:" , smap_swap ); 223 SCAN("Private_Clean:", private_clean)
233 } 224 SCAN("Shared_Dirty:" , shared_dirty )
234 SCAN("Private_Dirty:", private_dirty); 225 SCAN("Shared_Clean:" , shared_clean )
235 SCAN("Private_Clean:", private_clean);
236 SCAN("Shared_Dirty:" , shared_dirty );
237 SCAN("Shared_Clean:" , shared_clean );
238#undef SCAN 226#undef SCAN
227 }
239 tp = strchr(buf, '-'); 228 tp = strchr(buf, '-');
240 if (tp) { 229 if (tp) {
241 // We reached next mapping - the line of this form: 230 // We reached next mapping - the line of this form:
242 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME 231 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
243 232
244 if (cb) { 233 char *rwx;
245 /* If we have a previous record, there's nothing more 234 unsigned long sz;
246 * for it, call the callback and clear currec
247 */
248 if (currec.smap_size)
249 cb(&currec, data);
250 free(currec.smap_name);
251 }
252 memset(&currec, 0, sizeof(currec));
253 235
254 *tp = ' '; 236 *tp = ' ';
255 tp = buf; 237 tp = buf;
256 currec.smap_start = fast_strtoull_16(&tp); 238 sz = fast_strtoull_16(&tp); // start
257 currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; 239 sz = (fast_strtoull_16(&tp) - sz) >> 10; // end - start
258 240 // tp -> "rw-s" string
259 strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); 241 rwx = tp;
260
261 // skipping "rw-s FILEOFS M:m INODE " 242 // skipping "rw-s FILEOFS M:m INODE "
262 tp = skip_whitespace(skip_fields(tp, 4)); 243 tp = skip_whitespace(skip_fields(tp, 4));
263 // filter out /dev/something (something != zero) 244 // if not a device memory mapped...
264 if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) { 245 if (memcmp(tp, "/dev/", 5) != 0 // not "/dev/something"
265 if (currec.smap_mode[1] == 'w') { 246 || strcmp(tp + 5, "zero\n") == 0 // or is "/dev/zero" (which isn't a device)
266 currec.mapped_rw = currec.smap_size; 247 ) {
267 total->mapped_rw += currec.smap_size; 248 if (rwx[1] == 'w')
268 } else if (currec.smap_mode[1] == '-') { 249 sp->mapped_rw += sz;
269 currec.mapped_ro = currec.smap_size; 250 else if (rwx[0] == 'r' || rwx[2] == 'x')
270 total->mapped_ro += currec.smap_size; 251 sp->mapped_ro += sz;
271 } 252 // else: seen "---p" mappings (mmap guard gaps?),
253 // do NOT account these as VSZ, they aren't really
272 } 254 }
273
274 if (strcmp(tp, "[stack]\n") == 0) 255 if (strcmp(tp, "[stack]\n") == 0)
275 total->stack += currec.smap_size; 256 sp->stack += sz;
276 if (cb) {
277 p = skip_non_whitespace(tp);
278 if (p == tp) {
279 currec.smap_name = xstrdup(" [ anon ]");
280 } else {
281 *p = '\0';
282 currec.smap_name = xstrdup(tp);
283 }
284 }
285 total->smap_size += currec.smap_size;
286 } 257 }
287 } 258 }
288 fclose(file); 259 fclose(file);
289
290 if (cb) {
291 if (currec.smap_size)
292 cb(&currec, data);
293 free(currec.smap_name);
294 }
295
296 return 0;
297} 260}
298#endif 261#endif
299 262
@@ -502,7 +465,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
502 465
503#if ENABLE_FEATURE_TOPMEM 466#if ENABLE_FEATURE_TOPMEM
504 if (flags & PSSCAN_SMAPS) 467 if (flags & PSSCAN_SMAPS)
505 procps_read_smaps(pid, &sp->smaps, NULL, NULL); 468 procps_read_smaps(pid, sp);
506#endif /* TOPMEM */ 469#endif /* TOPMEM */
507#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 470#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
508 if (flags & PSSCAN_RUIDGID) { 471 if (flags & PSSCAN_RUIDGID) {
@@ -585,13 +548,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
585 return sp; 548 return sp;
586} 549}
587 550
588void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) 551int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
589{ 552{
590 int sz; 553 int sz;
591 char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; 554 char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
592 555
593 sprintf(filename, "/proc/%u/cmdline", pid); 556 sprintf(filename, "/proc/%u/cmdline", pid);
594 sz = open_read_close(filename, buf, col - 1); 557 sz = open_read_close(filename, buf, col - 1);
558 if (sz < 0)
559 return sz;
595 if (sz > 0) { 560 if (sz > 0) {
596 const char *base; 561 const char *base;
597 int comm_len; 562 int comm_len;
@@ -614,7 +579,7 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
614 * It allows to see thread names set by prctl(PR_SET_NAME). 579 * It allows to see thread names set by prctl(PR_SET_NAME).
615 */ 580 */
616 if (!comm) 581 if (!comm)
617 return; 582 return 0;
618 comm_len = strlen(comm); 583 comm_len = strlen(comm);
619 /* Why compare up to comm_len, not COMM_LEN-1? 584 /* Why compare up to comm_len, not COMM_LEN-1?
620 * Well, some processes rewrite argv, and use _spaces_ there 585 * Well, some processes rewrite argv, and use _spaces_ there
@@ -628,13 +593,14 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
628 memmove(buf + comm_len, buf, col - comm_len); 593 memmove(buf + comm_len, buf, col - comm_len);
629 snprintf(buf, col, "{%s}", comm); 594 snprintf(buf, col, "{%s}", comm);
630 if (col <= comm_len) 595 if (col <= comm_len)
631 return; 596 return 0;
632 buf[comm_len - 1] = ' '; 597 buf[comm_len - 1] = ' ';
633 buf[col - 1] = '\0'; 598 buf[col - 1] = '\0';
634 } 599 }
635 } else { 600 } else {
636 snprintf(buf, col, "[%s]", comm ? comm : "?"); 601 snprintf(buf, col, "[%s]", comm ? comm : "?");
637 } 602 }
603 return 0;
638} 604}
639 605
640/* from kernel: 606/* from kernel: