1 /*
2  * Copyright (C) 2021 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 /*
26    get memory usage
27    special versions for FreeBSD,MacOS X and Linux (without checking in autotools)
28    general 'getrusage' version for others
29  */
30 
31 #if __FreeBSD__
32 # include <sys/file.h>
33 # include <sys/sysctl.h>
34 # include <sys/user.h>
35 # include <kvm.h>
36 # include <sys/types.h>
37 # include <unistd.h>
38 #elif __APPLE__
39 # include <mach/mach_init.h>
40 # include <mach/task.h>
41 #elif __linux__
42 # include <fcntl.h>
43 # include <sys/types.h>
44 # include <unistd.h>
45 # include <stdlib.h>
46 #elif defined(HAVE_GETRUSAGE) && defined(HAVE_STRUCT_RUSAGE_RU_MAXRSS)
47 #  include <sys/types.h>
48 #  ifdef HAVE_SYS_RESOURCE_H
49 #    include <sys/resource.h>
50 #  endif
51 #  ifdef HAVE_SYS_RUSAGE_H
52 #    include <sys/rusage.h>
53 #  endif
54 #  ifndef RUSAGE_SELF
55 #    define RUSAGE_SELF 0
56 #  endif
57 #  define MEMORY_USAGE 1
58 #endif
59 #include <inttypes.h>
60 
mem_used(uint64_t * rss,uint64_t * virt)61 uint8_t mem_used(uint64_t *rss,uint64_t *virt) {
62 #if defined(__FreeBSD__)
63 	static kvm_t* kd = NULL;
64 
65 	if ( kd == NULL) {
66 		kd = kvm_open( NULL, "/dev/null", NULL, O_RDONLY, "kvm_open" ); // open once
67 	}
68 	if ( kd != NULL ) {
69 		// Use FreeBSD kvm function to get the size of resident pages (RSS).
70 		int pc = 0;
71 		struct kinfo_proc* kp;
72 		kp = kvm_getprocs(kd,KERN_PROC_PID,getpid(),&pc); // do not free returned struct
73 		if ( (kp != NULL) && (pc >= 1) ) { // in case multiple threads have the same PID
74 			*rss = kp->ki_rssize * getpagesize();
75 			*virt = kp->ki_size;
76 			return 1; // success
77 		}
78 	}
79 	*rss = 0;
80 	*virt = 0;
81 	return 0; // failed
82 #elif __APPLE__
83 	struct task_basic_info machInfo;
84 	mach_port_t machTask = mach_task_self();
85 	mach_msg_type_number_t machCount = TASK_BASIC_INFO_COUNT;
86 	if ( task_info( machTask, TASK_BASIC_INFO, (task_info_t)&machInfo, &machCount ) == KERN_SUCCESS ) {
87 		*rss = machInfo.resident_size;
88 		*virt = machInfo.virtual_size;
89 		return 1;
90 	}
91 	*rss = 0;
92 	*virt = 0;
93 	return 0; // error
94 #elif __linux__
95 	int fd = open("/proc/self/statm",O_RDONLY);
96 	char statbuff[1000],*p;
97 	int l,e;
98 	e = 0;
99 	*rss = 0;
100 	*virt = 0;
101 	if (fd>=0) {
102 		l = read(fd,statbuff,1000);
103 		if (l<1000 && l>0) {
104 			statbuff[l]=0;
105 			*virt = strtoul(statbuff,&p,10) * getpagesize();
106 			if (*p==' ') {
107 				*rss = strtoul(p+1,&p,10) * getpagesize();
108 				if (*p==' ' || *p=='\0') {
109 					e = 1;
110 				}
111 			}
112 		}
113 		close(fd);
114 	}
115 	return e;
116 #elif MEMORY_USAGE
117 	struct rusage ru;
118 	getrusage(RUSAGE_SELF,&ru);
119 	*rss = *virt = ru.ru_maxrss * UINT64_C(1024);
120 	return 2;
121 #else
122 	return 0;
123 #endif
124 }
125