Having these metrics, you find bottlenecks in your PHP code. After optimization, the same profiling shows that you've done a great job.
The profile report contains 20 metrics. You can switch them instantly in the UI.
Some correlations may occur between these metrics, but each of them has its own meaning:
@kphp-profile
annotation.KPHP_PROFILER=1
environment variable.--profiler-log-prefix
option, for example --profiler-log-prefix /tmp/kphp-profile/callgrind.out.kphp
ls
directory you provided by prefix and find the report).@kphp-profile
, it is for development, profiling purposes.
While generating C++ from PHP, KPHP adds additional profiling code to all functions.
There are 3 profiler modes, all of them are set with env variable:
@kphp-profile
and everything it calls.You must run a binary with the option
--profiler-log-prefix $prefix
Every incoming query will generate a unique profile report file, which you can analyze later. Its name is:
$prefix.$suffix.$timestamp_hex.$worker_pid
$suffix is the name of @kphp-profile
function or an empty string if KPHP_PROFILER=2.
You can override this suffix with
function profiler_set_log_suffix(string $suffix = ""): void;
It may be called several times, every time a new report will be generated. An argument is an alphanumeric string.
Use profiler_set_log_suffix() somewhere deep in the call tree — to mark special cases and to easier locate a needed report after.
You can mark functions with custom labels — to “split” a function depending on arguments / other factors. Instead of appearing once, this function will appear many times (as many as it was invoked with unique labels).
function profiler_set_function_label(string $label): void;
For example, you have rpcCall() function, you extend it with:
function rpcCall($cluster_name, $query) {
profiler_set_function_label($cluster_name);
// .. all rest code
}
You'll see “rpcCall (memcache)”, “rpcCall (messages)” and so on as if they were different functions. Call graphs become separate, it allows you to analyze traffic / queries / reversed call graph for each RPC engine independently.
If computing a label takes time, wrap this call into if:
function profiler_is_enabled(): bool;
This function returns true only if it is being called in the context of the currently profiling function.
When the profiler is disabled, it is replaced with false during compilation and has absolute zero overhead.
By default, the profiler does not trace inline functions. It is done on purpose, not to add overhead for very simple functions (because profiling overhead will be times more than function consumption itself).
None the less, sometimes it's interesting, what effect do inline functions arise. Adding @kphp-profile-allow-inline
above a function forces tracing it. This annotation can be committed.
KPHP has a heuristics of auto-inlining simple functions, that's why they are missing in a report by default.
Does profiling affect performance?
Yes, everything becomes 2-3 times slower. That's why a profiler is a development tool. You can set up perf and use grafana to monitor KPHP production metrics, but of course, they are cumulative, not per-query.
Why can't I find my function in a report?
Probably it is inlined — either auto inlined or marked with @kphp-inline. As pointed above, inline functions are not profiled, but you can add @kphp-profile-allow-inline to it.
Why don't I see PHP stdlib functions in a report?
Not to harm performance, all built-in (K)PHP functions are not being profiled. The report contains only PHP functions (only your code).
Why does the uppermost function have less than 100% with KPHP_PROFILER=2?
KPHP_PROFILER=2 profiles all functions, including registered with register_shutdown_function(). They are invoked by a special wrapper <shutdown caller>.
Why the value of the callee is more than the caller?
Complicated long-chain recursions are not handled properly, this can be a reason for such effect.