Skip to content

Commit d276e48

Browse files
authored
Merge pull request #47 from arnaud-lb/autodump
Auto dump profile on memory exhaustion
2 parents ced7a54 + afcad6f commit d276e48

File tree

7 files changed

+499
-118
lines changed

7 files changed

+499
-118
lines changed

README.md

Lines changed: 79 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,51 @@ Or permanently, in php.ini:
5151

5252
The extension has no overhead when not profiling, so it can be loaded by default on dev environments.
5353

54-
## Usage
54+
## Usage example
5555

56-
Using the extension is done in three steps:
56+
The simplest way to use `memprof` is to let it save the memory profile when the
57+
program's memory limit is exceeded.
5758

58-
### 1. Enabling profile
59+
### Step 1: Enable profiling in `dump_on_limit` mode
5960

60-
Profiling is enabled at request startup when one of these is true:
61+
Profiling in `dump_on_limit` mode is enabled at request startup when one
62+
of these is true:
6163

62-
* The environment variable `MEMPROF_PROFILE` is non-empty
63-
* `$_GET["MEMPROF_PROFILE"]` is non-empty
64-
* `$_POST["MEMPROF_PROFILE"]` is non-empty
64+
* The environment variable `MEMPROF_PROFILE` is equal to `dump_on_limit`
65+
* `$_GET["MEMPROF_PROFILE"]` is equal to `dump_on_limit`
66+
* `$_POST["MEMPROF_PROFILE"]` is equal to `dump_on_limit`
6567

66-
### 2. Dumping the profile
68+
For command line scripts, we can set the environment variable:
6769

68-
Once profiling is enabled, the program must call ``memprof_dump_callgrind()`` or
69-
one it its variants to dump the memory profile.
70+
```
71+
MEMPROF_PROFILE=dump_on_limit php test.php
72+
```
7073

71-
This can be done at anytime during the program, ideally when the leak is large,
72-
so that it will be more visible in the profile.
74+
For web scripts, we can set the `$_GET` variable:
7375

74-
This can be done multiple times during the same execution, but this is not necessary.
76+
```
77+
curl http://127.0.0.1/test.php?MEMPROF_PROFILE=dump_on_limit
78+
```
7579

76-
### 3. Visualizing the profile
80+
Or the `$_POST` variable:
81+
82+
```
83+
curl -d MEMPROF_PROFILE=dump_on_limit http://127.0.0.1/test.php
84+
```
85+
86+
> :information_source: The `memprof_enabled_flags()` function can be called to
87+
> check whether profiling is currently enabled in `dump_on_limit` mode.
88+
89+
### Step 2: Dumping the profile
90+
91+
In this mode, `memprof` will automatically save the profile if the program
92+
exceeds the memory limit (when PHP triggers an error like `Fatal error: Allowed
93+
memory size of 15728640 bytes exhausted (tried to allocate 1024 bytes)` error).
94+
95+
By default, the profile is saved in a file named `memprof.callgrind.*` in `/tmp`
96+
or `C:\Windows\Temp`.
97+
98+
### Step 3: Visualizing the profile
7799

78100
The recommended way to visualize the result is to use Kcachegrind (on Linux) or Qcachegrind (on MacOS, Windows). Google Perftools are also supported. See the documentation of ``memprof_dump_callgrind()`` and variants.
79101

@@ -97,42 +119,62 @@ Use Homebrew: https://formulae.brew.sh/formula/qcachegrind
97119

98120
Download it from https://sourceforge.net/projects/qcachegrindwin/
99121

100-
### Usage example
122+
## Advanced usage
101123

102-
```
103-
<?php // test.php
124+
### Profile trigger
104125

105-
do_some_work();
126+
Profiling is enabled at request startup when one of these is true:
106127

107-
if (function_exists('memprof_enabled') && memprof_enabled()) {
108-
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));
109-
}
110-
```
128+
* The environment variable `MEMPROF_PROFILE` is non-empty
129+
* `$_GET["MEMPROF_PROFILE"]` is non-empty
130+
* `$_POST["MEMPROF_PROFILE"]` is non-empty
111131

112-
When ran on the command line, profiling can be enabled by setting the `MEMPROF_PROFILE` environment variable:
132+
### Profile flags
113133

114-
```
115-
MEMPROF_PROFILE=1 php test.php
116-
```
134+
The `MEMPROF_PROFILE` variable accepts a comma-separated list of flags.
117135

118-
When ran in a web context, profiling can be enabled by setting the `MEMPROF_PROFILE` query string parameter or POST field:
136+
Examples of valid `MEMPROF_PROFILE` values:
119137

120-
```
121-
curl http://127.0.0.1/test.php?MEMPROF_PROFILE=1
122-
```
138+
* `1`: non-empty: profiling is enabled
139+
* `dump_on_limit`: profiling is enabled, will dump on memory limit
140+
* `native`: profiling is enabled, will profile native allocations
141+
* `dump_on_limit,native`: profiling is enabled, will profile native allocations, will dump on memory limit
123142

124-
Setting a POST field works as well:
143+
List of valid flags:
125144

126-
```
127-
curl -d MEMPROF_PROFILE=1 http://127.0.0.1/test.php
128-
```
145+
* `dump_on_limit`: Will dump the profile in callgrind format in `/tmp` or
146+
`C:\Windows\Temp`. The output directory can be changed with the
147+
`memprof.output_dir` ini setting.
148+
* `native`: Will profile native `malloc()` allocations, not only PHP's (This is
149+
not thread safe, see bellow).
150+
151+
### Profiling native allocations
152+
153+
Memprof doesn't track native allocations by default, but this can be enabled
154+
by setting `MEMPROF_PROFILE` to `native`.
155+
156+
Native allocations are the allocations made outside of PHP's own memory
157+
allocator. Typically, external libraries such as libxml2 (used in the DOM
158+
extension) make native allocations. PHP can also make native allocations for
159+
persistent resources.
160+
161+
Enabling native allocation tracking will profile these allocations in addition
162+
to PHP's own allocations.
163+
164+
Note that when native tracking is enabled, the program will crash if a native
165+
library uses threads, because the underlying hooks are not thread safe.
129166

130167
## Functions documentation
131168

132169
### memprof_enabled()
133170

134171
Returns whether memory profiling is currently enabled (see above).
135172

173+
### memprof_enabled_flags()
174+
175+
Returns whether memory profiling and which profiling features are enabled (see
176+
above).
177+
136178
### memprof_dump_callgrind(resource $stream)
137179

138180
Dumps the current profile in callgrind format. The result can be visualized with tools such as
@@ -194,7 +236,8 @@ The array exposes the following information:
194236
multiple places, it is possible to see which call path caused it to leak the
195237
most memory
196238

197-
Example output:
239+
<details>
240+
<summary>Example output</summary>
198241

199242
Array
200243
(
@@ -262,10 +305,10 @@ Example output:
262305
)
263306
)
264307
)
308+
</details>
265309

266310
## Troubleshooting
267311

268-
* If you are experiencing crashes, try disabling malloc hooks by setting HAVE_MALLOC_HOOKS to 0 in config.h after running configure; then run ``make clean && make && make install``. (Using malloc hooks may crash if some other extension uses threads internally.)
269312
* The extensions may conflict with xdebug, blackfire, or other extensions. If that's the case for you, please report it.
270313

271314
## PHP versions
@@ -274,10 +317,6 @@ The current branch supports PHP 7.1 to PHP 8.
274317

275318
The php5 branch supports PHP 5.
276319

277-
## TODO
278-
279-
* Thread-safe malloc hooks
280-
281320
## How it works
282321

283322
See [INTERNALS.md][7]

0 commit comments

Comments
 (0)