aboutsummaryrefslogtreecommitdiff
path: root/procps
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2025-08-05 14:04:01 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2025-08-05 14:21:51 +0200
commitd16bde623ced3cf113648e0bb977c1befed6d601 (patch)
tree08f688dc57a6efbc9e82f6eaa7587849fee68f2c /procps
parent58b2353baaebdfdfd166e0745aea0fe75d1a3d10 (diff)
downloadbusybox-w32-d16bde623ced3cf113648e0bb977c1befed6d601.tar.gz
busybox-w32-d16bde623ced3cf113648e0bb977c1befed6d601.tar.bz2
busybox-w32-d16bde623ced3cf113648e0bb977c1befed6d601.zip
top,pmap: do not use common code for reading /proc/PID/smaps
The logic is in fact quite far from common. While at it, stop accounting "---p" mappings as mapped (e.g. VSZ in top). Nothing is mapped there (why would kernel waste RAM to map pages which can't be accessed?). function old new delta read_smaps - 562 +562 read_cmdline 315 326 +11 print_smaprec 97 101 +4 procps_scan 1219 1211 -8 .rodata 115541 115533 -8 skip_whitespace_if_prefixed_with 25 - -25 procps_read_smaps 864 577 -287 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 2/3 up/down: 577/-328) Total: 249 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'procps')
-rw-r--r--procps/pmap.c122
-rw-r--r--procps/top.c16
2 files changed, 118 insertions, 20 deletions
diff --git a/procps/pmap.c b/procps/pmap.c
index 49f7688d9..de58f3304 100644
--- a/procps/pmap.c
+++ b/procps/pmap.c
@@ -29,10 +29,14 @@
29 29
30#if ULLONG_MAX == 0xffffffff 30#if ULLONG_MAX == 0xffffffff
31# define TABS "\t" 31# define TABS "\t"
32# define SIZEWIDTHx "7"
33# define SIZEWIDTH "9"
32# define AFMTLL "8" 34# define AFMTLL "8"
33# define DASHES "" 35# define DASHES ""
34#else 36#else
35# define TABS "\t\t" 37# define TABS "\t\t"
38# define SIZEWIDTHx "15"
39# define SIZEWIDTH "17"
36# define AFMTLL "16" 40# define AFMTLL "16"
37# define DASHES "--------" 41# define DASHES "--------"
38#endif 42#endif
@@ -42,22 +46,114 @@ enum {
42 OPT_q = 1 << 1, 46 OPT_q = 1 << 1,
43}; 47};
44 48
45static void print_smaprec(struct smaprec *currec, void *data) 49struct smaprec {
46{ 50 // For mixed 32/64 userspace, 32-bit pmap still needs
47 unsigned opt = (uintptr_t)data; 51 // 64-bit field here to correctly show 64-bit processes:
52 unsigned long long smap_start;
53 // Make size wider too:
54 // I've seen 1203765248 kb large "---p" mapping in a browser,
55 // this cuts close to 4 terabytes.
56 unsigned long long smap_size;
57 // (strictly speaking, other fields need to be wider too,
58 // but they are in kbytes, not bytes, and they hold sizes,
59 // not start addresses, sizes tend to be less than 4 terabytes)
60 unsigned long private_dirty;
61 unsigned long smap_pss, smap_swap;
62 char smap_mode[5];
63 char *smap_name;
64};
48 65
66static void print_smaprec(struct smaprec *currec)
67{
49 printf("%0" AFMTLL "llx ", currec->smap_start); 68 printf("%0" AFMTLL "llx ", currec->smap_start);
50 69
51 if (opt & OPT_x) 70 if (option_mask32 & OPT_x)
52 printf("%7lu %7lu %7lu %7lu ", 71 printf("%7llu %7lu %7lu %7lu ",
53 currec->smap_size, 72 currec->smap_size,
54 currec->smap_pss, 73 currec->smap_pss,
55 currec->private_dirty, 74 currec->private_dirty,
56 currec->smap_swap); 75 currec->smap_swap);
57 else 76 else
58 printf("%7luK", currec->smap_size); 77 printf("%7lluK", currec->smap_size);
78
79 printf(" %.4s %s\n", currec->smap_mode, currec->smap_name ? : " [ anon ]");
80}
81
82/* libbb's procps_read_smaps() looks somewhat similar,
83 * but the collected information is sufficiently different
84 * that merging them into one function is not a good idea
85 * (unless you feel masochistic today).
86 */
87static int read_smaps(pid_t pid, struct smaprec *total)
88{
89 FILE *file;
90 struct smaprec currec;
91 char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3];
92 char buf[4096]; // how long the max filenames we expect?
93
94 sprintf(filename, "/proc/%u/smaps", (int)pid);
95
96 file = fopen_for_read(filename);
97 if (!file)
98 return 1;
99
100 memset(&currec, 0, sizeof(currec));
101 while (fgets(buf, sizeof(buf), file)) {
102 // Each mapping datum has this form:
103 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
104 // Size: nnn kB
105 // Rss: nnn kB
106 // .....
107
108 char *tp, *p;
109
110 if (buf[0] == 'S' || buf[0] == 'P') {
111#define SCAN(S, X) \
112 if (memcmp(buf, S, sizeof(S)-1) == 0) { \
113 tp = skip_whitespace(buf + sizeof(S)-1); \
114 total->X += currec.X = fast_strtoul_10(&tp); \
115 continue; \
116 }
117 SCAN("Pss:" , smap_pss );
118 SCAN("Swap:" , smap_swap );
119 SCAN("Private_Dirty:", private_dirty);
120#undef SCAN
121 }
122 tp = strchr(buf, '-');
123 if (tp) {
124 // We reached next mapping - the line of this form:
125 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
126
127 // If we have a previous record, there's nothing more
128 // for it, print and clear currec
129 if (currec.smap_size)
130 print_smaprec(&currec);
131 free(currec.smap_name);
132 memset(&currec, 0, sizeof(currec));
133
134 *tp = ' ';
135 tp = buf;
136 currec.smap_start = fast_strtoull_16(&tp);
137 currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10;
138 strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1);
139
140 // skipping "rw-s FILEOFS M:m INODE "
141 tp = skip_fields(tp, 4);
142 tp = skip_whitespace(tp); // there may be many spaces, can't just "tp++"
143 p = strchrnul(tp, '\n');
144 if (p != tp) {
145 currec.smap_name = xstrndup(tp, p - tp);
146 }
147 total->smap_size += currec.smap_size;
148 }
149 } // while (got line)
150 fclose(file);
151
152 if (currec.smap_size)
153 print_smaprec(&currec);
154 free(currec.smap_name);
59 155
60 printf(" %.4s %s\n", currec->smap_mode, currec->smap_name); 156 return 0;
61} 157}
62 158
63static int procps_get_maps(pid_t pid, unsigned opt) 159static int procps_get_maps(pid_t pid, unsigned opt)
@@ -66,25 +162,27 @@ static int procps_get_maps(pid_t pid, unsigned opt)
66 int ret; 162 int ret;
67 char buf[256]; 163 char buf[256];
68 164
69 read_cmdline(buf, sizeof(buf), pid, NULL); 165 ret = read_cmdline(buf, sizeof(buf), pid, NULL);
166 if (ret < 0)
167 return ret;
168
70 printf("%u: %s\n", (int)pid, buf); 169 printf("%u: %s\n", (int)pid, buf);
71 170
72 if (!(opt & OPT_q) && (opt & OPT_x)) 171 if (!(opt & OPT_q) && (opt & OPT_x))
73 puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping"); 172 puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping");
74 173
75 memset(&total, 0, sizeof(total)); 174 memset(&total, 0, sizeof(total));
76 175 ret = read_smaps(pid, &total);
77 ret = procps_read_smaps(pid, &total, print_smaprec, (void*)(uintptr_t)opt);
78 if (ret) 176 if (ret)
79 return ret; 177 return ret;
80 178
81 if (!(opt & OPT_q)) { 179 if (!(opt & OPT_q)) {
82 if (opt & OPT_x) 180 if (opt & OPT_x)
83 printf("--------" DASHES " ------ ------ ------ ------\n" 181 printf("--------" DASHES " ------ ------ ------ ------\n"
84 "total" TABS " %7lu %7lu %7lu %7lu\n", 182 "total kB %"SIZEWIDTHx"llu %7lu %7lu %7lu\n",
85 total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); 183 total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap);
86 else 184 else
87 printf("mapped: %luK\n", total.smap_size); 185 printf(" total %"SIZEWIDTH"lluK\n", total.smap_size);
88 } 186 }
89 187
90 return 0; 188 return 0;
diff --git a/procps/top.c b/procps/top.c
index a87fa0ae4..e0ebf7026 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -1302,20 +1302,20 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1302 } 1302 }
1303#if ENABLE_FEATURE_TOPMEM 1303#if ENABLE_FEATURE_TOPMEM
1304 else { /* TOPMEM */ 1304 else { /* TOPMEM */
1305 if (!(p->smaps.mapped_ro | p->smaps.mapped_rw)) 1305 if (!(p->mapped_ro | p->mapped_rw))
1306 continue; /* kernel threads are ignored */ 1306 continue; /* kernel threads are ignored */
1307 n = ntop; 1307 n = ntop;
1308 /* No bug here - top and topmem are the same */ 1308 /* No bug here - top and topmem are the same */
1309 top = xrealloc_vector(topmem, 6, ntop++); 1309 top = xrealloc_vector(topmem, 6, ntop++);
1310 strcpy(topmem[n].comm, p->comm); 1310 strcpy(topmem[n].comm, p->comm);
1311 topmem[n].pid = p->pid; 1311 topmem[n].pid = p->pid;
1312 topmem[n].vsz = p->smaps.mapped_rw + p->smaps.mapped_ro; 1312 topmem[n].vsz = p->mapped_rw + p->mapped_ro;
1313 topmem[n].vszrw = p->smaps.mapped_rw; 1313 topmem[n].vszrw = p->mapped_rw;
1314 topmem[n].rss_sh = p->smaps.shared_clean + p->smaps.shared_dirty; 1314 topmem[n].rss_sh = p->shared_clean + p->shared_dirty;
1315 topmem[n].rss = p->smaps.private_clean + p->smaps.private_dirty + topmem[n].rss_sh; 1315 topmem[n].rss = p->private_clean + p->private_dirty + topmem[n].rss_sh;
1316 topmem[n].dirty = p->smaps.private_dirty + p->smaps.shared_dirty; 1316 topmem[n].dirty = p->private_dirty + p->shared_dirty;
1317 topmem[n].dirty_sh = p->smaps.shared_dirty; 1317 topmem[n].dirty_sh = p->shared_dirty;
1318 topmem[n].stack = p->smaps.stack; 1318 topmem[n].stack = p->stack;
1319 } 1319 }
1320#endif 1320#endif
1321 } /* end of "while we read /proc" */ 1321 } /* end of "while we read /proc" */