1 /*
2 * app_mem_usage.c
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #if defined(__linux__)
12 #define _XOPEN_SOURCE 500
13 #endif
14
15 #include "config.h"
16
17 #include <stdio.h>
18
19 #include <glib.h>
20
21 #ifdef _WIN32
22 #include <windows.h>
23 #include <psapi.h>
24 #endif /* _WIN32 */
25
26 #if defined(__linux__)
27 # include <sys/types.h>
28 # include <sys/stat.h>
29 # include <unistd.h>
30 # include <fcntl.h>
31 #endif
32
33 #include "wsutil/file_util.h"
34 #include "app_mem_usage.h"
35
36 #define MAX_COMPONENTS 16
37
38 #if defined(_WIN32)
39
40 static gsize
win32_get_total_mem_used_by_app(void)41 win32_get_total_mem_used_by_app(void)
42 {
43 HANDLE pHandle;
44 PROCESS_MEMORY_COUNTERS pmc;
45 SIZE_T workingSize = 0;
46
47 pHandle = GetCurrentProcess();
48
49 if (GetProcessMemoryInfo(pHandle, &pmc, sizeof(pmc))){
50 workingSize = pmc.WorkingSetSize;
51 }
52
53 CloseHandle(pHandle);
54
55 if(workingSize == 0){
56 return -1;
57 }else{
58 return (int)workingSize;
59 }
60 }
61
62 static const ws_mem_usage_t total_usage = { "Total", win32_get_total_mem_used_by_app, NULL };
63
64 static const ws_mem_usage_t *memory_components[MAX_COMPONENTS] = {
65 &total_usage,
66 };
67
68 static guint memory_register_num = 1;
69
70 #elif defined(__linux__)
71
72 static gboolean
linux_get_memory(gsize * ptotal,gsize * prss)73 linux_get_memory(gsize *ptotal, gsize *prss)
74 {
75 static int fd = -1;
76 static intptr_t pagesize = 0;
77
78 char buf[128];
79 unsigned long total, rss;
80 ssize_t ret;
81
82 if (!pagesize)
83 pagesize = sysconf(_SC_PAGESIZE);
84
85 if (pagesize == -1)
86 return FALSE;
87
88 if (fd < 0) {
89 char path[64];
90
91 g_snprintf(path, sizeof(path), "/proc/%d/statm", getpid());
92
93 fd = ws_open(path, O_RDONLY);
94
95 /* XXX, fallback to some other /proc file ? */
96 }
97
98 if (fd < 0)
99 return FALSE;
100
101 ret = pread(fd, buf, sizeof(buf)-1, 0);
102 if (ret <= 0)
103 return FALSE;
104
105 buf[ret] = '\0';
106
107 if (sscanf(buf, "%lu %lu", &total, &rss) != 2)
108 return FALSE;
109
110 if (ptotal)
111 *ptotal = pagesize * (gsize) total;
112 if (prss)
113 *prss = pagesize * (gsize) rss;
114
115 return TRUE;
116 }
117
118 static gsize
linux_get_total_mem_used_by_app(void)119 linux_get_total_mem_used_by_app(void)
120 {
121 gsize total;
122
123 if (!linux_get_memory(&total, NULL))
124 total = 0;
125
126 return total;
127 }
128
129 static gsize
linux_get_rss_mem_used_by_app(void)130 linux_get_rss_mem_used_by_app(void)
131 {
132 gsize rss;
133
134 if (!linux_get_memory(NULL, &rss))
135 rss = 0;
136
137 return rss;
138 }
139
140 static const ws_mem_usage_t total_usage = { "Total", linux_get_total_mem_used_by_app, NULL };
141 static const ws_mem_usage_t rss_usage = { "RSS", linux_get_rss_mem_used_by_app, NULL };
142
143 static const ws_mem_usage_t *memory_components[MAX_COMPONENTS] = {
144 &total_usage,
145 &rss_usage,
146 };
147
148 static guint memory_register_num = 2;
149
150 #else
151
152 /*
153 * macOS: task_info()?
154 *
155 * *BSD: getrusage() -> ru_ixrss ? Note that there are three
156 * current-RSS components in struct rusage, but those date
157 * back to the days when you had just text, data, and stack,
158 * and kernels might not even bother supplying them.
159 */
160
161 static const ws_mem_usage_t *memory_components[MAX_COMPONENTS];
162
163 static guint memory_register_num = 0;
164
165 #endif
166
167 /* public API */
168
169 void
memory_usage_component_register(const ws_mem_usage_t * component)170 memory_usage_component_register(const ws_mem_usage_t *component)
171 {
172 if (memory_register_num >= MAX_COMPONENTS)
173 return;
174
175 memory_components[memory_register_num++] = component;
176 }
177
178 const char *
memory_usage_get(guint idx,gsize * value)179 memory_usage_get(guint idx, gsize *value)
180 {
181 if (idx >= memory_register_num)
182 return NULL;
183
184 if (value)
185 *value = memory_components[idx]->fetch();
186
187 return memory_components[idx]->name;
188 }
189
190 void
memory_usage_gc(void)191 memory_usage_gc(void)
192 {
193 guint i;
194
195 for (i = 0; i < memory_register_num; i++) {
196 if (memory_components[i]->gc)
197 memory_components[i]->gc();
198 }
199 }
200
201
202 /*
203 * Editor modelines - https://www.wireshark.org/tools/modelines.html
204 *
205 * Local variables:
206 * c-basic-offset: 8
207 * tab-width: 8
208 * indent-tabs-mode: t
209 * End:
210 *
211 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
212 * :indentSize=8:tabSize=8:noTabs=false:
213 */
214