1: <?php
2: /**
3: * @author: stev leibelt <artodeto@bazzline.net>
4: * @since: 2014-07-27
5: */
6:
7: namespace Net\Bazzline\Component\MemoryLimitManager;
8:
9: /**
10: * Class MemoryLimitManager
11: * @package Net\Bazzline\Component\Fork
12: */
13: class MemoryLimitManager
14: {
15: /**
16: * @var int
17: */
18: private $bufferInBytes;
19:
20: /**
21: * @var int
22: */
23: private $limitFromIniInBytes;
24:
25: /**
26: * @var int
27: */
28: private $limitInBytes;
29:
30: public function __construct()
31: {
32: $currentMemoryLimitFromIni = trim(ini_get('memory_limit'));
33:
34: if (((int) $currentMemoryLimitFromIni) > 0) {
35: $unitIdentifier = strtolower($currentMemoryLimitFromIni[strlen($currentMemoryLimitFromIni)-1]);
36: $value = (int) substr($currentMemoryLimitFromIni, 0, -1);
37:
38: switch ($unitIdentifier) {
39: case 'g':
40: $this->limitFromIniInBytes = ($this->gigaBytesInBytes($value));
41: break;
42: case 'm':
43: $this->limitFromIniInBytes = ($this->megaBytesInBytes($value));
44: break;
45: case 'k':
46: $this->limitFromIniInBytes = ($this->kiloBytesInBytes($value));
47: break;
48: default:
49: $this->limitFromIniInBytes = $value;
50: }
51: } else {
52: $this->limitFromIniInBytes = 0;
53: }
54:
55: $this->limitInBytes = $this->limitFromIniInBytes;
56: }
57:
58: /**
59: * @param int $bytes
60: */
61: public function setBufferInBytes($bytes)
62: {
63: $this->bufferInBytes = (int) $bytes;
64: }
65:
66: /**
67: * @param int $kiloBytes
68: */
69: public function setBufferInKiloBytes($kiloBytes)
70: {
71: $this->setBufferInBytes($this->kiloBytesInBytes($kiloBytes));
72: }
73:
74: /**
75: * @param int $megaBytes
76: */
77: public function setBufferInMegaBytes($megaBytes)
78: {
79: $this->setBufferInBytes($this->megaBytesInBytes($megaBytes));
80: }
81:
82: /**
83: * @param int $gigaBytes
84: */
85: public function setBufferInGigaBytes($gigaBytes)
86: {
87: $this->setBufferInBytes($this->gigaBytesInBytes($gigaBytes));
88: }
89:
90: /**
91: * @return int
92: */
93: public function getBufferInBytes()
94: {
95: return $this->bufferInBytes;
96: }
97:
98: /**
99: * @return int
100: */
101: public function getBufferInKiloBytes()
102: {
103: return $this->bytesInKiloBytes($this->bufferInBytes);
104: }
105:
106: /**
107: * @return int
108: */
109: public function getBufferInMegaBytes()
110: {
111: return $this->bytesInMegaBytes($this->bufferInBytes);
112: }
113:
114: /**
115: * @return int
116: */
117: public function getBufferInGigaBytes()
118: {
119: return $this->bytesInGigaBytes($this->bufferInBytes);
120: }
121:
122: /**
123: * @param int $bytes
124: * @throws InvalidArgumentException
125: */
126: public function setLimitInBytes($bytes)
127: {
128: if ($this->limitFromIniInBytes > 0) {
129: if ($bytes > $this->limitFromIniInBytes) {
130: throw new InvalidArgumentException(
131: 'provided limit (' . $bytes .
132: ') is above ini limit (' .
133: $this->limitFromIniInBytes . ')',
134: 1
135: );
136: }
137: }
138:
139: $this->limitInBytes = (int) $bytes;
140: }
141:
142: /**
143: * @param int $kiloBytes
144: * @throws InvalidArgumentException
145: */
146: public function setLimitInKiloBytes($kiloBytes)
147: {
148: $this->setLimitInBytes($this->kiloBytesInBytes($kiloBytes));
149: }
150:
151: /**
152: * @param int $megaBytes
153: * @throws InvalidArgumentException
154: */
155: public function setLimitInMegaBytes($megaBytes)
156: {
157: $this->setLimitInBytes($this->megaBytesInBytes($megaBytes));
158: }
159:
160: /**
161: * @param int $gigaBytes
162: * @throws InvalidArgumentException
163: */
164: public function setLimitInGigaBytes($gigaBytes)
165: {
166: $this->setLimitInBytes($this->gigaBytesInBytes($gigaBytes));
167: }
168:
169: /**
170: * @return int
171: */
172: public function getLimitInBytes()
173: {
174: return $this->limitInBytes;
175: }
176:
177: /**
178: * @return int
179: */
180: public function getLimitInKiloBytes()
181: {
182: return $this->bytesInKiloBytes($this->limitInBytes);
183: }
184:
185: /**
186: * @return int
187: */
188: public function getLimitInMegaBytes()
189: {
190: return $this->bytesInMegaBytes($this->limitInBytes);
191: }
192:
193: /**
194: * @return int
195: */
196: public function getLimitInGigaBytes()
197: {
198: return $this->bytesInGigaBytes($this->limitInBytes);
199: }
200:
201: /**
202: * @param array $processIds
203: * @return int
204: */
205: public function getCurrentUsageInBytes(array $processIds = array())
206: {
207: $currentUsageInBytes = memory_get_usage(true);
208:
209: foreach ($processIds as $processId) {
210: $return = 0;
211: exec('ps -p ' . $processId . ' --no-headers -o rss', $return);
212:
213: if (isset($return[0])) {
214: //non-swapped physical memory in kilo bytes
215: $usageInBytes = (int) $return[0];
216: $currentUsageInBytes += ($usageInBytes * 1024);
217: }
218: }
219:
220: return $currentUsageInBytes;
221: }
222:
223: /**
224: * @param array $processIds
225: * @return int
226: */
227: public function getCurrentUsageInKiloBytes(array $processIds = array())
228: {
229: return $this->bytesInKiloBytes($this->getCurrentUsageInBytes($processIds));
230: }
231:
232: /**
233: * @param array $processIds
234: * @return int
235: */
236: public function getCurrentUsageInMegaBytes(array $processIds = array())
237: {
238: return $this->bytesInMegaBytes($this->getCurrentUsageInBytes($processIds));
239: }
240:
241: /**
242: * @param array $processIds
243: * @return int
244: */
245: public function getCurrentUsageInGigaBytes(array $processIds = array())
246: {
247: return $this->bytesInGigaBytes($this->getCurrentUsageInBytes($processIds));
248: }
249:
250: /**
251: * @param array $processIds
252: * @return bool
253: */
254: public function isLimitReached(array $processIds = array())
255: {
256: $currentUsageInBytes = $this->getCurrentUsageInBytes($processIds);
257: $currentUsageWithBufferInBytes = $currentUsageInBytes + $this->bufferInBytes;
258:
259: $isReached = ($currentUsageWithBufferInBytes >= $this->limitInBytes);
260:
261: return $isReached;
262: }
263:
264: /**
265: * @param int $bytes
266: * @return int
267: */
268: private function bytesInKiloBytes($bytes)
269: {
270: return ((int) ($bytes / 1024));
271: }
272:
273: /**
274: * @param int $bytes
275: * @return int
276: */
277: private function bytesInMegaBytes($bytes)
278: {
279: return ((int) ($bytes / 1048576)); //1048576 = 1024 * 1024
280: }
281:
282: /**
283: * @param int $bytes
284: * @return int
285: */
286: private function bytesInGigaBytes($bytes)
287: {
288: return ((int) ($bytes / 1073741824)); //1073741824 = 1024 * 1024 * 1024
289: }
290:
291: /**
292: * @param int $kiloBytes
293: * @return int
294: */
295: private function kiloBytesInBytes($kiloBytes)
296: {
297: return ((int) ($kiloBytes * 1024));
298: }
299:
300: /**
301: * @param int $megaBytes
302: * @return int
303: */
304: private function megaBytesInBytes($megaBytes)
305: {
306: return ((int) ($megaBytes * 1048576)); //1048576 = 1024 * 1024
307: }
308:
309: /**
310: * @param int $gigaBytes
311: * @return int
312: */
313: private function gigaBytesInBytes($gigaBytes)
314: {
315: return ((int) ($gigaBytes * 1073741824)); //1073741824 = 1024 * 1024 * 1024
316: }
317: }
318: