1 /*
2  * Copyright (C) 2016 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 #if defined(HAVE_SETITIMER)
26 #  include <sys/time.h>
27 #  ifndef ITIMER_REAL
28 #    define ITIMER_REAL 0
29 #  endif
30 #  ifndef ITIMER_VIRTUAL
31 #    define ITIMER_VIRTUAL 1
32 #  endif
33 #  ifndef ITIMER_PROF
34 #    define ITIMER_PROF 2
35 #  endif
36 #  define MAXITIMER 999
37 #endif
38 
39 #if defined(HAVE_GETRUSAGE)
40 #  include <sys/types.h>
41 #  ifdef HAVE_SYS_RESOURCE_H
42 #    include <sys/resource.h>
43 #  endif
44 #  ifdef HAVE_SYS_RUSAGE_H
45 #    include <sys/rusage.h>
46 #  endif
47 #  ifndef RUSAGE_SELF
48 #    define RUSAGE_SELF 0
49 #  endif
50 #endif
51 
52 #if defined(HAVE_GETTIMEOFDAY)
53 #  include <sys/time.h>
54 #else
55 #  include <time.h>
56 #endif
57 
58 #include <stdlib.h>
59 #include <inttypes.h>
60 // #include <syslog.h>
61 
62 #if defined(HAVE_SETITIMER)
63 static struct itimerval it_set;
64 static uint32_t addsec,addusec;
65 #endif
66 
67 #if defined(HAVE_GETRUSAGE)
68 static uint64_t lastautime;
69 static uint64_t lastastime;
70 #endif
71 
72 static uint64_t lastget;
73 
cpu_init(void)74 void cpu_init (void) {
75 #if defined(HAVE_SETITIMER)
76 	struct itimerval rc,uc,pc;
77 #endif
78 #if defined(HAVE_GETRUSAGE)
79 	struct rusage rus;
80 #endif
81 #if defined(HAVE_GETTIMEOFDAY)
82 	struct timeval tod;
83 #endif
84 
85 #if defined(HAVE_GETTIMEOFDAY)
86 	gettimeofday(&tod,NULL);
87 	lastget = tod.tv_sec;
88 	lastget *= UINT64_C(1000000);
89 	lastget += tod.tv_usec;
90 #else
91 	lastget = time(NULL);
92 	lastget *= UINT64_C(1000000);
93 #endif
94 
95 #if defined(HAVE_SETITIMER)
96 	addsec = 0;
97 	addusec = 0;
98 	it_set.it_interval.tv_sec = 0;
99 	it_set.it_interval.tv_usec = 0;
100 	it_set.it_value.tv_sec = MAXITIMER;
101 	it_set.it_value.tv_usec = 999999;
102 	setitimer(ITIMER_REAL,&it_set,&rc);                // real time
103 	setitimer(ITIMER_VIRTUAL,&it_set,&uc);             // user time
104 	setitimer(ITIMER_PROF,&it_set,&pc);                // user time + system time
105 #endif
106 
107 #if defined(HAVE_GETRUSAGE)
108         getrusage(RUSAGE_SELF,&rus);
109 
110         lastautime = (uint64_t)rus.ru_utime.tv_sec;
111         lastautime *= UINT64_C(1000000);
112         lastautime += (uint64_t)rus.ru_utime.tv_usec;
113 
114         lastastime = (uint64_t)rus.ru_stime.tv_sec;
115         lastastime *= UINT64_C(1000000);
116         lastastime += (uint64_t)rus.ru_stime.tv_usec;
117 #endif
118 }
119 
cpu_used(uint64_t * scpu,uint64_t * ucpu)120 void cpu_used (uint64_t *scpu,uint64_t *ucpu) {
121 #if defined(HAVE_SETITIMER)
122 	struct itimerval rc,uc,pc;
123 	uint64_t ucusec,pcusec;
124 #endif
125 #if defined(HAVE_GETRUSAGE)
126 	struct rusage rus;
127 	uint64_t autime,astime;
128 #endif
129 	uint64_t rdiff,now;
130 #if defined(HAVE_GETTIMEOFDAY)
131 	struct timeval tod;
132 #endif
133 	uint64_t systime,usertime;
134 
135 #if defined(HAVE_GETTIMEOFDAY)
136 	gettimeofday(&tod,NULL);
137 	now = tod.tv_sec;
138 	now *= UINT64_C(1000000);
139 	now += tod.tv_usec;
140 #else
141 	now = time(NULL);
142 	now *= UINT64_C(1000000);
143 #endif
144 
145 	if (now>lastget) {
146 		rdiff = now-lastget;
147 		lastget = now;
148 	} else {
149 		rdiff = 0;
150 	}
151 
152 	systime = 0;
153 	usertime = 0;
154 
155 //	syslog(LOG_NOTICE,"rdiff1: %"PRIu64,rdiff);
156 #if defined(HAVE_SETITIMER)
157 /* method 1 - use itimers - usually worse */
158         setitimer(ITIMER_REAL,&it_set,&rc);                // real time
159         setitimer(ITIMER_VIRTUAL,&it_set,&uc);             // user time
160         setitimer(ITIMER_PROF,&it_set,&pc);                // user time + system time
161 
162         rc.it_value.tv_sec = MAXITIMER-rc.it_value.tv_sec;
163         rc.it_value.tv_usec = 999999-rc.it_value.tv_usec;
164         uc.it_value.tv_sec = MAXITIMER-uc.it_value.tv_sec;
165         uc.it_value.tv_usec = 999999-uc.it_value.tv_usec;
166         pc.it_value.tv_sec = MAXITIMER-pc.it_value.tv_sec;
167         pc.it_value.tv_usec = 999999-pc.it_value.tv_usec;
168 	addsec += rc.it_value.tv_sec;
169 	addusec += rc.it_value.tv_usec;
170 	while (addusec>1000000) {
171 		addusec-=1000000;
172 		addsec++;
173 	}
174 
175 	if (rc.it_value.tv_sec>=0 && rc.it_value.tv_usec>=0) {
176 		rdiff = (uint64_t)rc.it_value.tv_sec;
177 		rdiff *= UINT64_C(1000000);
178 		rdiff += (uint64_t)rc.it_value.tv_usec;
179 	}
180 	if (uc.it_value.tv_sec>=0 && pc.it_value.tv_sec>=0 && uc.it_value.tv_usec>=0 && pc.it_value.tv_usec>=0) {
181 	        ucusec = (uint64_t)uc.it_value.tv_sec;
182 		ucusec *= UINT64_C(1000000);
183 		ucusec += (uint64_t)uc.it_value.tv_usec;
184 	        pcusec = (uint64_t)pc.it_value.tv_sec;
185 		pcusec *= UINT64_C(1000000);
186 		pcusec += (uint64_t)pc.it_value.tv_usec;
187 	} else {
188 		ucusec = 0;
189 		pcusec = 0;
190 	}
191 
192         if (pcusec>ucusec) {
193                 pcusec-=ucusec;
194         } else {
195                 pcusec=0;
196         }
197 	usertime = ucusec;
198 	systime = pcusec;
199 #endif
200 
201 //	syslog(LOG_NOTICE,"rdiff2: %"PRIu64,rdiff);
202 //	syslog(LOG_NOTICE,"usertime1: %"PRIu64",systime1: %"PRIu64,usertime,systime);
203 
204 #if defined(HAVE_GETRUSAGE)
205 /* method 2 - use getrusage - usually better (if both are available, overwrites data set by itimer method) */
206         getrusage(RUSAGE_SELF,&rus);
207 
208         autime = (uint64_t)rus.ru_utime.tv_sec;
209         autime *= UINT64_C(1000000);
210         autime += (uint64_t)rus.ru_utime.tv_usec;
211 
212         astime = (uint64_t)rus.ru_stime.tv_sec;
213         astime *= UINT64_C(1000000);
214         astime += (uint64_t)rus.ru_stime.tv_usec;
215 
216 	if (autime>lastautime) {
217 		usertime = autime - lastautime;
218 		lastautime = autime;
219 	}
220 
221 	if (astime>lastastime) {
222 		systime = astime - lastastime;
223 		lastastime = astime;
224 	}
225 #endif
226 
227 //	syslog(LOG_NOTICE,"usertime2: %"PRIu64",systime2: %"PRIu64,usertime,systime);
228 
229 	if (rdiff>0) {
230 		*scpu = (systime*UINT64_C(1000000000)) / rdiff;
231 		*ucpu = (usertime*UINT64_C(1000000000)) / rdiff;
232 	} else {
233 		*scpu = 0;
234 		*ucpu = 0;
235 	}
236 
237 //	syslog(LOG_NOTICE,"scpu: %"PRIu32",ucpu: %"PRIu32,*scpu,*ucpu);
238 }
239