1 /*
2    Copyright 2005-2010 Jakub Kruszona-Zawadzki, Gemius SA, 2013-2014 EditShare, 2013-2015 Skytechnology sp. z o.o..
3 
4    This file was part of MooseFS and is part of LizardFS.
5 
6    LizardFS 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 3.
9 
10    LizardFS 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 LizardFS  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "common/platform.h"
20 #include "master/chartsdata.h"
21 
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <syslog.h>
28 #include <time.h>
29 #include <unistd.h>
30 
31 #include "common/charts.h"
32 #include "common/event_loop.h"
33 #include "master/chunks.h"
34 #include "master/filesystem.h"
35 #include "master/filesystem_operations.h"
36 #include "master/matoclserv.h"
37 
38 #if defined(LIZARDFS_HAVE_GETRUSAGE) && defined(LIZARDFS_HAVE_STRUCT_RUSAGE_RU_MAXRSS)
39 #  include <sys/types.h>
40 #  ifdef LIZARDFS_HAVE_SYS_RESOURCE_H
41 #    include <sys/resource.h>
42 #  endif
43 #  ifdef LIZARDFS_HAVE_SYS_RUSAGE_H
44 #    include <sys/rusage.h>
45 #  endif
46 #  ifndef RUSAGE_SELF
47 #    define RUSAGE_SELF 0
48 #  endif
49 #  define MEMORY_USAGE 1
50 #endif
51 
52 #if defined(LIZARDFS_HAVE_SETITIMER)
53 #  include <sys/time.h>
54 #  ifndef ITIMER_REAL
55 #    define ITIMER_REAL 0
56 #  endif
57 #  ifndef ITIMER_VIRTUAL
58 #    define ITIMER_VIRTUAL 1
59 #  endif
60 #  ifndef ITIMER_PROF
61 #    define ITIMER_PROF 2
62 #  endif
63 #  define CPU_USAGE 1
64 #endif
65 
66 #define CHARTS_FILENAME "stats.mfs"
67 
68 #define CHARTS_UCPU 0
69 #define CHARTS_SCPU 1
70 #define CHARTS_DELCHUNK 2
71 #define CHARTS_REPLCHUNK 3
72 #define CHARTS_STATFS 4
73 #define CHARTS_GETATTR 5
74 #define CHARTS_SETATTR 6
75 #define CHARTS_LOOKUP 7
76 #define CHARTS_MKDIR 8
77 #define CHARTS_RMDIR 9
78 #define CHARTS_SYMLINK 10
79 #define CHARTS_READLINK 11
80 #define CHARTS_MKNOD 12
81 #define CHARTS_UNLINK 13
82 #define CHARTS_RENAME 14
83 #define CHARTS_LINK 15
84 #define CHARTS_READDIR 16
85 #define CHARTS_OPEN 17
86 #define CHARTS_READ 18
87 #define CHARTS_WRITE 19
88 #define CHARTS_MEMORY 20
89 #define CHARTS_PACKETSRCVD 21
90 #define CHARTS_PACKETSSENT 22
91 #define CHARTS_BYTESRCVD 23
92 #define CHARTS_BYTESSENT 24
93 
94 #define CHARTS 25
95 
96 /* name , join mode , percent , scale , multiplier , divisor */
97 #define STATDEFS { \
98 	{"ucpu"         ,CHARTS_MODE_ADD,1,CHARTS_SCALE_MICRO, 100,60}, \
99 	{"scpu"         ,CHARTS_MODE_ADD,1,CHARTS_SCALE_MICRO, 100,60}, \
100 	{"delete"       ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
101 	{"replicate"    ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
102 	{"statfs"       ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
103 	{"getattr"      ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
104 	{"setattr"      ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
105 	{"lookup"       ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
106 	{"mkdir"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
107 	{"rmdir"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
108 	{"symlink"      ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
109 	{"readlink"     ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
110 	{"mknod"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
111 	{"unlink"       ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
112 	{"rename"       ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
113 	{"link"         ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
114 	{"readdir"      ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
115 	{"open"         ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
116 	{"read"         ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
117 	{"write"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_NONE ,   1, 1}, \
118 	{"memory"       ,CHARTS_MODE_MAX,0,CHARTS_SCALE_NONE ,   1, 1}, \
119 	{"prcvd"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_MILI ,1000,60}, \
120 	{"psent"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_MILI ,1000,60}, \
121 	{"brcvd"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_MILI ,8000,60}, \
122 	{"bsent"        ,CHARTS_MODE_ADD,0,CHARTS_SCALE_MILI ,8000,60}, \
123 	{NULL           ,0              ,0,0                 ,   0, 0}  \
124 };
125 
126 #define CALCDEFS { \
127 	CHARTS_DEFS_END \
128 };
129 
130 /* c1_def , c2_def , c3_def , join mode , percent , scale , multiplier , divisor */
131 #define ESTATDEFS { \
132 	{CHARTS_DIRECT(CHARTS_UCPU)        ,CHARTS_DIRECT(CHARTS_SCPU)        ,CHARTS_NONE                       ,CHARTS_MODE_ADD,1,CHARTS_SCALE_MICRO, 100,60}, \
133 	{CHARTS_NONE                       ,CHARTS_NONE                       ,CHARTS_NONE                       ,0              ,0,0                 ,   0, 0}  \
134 };
135 
136 static const uint32_t calcdefs[]=CALCDEFS
137 static const statdef statdefs[]=STATDEFS
138 static const estatdef estatdefs[]=ESTATDEFS
139 
140 #ifdef CPU_USAGE
141 static struct itimerval it_set;
142 #endif
143 
144 #ifdef MEMORY_USAGE
145 static uint64_t memusage;
chartsdata_memusage(void)146 uint64_t chartsdata_memusage(void) {
147 	return memusage;
148 }
149 #else
chartsdata_memusage(void)150 uint64_t chartsdata_memusage(void) {
151 	return 0;
152 }
153 #endif
154 
chartsdata_refresh(void)155 void chartsdata_refresh(void) {
156 	uint64_t data[CHARTS];
157 	std::array<uint32_t, FsStats::Size> fsdata;
158 	uint32_t i,del,repl; //,bin,bout,opr,opw,dbr,dbw,dopr,dopw,repl;
159 #ifdef CPU_USAGE
160 	struct itimerval uc,pc;
161 	uint32_t ucusec,pcusec;
162 #endif
163 #ifdef MEMORY_USAGE
164 	struct rusage ru;
165 #endif
166 
167 	for (i=0 ; i<CHARTS ; i++) {
168 		data[i]=CHARTS_NODATA;
169 	}
170 
171 #ifdef CPU_USAGE
172 // CPU usage
173 	setitimer(ITIMER_VIRTUAL,&it_set,&uc);             // user time
174 	setitimer(ITIMER_PROF,&it_set,&pc);                // user time + system time
175 
176 	if (uc.it_value.tv_sec<=999) {  // on fucken linux timers can go backward !!!
177 		uc.it_value.tv_sec = 999-uc.it_value.tv_sec;
178 		uc.it_value.tv_usec = 999999-uc.it_value.tv_usec;
179 	} else {
180 		uc.it_value.tv_sec = 0;
181 		uc.it_value.tv_usec = 0;
182 	}
183 	if (pc.it_value.tv_sec<=999) {  // as abowe - who the hell has invented this stupid os !!!
184 		pc.it_value.tv_sec = 999-pc.it_value.tv_sec;
185 		pc.it_value.tv_usec = 999999-pc.it_value.tv_usec;
186 	} else {
187 		pc.it_value.tv_sec = 0;
188 		uc.it_value.tv_usec = 0;
189 	}
190 
191 	ucusec = uc.it_value.tv_sec*1000000U+uc.it_value.tv_usec;
192 	pcusec = pc.it_value.tv_sec*1000000U+pc.it_value.tv_usec;
193 
194 	if (pcusec>ucusec) {
195 		pcusec-=ucusec;
196 	} else {
197 		pcusec=0;
198 	}
199 	data[CHARTS_UCPU] = ucusec;
200 	data[CHARTS_SCPU] = pcusec;
201 #endif
202 
203 // memory usage
204 #ifdef MEMORY_USAGE
205 	getrusage(RUSAGE_SELF,&ru);
206 #  ifdef __APPLE__
207 	memusage = ru.ru_maxrss;
208 #  else
209 	memusage = ru.ru_maxrss * UINT64_C(1024);
210 #  endif
211 #  ifdef __linux__
212 	if (memusage==0) {
213 		int fd = open("/proc/self/statm",O_RDONLY);
214 		char statbuff[1000];
215 		int l;
216 		if (fd>=0) {
217 			l = read(fd,statbuff,1000);
218 			if (l<1000 && l>0) {
219 				statbuff[l]=0;
220 				memusage = strtoul(statbuff,NULL,10)*getpagesize();
221 			}
222 			close(fd);
223 		}
224 	}
225 #  endif
226 	if (memusage>0) {
227 		data[CHARTS_MEMORY] = memusage;
228 	}
229 #endif
230 
231 	chunk_stats(&del,&repl);
232 	data[CHARTS_DELCHUNK]=del;
233 	data[CHARTS_REPLCHUNK]=repl;
234 	fs_retrieve_stats(fsdata);
235 	for (i = 0 ; i < FsStats::Size; ++i) {
236 		data[CHARTS_STATFS + i] = fsdata[i];
237 	}
238 	matoclserv_stats(data+CHARTS_PACKETSRCVD);
239 
240 	charts_add(data,eventloop_time()-60);
241 }
242 
chartsdata_term(void)243 void chartsdata_term(void) {
244 	chartsdata_refresh();
245 	charts_store();
246 	charts_term();
247 }
248 
chartsdata_store(void)249 void chartsdata_store(void) {
250 	charts_store();
251 }
252 
chartsdata_init(void)253 int chartsdata_init (void) {
254 #ifdef CPU_USAGE
255 	struct itimerval uc,pc;
256 #endif
257 #ifdef MEMORY_USAGE
258 	struct rusage ru;
259 #endif
260 
261 #ifdef CPU_USAGE
262 	it_set.it_interval.tv_sec = 0;
263 	it_set.it_interval.tv_usec = 0;
264 	it_set.it_value.tv_sec = 999;
265 	it_set.it_value.tv_usec = 999999;
266 	setitimer(ITIMER_VIRTUAL,&it_set,&uc);             // user time
267 	setitimer(ITIMER_PROF,&it_set,&pc);                // user time + system time
268 #endif
269 #ifdef MEMORY_USAGE
270 	getrusage(RUSAGE_SELF,&ru);
271 #  ifdef __APPLE__
272 	memusage = ru.ru_maxrss;
273 #  else
274 	memusage = ru.ru_maxrss * 1024;
275 #  endif
276 #endif
277 
278 	eventloop_timeregister(TIMEMODE_RUN_LATE,60,0,chartsdata_refresh);
279 	eventloop_timeregister(TIMEMODE_RUN_LATE,3600,0,chartsdata_store);
280 	eventloop_destructregister(chartsdata_term);
281 	return charts_init(calcdefs,statdefs,estatdefs,CHARTS_FILENAME);
282 }
283