1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2014 Sony Mobile Communications Inc. |
4 | * |
5 | * Selftest for runtime system size |
6 | * |
7 | * Prints the amount of RAM that the currently running system is using. |
8 | * |
9 | * This program tries to be as small as possible itself, to |
10 | * avoid perturbing the system memory utilization with its |
11 | * own execution. It also attempts to have as few dependencies |
12 | * on kernel features as possible. |
13 | * |
14 | * It should be statically linked, with startup libs avoided. It uses |
15 | * no library calls except the syscall() function for the following 3 |
16 | * syscalls: |
17 | * sysinfo(), write(), and _exit() |
18 | * |
19 | * For output, it avoids printf (which in some C libraries |
20 | * has large external dependencies) by implementing it's own |
21 | * number output and print routines, and using __builtin_strlen() |
22 | * |
23 | * The test may crash if any of the above syscalls fails because in some |
24 | * libc implementations (e.g. the GNU C Library) errno is saved in |
25 | * thread-local storage, which does not get initialized due to avoiding |
26 | * startup libs. |
27 | */ |
28 | |
29 | #include <sys/sysinfo.h> |
30 | #include <unistd.h> |
31 | #include <sys/syscall.h> |
32 | |
33 | #define STDOUT_FILENO 1 |
34 | |
35 | static int print(const char *s) |
36 | { |
37 | size_t len = 0; |
38 | |
39 | while (s[len] != '\0') |
40 | len++; |
41 | |
42 | return syscall(SYS_write, STDOUT_FILENO, s, len); |
43 | } |
44 | |
45 | static inline char *num_to_str(unsigned long num, char *buf, int len) |
46 | { |
47 | unsigned int digit; |
48 | |
49 | /* put digits in buffer from back to front */ |
50 | buf += len - 1; |
51 | *buf = 0; |
52 | do { |
53 | digit = num % 10; |
54 | *(--buf) = digit + '0'; |
55 | num /= 10; |
56 | } while (num > 0); |
57 | |
58 | return buf; |
59 | } |
60 | |
61 | static int print_num(unsigned long num) |
62 | { |
63 | char num_buf[30]; |
64 | |
65 | return print(s: num_to_str(num, buf: num_buf, len: sizeof(num_buf))); |
66 | } |
67 | |
68 | static int print_k_value(const char *s, unsigned long num, unsigned long units) |
69 | { |
70 | unsigned long long temp; |
71 | int ccode; |
72 | |
73 | print(s); |
74 | |
75 | temp = num; |
76 | temp = (temp * units)/1024; |
77 | num = temp; |
78 | ccode = print_num(num); |
79 | print(s: "\n" ); |
80 | return ccode; |
81 | } |
82 | |
83 | /* this program has no main(), as startup libraries are not used */ |
84 | void _start(void) |
85 | { |
86 | int ccode; |
87 | struct sysinfo info; |
88 | unsigned long used; |
89 | static const char *test_name = " get runtime memory use\n" ; |
90 | |
91 | print(s: "TAP version 13\n" ); |
92 | print(s: "# Testing system size.\n" ); |
93 | |
94 | ccode = syscall(SYS_sysinfo, &info); |
95 | if (ccode < 0) { |
96 | print(s: "not ok 1" ); |
97 | print(s: test_name); |
98 | print(s: " ---\n reason: \"could not get sysinfo\"\n ...\n" ); |
99 | syscall(SYS_exit, ccode); |
100 | } |
101 | print(s: "ok 1" ); |
102 | print(s: test_name); |
103 | |
104 | /* ignore cache complexities for now */ |
105 | used = info.totalram - info.freeram - info.bufferram; |
106 | print(s: "# System runtime memory report (units in Kilobytes):\n" ); |
107 | print(s: " ---\n" ); |
108 | print_k_value(s: " Total: " , num: info.totalram, units: info.mem_unit); |
109 | print_k_value(s: " Free: " , num: info.freeram, units: info.mem_unit); |
110 | print_k_value(s: " Buffer: " , num: info.bufferram, units: info.mem_unit); |
111 | print_k_value(s: " In use: " , num: used, units: info.mem_unit); |
112 | print(s: " ...\n" ); |
113 | print(s: "1..1\n" ); |
114 | |
115 | syscall(SYS_exit, 0); |
116 | } |
117 | |