/** * Start production profiling for the application. * * There are three modes for profiling: * * 1. Wall-time only profiling of the complete request (no overhead) * 2. Full profile/trace using xhprof (depending of # function calls * significant overhead) * 3. Whitelist-profiling mode only interesting functions. * (5-40% overhead, requires custom xhprof version >= 0.95) * * Decisions to profile are made based on a sample-rate and random picks. * You can influence the sample rate and pick a value that suites your * application. Applications with lower request rates need a much higher * transaction rate (25-50%) than applications with high load (<= 1%). * * Factors that influence sample rate: * * 1. Second parameter $sampleRate to start() method. * 2. _qprofiler Query Parameter (string key is deprecated or array) * 3. Cookie TIDEWAYS_SESSION * 4. TIDEWAYS_SAMPLERATE environment variable. * * start() automatically invokes a register shutdown handler that stops and * transmits the profiling data to the local daemon for further processing. * * @param array|string $options Either options array or api key (when string) * @param int $sampleRate Deprecated, use "sample_rate" key in options instead. * * @return void */ public static function start($options = array(), $sampleRate = null) { if (self::$mode !== self::MODE_NONE) { return; } if (!is_array($options)) { $options = array('api_key' => $options); } if ($sampleRate !== null) { $options['sample_rate'] = $sampleRate; } $defaults = array('api_key' => isset($_SERVER['TIDEWAYS_APIKEY']) ? $_SERVER['TIDEWAYS_APIKEY'] : ini_get("tideways.api_key"), 'sample_rate' => isset($_SERVER['TIDEWAYS_SAMPLERATE']) ? intval($_SERVER['TIDEWAYS_SAMPLERATE']) : ini_get("tideways.sample_rate"), 'collect' => isset($_SERVER['TIDEWAYS_COLLECT']) ? $_SERVER['TIDEWAYS_COLLECT'] : (ini_get("tideways.collect") ?: self::MODE_TRACING), 'monitor' => isset($_SERVER['TIDEWAYS_MONITOR']) ? $_SERVER['TIDEWAYS_MONITOR'] : (ini_get("tideways.monitor") ?: self::MODE_BASIC), 'distributed_tracing_hosts' => isset($_SERVER['TIDEWAYS_ALLOWED_HOSTS']) ? $_SERVER['TIDEWAYS_ALLOWED_HOSTS'] : (ini_get("tideways.distributed_tracing_hosts") ?: '127.0.0.1'), 'distributed_trace' => null); $options = array_merge($defaults, $options); if (strlen((string) $options['api_key']) === 0) { return; } self::init($options['api_key'], $options['distributed_trace'], $options['distributed_tracing_hosts']); self::$mode = self::decideProfiling($options['sample_rate'], $options); if (self::$extension === self::EXTENSION_TIDEWAYS) { switch (self::$mode) { case self::MODE_FULL: $flags = 0; break; case self::MODE_PROFILING: $flags = TIDEWAYS_FLAGS_NO_SPANS; break; case self::MODE_TRACING: $flags = TIDEWAYS_FLAGS_NO_HIERACHICAL; break; default: $flags = TIDEWAYS_FLAGS_NO_COMPILE | TIDEWAYS_FLAGS_NO_USERLAND | TIDEWAYS_FLAGS_NO_BUILTINS; break; } self::$currentRootSpan = new \Tideways\Traces\TwExtensionSpan(0); tideways_enable($flags, self::$defaultOptions); if (($flags & TIDEWAYS_FLAGS_NO_SPANS) === 0) { foreach (self::$defaultOptions['watches'] as $watch => $category) { tideways_span_watch($watch, $category); } foreach (self::$defaultOptions['callbacks'] as $function => $callback) { tideways_span_callback($function, $callback); } } } elseif (self::$extension === self::EXTENSION_XHPROF && (self::$mode & self::MODE_PROFILING) > 0) { \Tideways\Traces\PhpSpan::clear(); self::$currentRootSpan = new \Tideways\Traces\PhpSpan(0, 'app'); self::$currentRootSpan->startTimer(); xhprof_enable(0, self::$defaultOptions); } else { \Tideways\Traces\PhpSpan::clear(); self::$currentRootSpan = new \Tideways\Traces\PhpSpan(0, 'app'); self::$currentRootSpan->startTimer(); } }
/** * Enable the profiler in the given $mode. * * @param string $mode * @return void */ private static function enableProfiler($mode) { self::$mode = $mode; if (self::$extension === self::EXTENSION_TIDEWAYS && self::$mode !== self::MODE_NONE) { switch (self::$mode) { case self::MODE_FULL: $flags = 0; break; case self::MODE_PROFILING: $flags = TIDEWAYS_FLAGS_NO_SPANS; break; case self::MODE_TRACING: $flags = TIDEWAYS_FLAGS_NO_HIERACHICAL; break; default: $flags = TIDEWAYS_FLAGS_NO_COMPILE | TIDEWAYS_FLAGS_NO_USERLAND | TIDEWAYS_FLAGS_NO_BUILTINS; break; } self::$currentRootSpan = new \Tideways\Traces\TwExtensionSpan(0); tideways_enable($flags, self::$defaultOptions); if (($flags & TIDEWAYS_FLAGS_NO_SPANS) === 0) { foreach (self::$defaultOptions['watches'] as $watch => $category) { tideways_span_watch($watch, $category); } foreach (self::$defaultOptions['callbacks'] as $function => $callback) { tideways_span_callback($function, $callback); } } self::log(2, "Starting tideways extension for " . self::$trace['apiKey'] . " with mode: " . $mode); } elseif (self::$extension === self::EXTENSION_XHPROF && (self::$mode & self::MODE_PROFILING) > 0) { \Tideways\Traces\PhpSpan::clear(); self::$currentRootSpan = new \Tideways\Traces\PhpSpan(0, 'app'); self::$currentRootSpan->startTimer(); xhprof_enable(0, self::$defaultOptions); self::log(2, "Starting xhprof extension for " . self::$trace['apiKey'] . " with mode: " . $mode); } else { \Tideways\Traces\PhpSpan::clear(); self::$currentRootSpan = new \Tideways\Traces\PhpSpan(0, 'app'); self::$currentRootSpan->startTimer(); self::log(2, "Starting non-extension based tracing for " . self::$trace['apiKey'] . " with mode: " . $mode); } }