Skip to content

Commit 6e79b37

Browse files
swarupkotikalapudiakpm00
authored andcommitted
proc: test /proc/${pid}/statm
My original comment lied, output can be "0 A A B 0 0 0\n" (see comment in the code). I don't quite understand why get_mm_counter(mm, MM_FILEPAGES) + get_mm_counter(mm, MM_SHMEMPAGES) can stay positive but get_mm_counter(mm, MM_ANONPAGES) is always 0 after everything is unmapped but that's just me. [[email protected]: more or less rewritten] Link: https://lkml.kernel.org/r/0721ca69-7bb4-40aa-8d01-0c5f91e5f363@p183 Signed-off-by: Swarup Laxman Kotiaklapudi <[email protected]> Signed-off-by: Alexey Dobriyan <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 598f0ac commit 6e79b37

File tree

1 file changed

+92
-5
lines changed

1 file changed

+92
-5
lines changed

tools/testing/selftests/proc/proc-empty-vm.c

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,95 @@ static int test_proc_pid_smaps_rollup(pid_t pid)
303303
}
304304
}
305305

306+
static const char *parse_u64(const char *p, const char *const end, uint64_t *rv)
307+
{
308+
*rv = 0;
309+
for (; p != end; p += 1) {
310+
if ('0' <= *p && *p <= '9') {
311+
assert(!__builtin_mul_overflow(*rv, 10, rv));
312+
assert(!__builtin_add_overflow(*rv, *p - '0', rv));
313+
} else {
314+
break;
315+
}
316+
}
317+
assert(p != end);
318+
return p;
319+
}
320+
321+
/*
322+
* There seems to be 2 types of valid output:
323+
* "0 A A B 0 0 0\n" for dynamic exeuctables,
324+
* "0 0 0 B 0 0 0\n" for static executables.
325+
*/
326+
static int test_proc_pid_statm(pid_t pid)
327+
{
328+
char buf[4096];
329+
snprintf(buf, sizeof(buf), "/proc/%u/statm", pid);
330+
int fd = open(buf, O_RDONLY);
331+
if (fd == -1) {
332+
perror("open /proc/${pid}/statm");
333+
return EXIT_FAILURE;
334+
}
335+
336+
ssize_t rv = read(fd, buf, sizeof(buf));
337+
close(fd);
338+
339+
assert(rv >= 0);
340+
assert(rv <= sizeof(buf));
341+
if (0) {
342+
write(1, buf, rv);
343+
}
344+
345+
const char *p = buf;
346+
const char *const end = p + rv;
347+
348+
/* size */
349+
assert(p != end && *p++ == '0');
350+
assert(p != end && *p++ == ' ');
351+
352+
uint64_t resident;
353+
p = parse_u64(p, end, &resident);
354+
assert(p != end && *p++ == ' ');
355+
356+
uint64_t shared;
357+
p = parse_u64(p, end, &shared);
358+
assert(p != end && *p++ == ' ');
359+
360+
uint64_t text;
361+
p = parse_u64(p, end, &text);
362+
assert(p != end && *p++ == ' ');
363+
364+
assert(p != end && *p++ == '0');
365+
assert(p != end && *p++ == ' ');
366+
367+
/* data */
368+
assert(p != end && *p++ == '0');
369+
assert(p != end && *p++ == ' ');
370+
371+
assert(p != end && *p++ == '0');
372+
assert(p != end && *p++ == '\n');
373+
374+
assert(p == end);
375+
376+
/*
377+
* "text" is "mm->end_code - mm->start_code" at execve(2) time.
378+
* munmap() doesn't change it. It can be anything (just link
379+
* statically). It can't be 0 because executing to this point
380+
* implies at least 1 page of code.
381+
*/
382+
assert(text > 0);
383+
384+
/*
385+
* These two are always equal. Always 0 for statically linked
386+
* executables and sometimes 0 for dynamically linked executables.
387+
* There is no way to tell one from another without parsing ELF
388+
* which is too much for this test.
389+
*/
390+
assert(resident == shared);
391+
392+
return EXIT_SUCCESS;
393+
}
394+
306395
int main(void)
307396
{
308397
int rv = EXIT_SUCCESS;
@@ -389,11 +478,9 @@ int main(void)
389478
if (rv == EXIT_SUCCESS) {
390479
rv = test_proc_pid_smaps_rollup(pid);
391480
}
392-
/*
393-
* TODO test /proc/${pid}/statm, task_statm()
394-
* ->start_code, ->end_code aren't updated by munmap().
395-
* Output can be "0 0 0 2 0 0 0\n" where "2" can be anything.
396-
*/
481+
if (rv == EXIT_SUCCESS) {
482+
rv = test_proc_pid_statm(pid);
483+
}
397484

398485
/* Cut the rope. */
399486
int wstatus;

0 commit comments

Comments
 (0)