A metric is a collection of costs (memory, network, CPU, ...) associated with some function calls. Blackfire offers some built-in metrics, but you can also create your own custom metrics.
You can define the performance expectations of your projects by setting an
expected metric value, on a given metric dimension, in
assertions. To write an assertion on a specific dimension,
just append the dimension name to the metric name, separated with a
For instance, for the
sql.queries metric, the number of calls is stored in
metrics.sql.queries.count and the memory usage in
metrics.sql.queries.peak_memory. To check that you don't have more than 10
SQL queries in an assertion, you would write
metrics.sql.queries.count <= 10.
The available dimensions for metrics are the following ones.
Here is the list of built-in metrics that are always available in assertions:
By default, Blackfire gives access to a large number of built-in metrics, most of them being specific to the language or popular Open-Source libraries. Based on project requirements, custom metrics can also be defined for a project.
Let's create the
cache.write metric. It will aggregate the costs of the
Cache::write() calls, an hypothetical class of my project that is memory
Besides a name (
cache.write), a metric must be associated with some
function calls, via a metric selector; here we want
to match all calls to
Cache::write(), so the selector would be
Custom metrics can be used in assertions like any other metrics: the name is
made of the
metrics. prefix, then the metric name (
cache.write in our
example), and it ends with one of the available dimensions (
"metrics.foo.bar.peak_memory < 10mb"
As a matter of fact, built-in metrics are defined in the exact same way as custom ones.
Defining a metric is all about selecting a sub-set of the profile function calls. A selector first character defines how to interpret the rest of the expression:
=: Matches the expression exactly;
^: Matches everything starting with the expression;
/: Interprets the expression as a regex that should match;
!: Interprets the expression as a regex that should not match;
The second part of the selector defines which function calls to match.
Here are some selector examples:
=Class::method: Matches the
methodfunction calls on
=func: Matches the
^ArrayObject::: Matches all function calls from the
^exif_: Matches all function calls for which the function starts with
!^spl_autoload_call$!: Matches any function/method calls but
Besides matching nodes, a metric can also be used to gather function call arguments (to be precise, you can get at most one argument for a function call).
Blackfire aggregates all calls to a function into one node to make it easy to reason about resources consumed by it. But sometimes, begin able to have different nodes for a function call depending on one argument can help if the argument makes the function behave very differently (think of a database function call that is very sensitive to the SQL statement that needs to be executed for instance).
When defining argument capturing, you determine which argument you want to
capture (1-based index) and when to capture it (
^ means that Blackfire
needs to always get the argument;
^http would only get the argument if it
starts with the
http string, all other calls would be aggregated into one
Argument capturing is only available in .blackfire.yml file.
Arguments are displayed in the function call table and in the call graph. As Blackfire displays separate nodes for each unique argument, it's also a great way to better understand how the code behaves (for instance, one node per event for an event dispatcher handle method instead of one big node for all events).