1<?php
2/**
3 * Simple interface for tracking memory consumption.
4 *
5 * <code>
6 *  $t = new Horde_Support_Memory;
7 *  $t->push();
8 *  $used = $t->pop();
9 * </code>
10 *
11 * Do not expect too much of this memory tracker. Profiling memory is not
12 * trivial as your placement of the measurements may obscure important
13 * information. As a trivial example: Assuming that your script used 20 MB of
14 * memory befory you call push() the information you get when calling pop()
15 * might only tell you that there was less than 20 MB of memory consumed in
16 * between the two calls. Take the changes to internal memory handling of PHP in
17 * between the different versions into account
18 * (http://de3.php.net/manual/en/features.gc.performance-considerations.php) and
19 * you should get an idea about why you might be cautious about the values you
20 * get from this memory tracker.
21 *
22 * Copyright 2011-2017 Horde LLC (http://www.horde.org/)
23 *
24 * @category   Horde
25 * @package    Support
26 * @license    http://www.horde.org/licenses/bsd
27 */
28class Horde_Support_Memory
29{
30    /**
31     * Holds the starting memory consumption.
32     *
33     * @var array
34     */
35    protected $_start = array();
36
37    /**
38     * Current index for stacked trackers.
39     *
40     * @var integer
41     */
42    protected $_idx = 0;
43
44    /**
45     * Push a new tracker on the stack.
46     */
47    public function push()
48    {
49        $start = $this->_start[$this->_idx++] = array(
50            memory_get_usage(),
51            memory_get_peak_usage(),
52            memory_get_usage(true),
53            memory_get_peak_usage(true)
54        );
55        return $start;
56    }
57
58    /**
59     * Pop the latest tracker and return the difference with the current
60     * memory situation.
61     *
62     * @return array The change in memory allocated via emalloc() in between the
63     *               push() and the pop() call. The array holds four values: the
64     *               first one indicates the change in current usage of memory
65     *               while the second value indicates any changes in the peak
66     *               amount of memory used. The third and fourth value show
67     *               current and peak usage as well but indicate the real memory
68     *               usage and not just the part allocated via emalloc(),
69     */
70    public function pop()
71    {
72        if (! ($this->_idx > 0)) {
73            throw new Exception('No timers have been started');
74        }
75        $start = $this->_start[--$this->_idx];
76        return array(
77            memory_get_usage() - $start[0],
78            memory_get_peak_usage() - $start[1],
79            memory_get_usage(true) - $start[2],
80            memory_get_peak_usage(true) - $start[3]
81        );
82    }
83
84}
85