diff --git a/modules/qtools_cache_profiler/src/PerformanceService.php b/modules/qtools_cache_profiler/src/PerformanceService.php
index a44df74..4057160 100644
--- a/modules/qtools_cache_profiler/src/PerformanceService.php
+++ b/modules/qtools_cache_profiler/src/PerformanceService.php
@@ -32,7 +32,7 @@ class PerformanceService {
    * @var array
    */
   protected $configuration = [
-    'logging_mode' => 0
+    'logging_mode' => 0,
   ];
 
   // Cache actions.
diff --git a/qtools_profiler.install b/qtools_profiler.install
index e59f04f..c2b9a98 100644
--- a/qtools_profiler.install
+++ b/qtools_profiler.install
@@ -116,11 +116,10 @@ function qtools_profiler_schema() {
         'default' => 0,
       ],
       'report' => [
-        'type' => 'int',
-        'description' => 'Has profiler report',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'default' => 0,
+        'type' => 'varchar',
+        'length' => 20,
+        'description' => 'Profile report type. Empty if no report.',
+        'default' => '',
       ],
     ],
     'indexes' => [
@@ -160,3 +159,26 @@ function qtools_profiler_update_8002(&$sandbox) {
   $schema = Database::getConnection()->schema();
   $schema->addField('qtools_profiler_request', 'method', $spec);
 }
+
+/**
+ * Implements hook_update_N().
+ */
+function qtools_profiler_update_8003(&$sandbox) {
+  // Update field.
+  $spec = [
+    'type' => 'varchar',
+    'length' => 20,
+    'description' => 'Profile report type. Empty if no report.',
+    'not null' => TRUE,
+    'default' => '',
+  ];
+  $schema = Database::getConnection()->schema();
+  $schema->dropField('qtools_profiler_response', 'report');
+  $schema->addField('qtools_profiler_response', 'report', $spec);
+
+  // Set default field value.
+  $profiler = \Drupal::service('qtools_profiler.performance')->confGet('profiling')['extension'];
+  Database::getConnection()->update('qtools_profiler_response')
+    ->fields(['report' => $profiler])
+    ->execute();
+}
diff --git a/qtools_profiler.routing.yml b/qtools_profiler.routing.yml
index f66286d..cbc7a20 100644
--- a/qtools_profiler.routing.yml
+++ b/qtools_profiler.routing.yml
@@ -41,7 +41,7 @@ qtools_profiler.preview_app:
 qtools_profiler.preview.profile:
   path: '/admin/config/development/qtools_profiler/preview_profile/{id}'
   defaults:
-    _controller: '\Drupal\qtools_profiler\Controller\RequestReportController::previewProfile'
+    _controller: '\Drupal\qtools_profiler\Controller\RequestReportController::pageBuildProfile'
     _title: 'Preview Profiler info'
   requirements:
     _permission: 'qtools_profiler.preview'
diff --git a/qtools_profiler.services.yml b/qtools_profiler.services.yml
index 2706660..cf48a06 100644
--- a/qtools_profiler.services.yml
+++ b/qtools_profiler.services.yml
@@ -1,7 +1,18 @@
 services:
+  cache.qtools_profiler:
+    class: Drupal\Core\Cache\CacheBackendInterface
+    tags:
+      - { name: cache.bin }
+    factory: cache_factory:get
+    arguments: [qtools_profiler]
+
   qtools_profiler.performance:
     class: Drupal\qtools_profiler\PerformanceService
-    arguments: ['@current_user', '@database', '@datetime.time', '@module_handler', '@state', '@path.matcher']
+    arguments: ['@current_user', '@database', '@datetime.time', '@module_handler', '@state', '@path.matcher', '@plugin.manager.qtools_profiler', '@cache.qtools_profiler']
+
+  plugin.manager.qtools_profiler:
+    class: Drupal\qtools_profiler\ProfilerPluginManager
+    parent: default_plugin_manager
 
   qtools_profiler.report:
     class: Drupal\qtools_profiler\ReportService
@@ -17,4 +28,4 @@ services:
     class: Drupal\qtools_profiler\Theme\QtoolsProfilerThemeswitcherNegotiator
     arguments: ['@qtools_profiler.performance']
     tags:
-      - { name: theme_negotiator, priority: 10 }
\ No newline at end of file
+      - { name: theme_negotiator, priority: 10 }
diff --git a/src/Annotaion/Profiler.php b/src/Annotaion/Profiler.php
new file mode 100644
index 0000000..38a4db1
--- /dev/null
+++ b/src/Annotaion/Profiler.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\qtools_profiler\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a Profiler annotation object.
+ *
+ * @Annotation
+ */
+class Profiler extends Plugin {
+
+  /**
+   * The profiler plugin's internal ID, in machine name format.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The display label/name of the profiler plugin.
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   *
+   * @ingroup plugin_translatable
+   */
+  public $label;
+
+  /**
+   * A longer explanation of what the field is for.
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   *
+   * @ingroup plugin_translatable
+   */
+  public $description;
+
+  /**
+   * The name of the field formatter class.
+   *
+   * This is not provided manually, it will be added by the discovery mechanism.
+   *
+   * @var string
+   */
+  public $class;
+
+}
diff --git a/src/Controller/RequestReportController.php b/src/Controller/RequestReportController.php
index 0a92cca..5840adc 100644
--- a/src/Controller/RequestReportController.php
+++ b/src/Controller/RequestReportController.php
@@ -2,30 +2,18 @@
 
 namespace Drupal\qtools_profiler\Controller;
 
+use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormBuilderInterface;
 use Drupal\Core\Render\HtmlResponse;
-use Drupal\qtools_profiler\XHProfLib\Parser\Parser;
-use Drupal\qtools_profiler\XHProfLib\Report\Report;
-use Drupal\qtools_profiler\XHProfLib\Report\ReportConstants;
-use Drupal\qtools_profiler\XHProfLib\Run;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\qtools_profiler\Ajax\PreviewSummaryCommand;
+use Drupal\qtools_profiler\PerformanceService;
+use Drupal\qtools_profiler\ReportService;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
-use Drupal\qtools_profiler\ReportService;
-use Drupal\Core\Url;
-use Drupal\Component\Utility\Xss;
-
-use Drupal\Component\Render\FormattableMarkup;
-use Drupal\qtools_profiler\XHProfLib\Report\ReportInterface;
-
-use Drupal\qtools_profiler\PerformanceService;
-
-use Drupal\Core\Ajax\AjaxResponse;
-use Drupal\qtools_profiler\Ajax\PreviewSummaryCommand;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-
 /**
  * Class RequestReportController.
  *
@@ -68,12 +56,14 @@ class RequestReportController extends ControllerBase {
     PerformanceService $performanceService,
     ReportService $reportService,
     FormBuilderInterface $formBuilder,
-    ModuleHandlerInterface $moduleHandler
+    ModuleHandlerInterface $moduleHandler,
+    RendererInterface $renderer
   ) {
     $this->performanceService = $performanceService;
     $this->reportService = $reportService;
     $this->formBuilder = $formBuilder;
     $this->moduleHandler = $moduleHandler;
+    $this->renderer = $renderer;
   }
 
   /**
@@ -84,7 +74,8 @@ class RequestReportController extends ControllerBase {
       $container->get('qtools_profiler.performance'),
       $container->get('qtools_profiler.report'),
       $container->get('form_builder'),
-      $container->get('module_handler')
+      $container->get('module_handler'),
+      $container->get('renderer')
     );
   }
 
@@ -134,146 +125,7 @@ class RequestReportController extends ControllerBase {
    *   Page array.
    */
   public function pageBuildProfile(Request $request, $id) {
-    $route_name = $route = $request->attributes->get('_route');
-
-    // Build run from data.
-    $data = $this->reportService->getProfileDetails($id);
-    if (empty($data)) {
-      throw new NotFoundHttpException();
-    }
-
-    // Parse run.
-    $run = new Run($id, 'space', $data);
-
-    // Get filter/sort.
-    $length = $request->get('length', 100);
-    $sort = $request->get('sort', 'excl_wt');
-
-    $parser = new Parser($run, $sort, NULL);
-    $report = new Report($parser);
-    $build['#title'] = $this->t('XHProf view report for %id', ['%id' => $run->getId()]);
-    $descriptions = ReportConstants::getDescriptions();
-
-    $build['summary'] = [
-      'title' => [
-        '#type' => 'inline_template',
-        '#template' => '<h3>Summary</h3>',
-      ],
-      'table' => [
-        '#theme' => 'table',
-        '#header' => [],
-        '#rows' => $this->getSummaryRows($report, $descriptions),
-      ],
-    ];
-
-    $build['length'] = [
-      '#type' => 'inline_template',
-      '#template' => ($length == -1) ? '<h3>Displaying all functions, sorted by <em>{{ sort }}</em>.</h3>' : '<h3>Displaying top {{ length }} functions, sorted by {{ sort }}. [{{ all }}]</h3>',
-      '#context' => [
-        'length' => $length,
-        'all' => $this->l($this->t('show all'), Url::fromRoute($route_name, [
-          'id' => $run->getId(),
-          'length' => -1,
-        ])),
-        'sort' => Xss::filter($descriptions[$sort], []),
-      ],
-    ];
-
-    $build['table'] = [
-      '#theme' => 'table',
-      '#header' => $this->getRunHeader($report, $descriptions, $run, $route_name),
-      '#rows' => $this->getRunRows($report, $length),
-      '#attributes' => ['class' => ['responsive']],
-      '#attached' => [
-        'library' => [
-          'xhprof/xhprof',
-        ],
-      ],
-    ];
-
-    return $build;
-  }
-
-  /**
-   * Theme class.
-   */
-  protected function abbrClass($class) {
-    $parts = explode('\\', $class);
-    $short = array_pop($parts);
-
-    if (strlen($short) >= 40) {
-      $short = substr($short, 0, 30) . " … " . substr($short, -5);
-    }
-
-    return new FormattableMarkup('<abbr title="@class">@short</abbr>', [
-      '@class' => $class,
-      '@short' => $short,
-    ]);
-  }
-
-  /**
-   * Ger run header from report.
-   */
-  protected function getRunHeader(ReportInterface $report, $descriptions, Run $run, $route_name) {
-    $headers = ['fn', 'ct', 'ct_perc'];
-
-    $metrics = $report->getMetrics();
-
-    foreach ($metrics as $metric) {
-      $headers[] = $metric;
-      $headers[] = $metric . '_perc';
-      $headers[] = 'excl_' . $metric;
-      $headers[] = 'excl_' . $metric . '_perc';
-    }
-
-    foreach ($headers as &$header) {
-      $description = strip_tags($descriptions[$header]);
-      $link = $this->l($description, Url::fromRoute($route_name, [
-        'id' => $run->getId(),
-        'length' => -1,
-        'sort' => str_replace('_perc', '', $header),
-      ]));
-      $header = new FormattableMarkup($link, []);
-    }
-
-    return $headers;
-  }
-
-  /**
-   * Get run Rows from report.
-   */
-  protected function getRunRows(ReportInterface $report, $length) {
-    $symbols = $report->getSymbols($length);
-
-    foreach ($symbols as &$symbol) {
-      $symbol[0] = $this->abbrClass($symbol[0]);
-    }
-
-    return $symbols;
-  }
-
-  /**
-   * Get rows summary from report.
-   */
-  protected function getSummaryRows(ReportInterface $report, $descriptions) {
-    $summaryRows = [];
-    $possibileMetrics = $report->getPossibleMetrics();
-    foreach ($report->getSummary() as $metric => $value) {
-      $key = 'Total ' . Xss::filter($descriptions[$metric], []);
-      $unit = isset($possibileMetrics[$metric]) ? $possibileMetrics[$metric][1] : '';
-
-      $value = new FormattableMarkup('@value @unit', [
-        '@value' => $value,
-        '@unit' => $unit,
-      ]);
-
-      $summaryRows[] = [
-        $key,
-        $value,
-      ];
-    }
-
-    return $summaryRows;
+    return $this->performanceService->buildProfilePage($request, $id);
   }
 
   /**
@@ -312,20 +164,11 @@ class RequestReportController extends ControllerBase {
       '#theme' => 'qtools_profiler_preview_iframe',
       '#build_path' => $build_path,
     ];
-    /** @var \Drupal\Core\Render\RendererInterface $renderer */
-    $renderer = \Drupal::service('renderer');
 
     $response = new HtmlResponse();
-    $response->setContent($renderer->renderRoot($build));
+    $response->setContent($this->renderer->renderRoot($build));
 
     return $response;
   }
 
-  /**
-   * Preview profile report.
-   */
-  public function previewProfile(Request $request, $id) {
-    return $this->pageBuildProfile($request, $id);
-  }
-
 }
diff --git a/src/Extension/ExtensionInterface.php b/src/Extension/ExtensionInterface.php
deleted file mode 100644
index 8b463b2..0000000
--- a/src/Extension/ExtensionInterface.php
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-
-namespace Drupal\qtools_profiler\Extension;
-
-/**
- * Interface ExtensionInterface.
- */
-interface ExtensionInterface {
-
-  /**
-   * Returns TRUE if this extension is loaded into the PHP interpreter.
-   *
-   * @return bool
-   *   Flag if extension loaded.
-   */
-  public static function isLoaded();
-
-  /**
-   * Returns the options supported by this extension.
-   *
-   * @return mixed
-   *   Extension options.
-   */
-  public function getOptions();
-
-  /**
-   * Enable the extension.
-   */
-  public function enable($modifier, $options);
-
-  /**
-   * Disable the extension.
-   */
-  public function disable();
-
-}
diff --git a/src/Extension/TidewaysXhprofExtension.php b/src/Extension/TidewaysXhprofExtension.php
deleted file mode 100644
index 9fa0510..0000000
--- a/src/Extension/TidewaysXhprofExtension.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-
-namespace Drupal\qtools_profiler\Extension;
-
-/**
- * Class TidewaysXhprofExtension.
- */
-class TidewaysXhprofExtension implements ExtensionInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function isLoaded() {
-    return extension_loaded('tideways_xhprof');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getOptions() {
-    return [
-      'FLAGS_CPU' => 'TIDEWAYS_XHPROF_FLAGS_CPU',
-      'FLAGS_MEMORY' => 'TIDEWAYS_XHPROF_FLAGS_MEMORY',
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function enable($modifier, $options) {
-    $flags = 0;
-    if (!empty($options['FLAGS_CPU'])) {
-      $flags = $flags | TIDEWAYS_XHPROF_FLAGS_CPU;
-    }
-    if (!empty($options['FLAGS_MEMORY'])) {
-      $flags = $flags | TIDEWAYS_XHPROF_FLAGS_MEMORY;
-    }
-    tideways_xhprof_enable($flags);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function disable() {
-    return tideways_xhprof_disable();
-  }
-
-}
diff --git a/src/Form/StatusConfigurationForm.php b/src/Form/StatusConfigurationForm.php
index a95e1fb..1ea86bb 100644
--- a/src/Form/StatusConfigurationForm.php
+++ b/src/Form/StatusConfigurationForm.php
@@ -72,8 +72,8 @@ class StatusConfigurationForm extends FormBase {
       '#title' => $this->t('Preview mode'),
       '#default_value' => $conf['preview_mode'],
       '#options' => [
-        PerformanceService::PREVIEW_MODE_SILENT => t('Silent'),
-        PerformanceService::PREVIEW_MODE_IFRAME => t('Iframe'),
+        PerformanceService::PREVIEW_MODE_SILENT => $this->t('Silent'),
+        PerformanceService::PREVIEW_MODE_IFRAME => $this->t('Iframe'),
       ],
     ];
     $form['conf']['cleanup'] = [
@@ -115,17 +115,16 @@ class StatusConfigurationForm extends FormBase {
       '#options' => $profiler_extensions,
       '#default_value' => $conf['profiling']['extension'],
     ];
-    $profiler_options = [
-      'FLAGS_CPU' => $this->t('FLAGS_CPU'),
-      'FLAGS_MEMORY' => $this->t('FLAGS_MEMORY'),
-    ];
-    $form['conf']['profiling']['options'] = [
-      '#type' => 'checkboxes',
-      '#title' => $this->t('Profiling options'),
-      '#default_value' => $conf['profiling']['options'],
-      '#options' => $profiler_options,
-      '#description' => $this->t('Support depends on particular extension'),
-    ];
+
+    $form['conf']['profiling']['profilers'] = $this->performanceService->getProfilerOptionsForm();
+    foreach ($form['conf']['profiling']['profilers'] as $key => $value) {
+      $form['conf']['profiling']['profilers'][$key]['#states'] = [
+        'visible' => [
+          ':input[name="conf[profiling][extension]"]' => ['value' => $key],
+        ],
+      ];
+    }
+
     $form['conf']['profiling']['rules'] = [
       '#type' => 'textarea',
       '#title' => $this->t('Rules to match requests to profile'),
diff --git a/src/PerformanceService.php b/src/PerformanceService.php
index ac89561..6cbe38f 100644
--- a/src/PerformanceService.php
+++ b/src/PerformanceService.php
@@ -3,7 +3,7 @@
 namespace Drupal\qtools_profiler;
 
 use Drupal\Component\Datetime\TimeInterface;
-use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
@@ -11,14 +11,10 @@ use Drupal\Core\Site\Settings;
 use Drupal\Core\State\State;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\qtools_common\QToolsCryptHelper;
-use Drupal\sg_api\SessionService;
 use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
-use Drupal\qtools_profiler\Extension\XHProfExtension;
-use Drupal\qtools_profiler\Extension\UprofilerExtension;
-use Drupal\qtools_profiler\Extension\TidewaysExtension;
-use Drupal\qtools_profiler\Extension\TidewaysXhprofExtension;
 use Drupal\Core\Path\PathMatcherInterface;
 use Symfony\Component\HttpKernel\Event\PostResponseEvent;
 
@@ -116,6 +112,20 @@ class PerformanceService {
     ],
   ];
 
+  /**
+   * Profile plugin manager.
+   *
+   * @var \Drupal\qtools_profiler\ProfilerPluginManager
+   */
+  protected $profilerPluginManager;
+
+  /**
+   * Cache backend.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cacheBackend;
+
   // Preview modes.
   const PREVIEW_MODE_SILENT = 0;
   const PREVIEW_MODE_IFRAME = 1;
@@ -133,9 +143,6 @@ class PerformanceService {
   const HOOK_REQUEST_SUMMARY_ALTER = 'qtools_profiler_request_summary';
   const HOOK_REQUEST_SUMMARY_RESPONSE_ALTER = 'qtools_profiler_request_summary_response';
 
-  // Profiler extensions (extensions).
-  const PROFILER_TIDEWAYS_XHPROF = 'tideways_xhprof';
-
   // Cookies.
   const COOKIE_PROFILER = 'qtools_profiler';
   const COOKIE_PROFILER_CLIENT = 'qtools_profiler_client';
@@ -152,7 +159,9 @@ class PerformanceService {
     TimeInterface $time,
     ModuleHandlerInterface $moduleHandler,
     State $state,
-    PathMatcherInterface $pathMatcher
+    PathMatcherInterface $pathMatcher,
+    ProfilerPluginManager $profilerPluginManager,
+    CacheBackendInterface $cacheBackend
   ) {
     $this->currentUser = $currentUser;
     $this->connection = $connection;
@@ -160,6 +169,8 @@ class PerformanceService {
     $this->moduleHandler = $moduleHandler;
     $this->state = $state;
     $this->pathMatcher = $pathMatcher;
+    $this->profilerPluginManager = $profilerPluginManager;
+    $this->cacheBackend = $cacheBackend;
 
     // Read configuration from state and merge with defaults.
     $activeConfiguration = $this->state->get(static::STATE_CONFIGURATION_KEY, []);
@@ -175,10 +186,55 @@ class PerformanceService {
    * Returns list of supported profilers.
    */
   public function getProfilerOptions() {
-    return [
-      '' => $this->t('None'),
-      static::PROFILER_TIDEWAYS_XHPROF => 'TidewaysXHProf',
-    ];
+    $options = ['' => $this->t('None')];
+
+    foreach ($this->profilerPluginManager->getDefinitions() as $plugin) {
+      $options[$plugin['id']] = $plugin['label'];
+    }
+
+    return $options;
+  }
+
+  /**
+   * Returns settings form for profilers.
+   */
+  public function getProfilerOptionsForm() {
+    $form_items = [];
+    foreach ($this->profilerPluginManager->getDefinitions() as $plugin) {
+      $profiler = $this->profilerPluginManager->createInstance($plugin['id']);
+      $form_items[$plugin['id']] = [
+        '#type' => 'fieldset',
+        '#title' => $this->t('@name settings', ['@name' => $plugin['label']]),
+        '#tree' => TRUE,
+      ];
+      $form_items[$plugin['id']] += $profiler->getSettingsForm($this->confGet());
+    }
+
+    return $form_items;
+  }
+
+  /**
+   * Build profile.
+   */
+  public function buildProfilePage(Request $request, $id) {
+    $query = $this->connection->select(static::TABLE_RESPONSE, 'r');
+    $query->fields('r', ['report']);
+
+    $query->condition('r.rid', $id);
+    $extension = $query->execute()->fetchField();
+
+    try {
+      $this->activeExtension = $this->profilerPluginManager->createInstance($extension);
+    }
+    catch (\Exception $e) {
+      // Php extention is not loaded.
+    }
+
+    if (!empty($this->activeExtension)) {
+      return $this->activeExtension->buildProfilePage($request, $id);
+    }
+
+    return [];
   }
 
   /**
@@ -275,10 +331,10 @@ class PerformanceService {
   public function storeRedirectId($id) {
     // We can only store them is we have a client cookie.
     if (!empty($this->cookieClient)) {
-      $cache = \Drupal::cache()->get($this->cookieClient);
+      $cache = $this->cacheBackend->get($this->cookieClient);
       $data = !empty($cache) && !empty($cache->data) ? $cache->data : [];
       $data[] = $id;
-      \Drupal::cache()->set($this->cookieClient, $data, time() + 60);
+      $this->cacheBackend->set($this->cookieClient, $data, time() + 60);
     }
   }
 
@@ -291,11 +347,11 @@ class PerformanceService {
       return [];
     }
 
-    $cache = \Drupal::cache()->get($this->cookieClient);
+    $cache = $this->cacheBackend->get($this->cookieClient);
     $data = !empty($cache) && !empty($cache->data) ? $cache->data : [];
 
     if ($clear) {
-      \Drupal::cache()->delete($this->cookieClient);
+      $this->cacheBackend->delete($this->cookieClient);
     }
     return $data;
   }
@@ -327,7 +383,7 @@ class PerformanceService {
       'memory' => memory_get_peak_usage(),
       'time' => $this->time->getCurrentMicroTime() - $this->time->getRequestMicroTime(),
       'code' => $event->getResponse()->getStatusCode(),
-      'report' => !empty($this->activeExtension) ? 1 : 0,
+      'report' => !empty($this->activeExtension) ? $this->activeExtension->getPluginId() : 0,
     ];
 
     // Save response data.
@@ -364,7 +420,7 @@ class PerformanceService {
       'memory' => memory_get_peak_usage(),
       'time' => $this->time->getCurrentMicroTime() - $this->time->getRequestMicroTime(),
       'code' => $event->getResponse()->getStatusCode(),
-      'report' => !empty($this->activeExtension) ? 1 : 0,
+      'report' => !empty($this->activeExtension) ? $this->activeExtension->getPluginId() : 0,
     ];
 
     // Place tracking data in the response.
@@ -619,15 +675,18 @@ class PerformanceService {
 
     // Choose extension.
     $extension = $conf['profiling']['extension'];
-    if ($extension == static::PROFILER_TIDEWAYS_XHPROF && TidewaysXhprofExtension::isLoaded()) {
-      $this->activeExtension = new TidewaysXhprofExtension();
+
+    try {
+      $this->activeExtension = $this->profilerPluginManager->createInstance($extension);
+    }
+    catch (\Exception $e) {
+      // Php extention is not loaded.
     }
 
     // Start profiling if we have active extension.
     if (!empty($this->activeExtension)) {
-      $modifier = 0;
-      $options = !empty($conf['profiling']['options']) ? array_filter($conf['profiling']['options']) : [];
-      $this->activeExtension->enable($modifier, $options);
+      $options = $conf['profiling']['profilers'][$extension] ?? [];
+      $this->activeExtension->enable($options);
     }
   }
 
@@ -730,10 +789,10 @@ class PerformanceService {
    *   Profiling epoch.
    */
   public function getProfilingEpoch($reset = FALSE) {
-    $epoch = \Drupal::state()->get('qtools_profiler.epoch', NULL);
+    $epoch = $this->state->get('qtools_profiler.epoch', NULL);
     if (empty($epoch) || $reset) {
       $epoch = time();
-      \Drupal::state()->set('qtools_profiler.epoch', $epoch);
+      $this->state->set('qtools_profiler.epoch', $epoch);
     }
 
     return $epoch;
diff --git a/src/Plugin/Profiler/Blackfire.php b/src/Plugin/Profiler/Blackfire.php
new file mode 100644
index 0000000..1cb2fa1
--- /dev/null
+++ b/src/Plugin/Profiler/Blackfire.php
@@ -0,0 +1,179 @@
+<?php
+
+namespace Drupal\qtools_profiler\Plugin\Profiler;
+
+use Blackfire\Client as BlackfireClient;
+use Blackfire\ClientConfiguration;
+use Blackfire\Exception\ApiException;
+use Blackfire\Exception\ConfigNotFoundException;
+use Blackfire\Exception\EnvNotFoundException;
+use Blackfire\Exception\NotAvailableException;
+use Blackfire\Exception\OfflineException;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Link;
+use Drupal\Core\Url;
+use Drupal\qtools_profiler\ProfilerPluginInterface;
+use Drupal\salesforce\Exception;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+/**
+ * Provides Blackfire profiler plugin.
+ *
+ * @Plugin(
+ *   id = "blackfire",
+ *   label = @Translation("Blackfire.io"),
+ *   description = @Translation("Blackfire php profiler.")
+ * )
+ */
+class Blackfire extends PluginBase implements ProfilerPluginInterface {
+
+  /**
+   * Blackfire Profile client.
+   *
+   * @var \Blackfire\Client
+   */
+  protected $blackfire;
+
+  /**
+   * Blackfire probe.
+   *
+   * @var \Blackfire\Probe
+   */
+  protected $probe;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    if (!static::isLoaded()) {
+      throw new \Exception('Php extention blackfire is not installed');
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isLoaded() {
+    return extension_loaded('blackfire');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enable($options) {
+    try {
+      $config = new ClientConfiguration($options['client_id'], $options['client_token']);
+      $this->blackfire = new BlackfireClient($config);
+      $this->probe = $this->blackfire->createProbe();
+    }
+    catch (NotAvailableException $e) {
+      // The Blackfire PHP extension is not installed or not enabled.
+    }
+    catch (OfflineException $e) {
+      // You are offline or the Blackfire servers are not reachable (check your
+      // proxy configuration).
+    }
+    catch (ApiException $e) {
+      // An error occurred when communicating with Blackfire.
+      if ($e->getCode() === 429) {
+        // Too many requests while calling POST
+        // https://blackfire.io/api/v1/signing.
+      }
+    }
+    catch (ConfigNotFoundException $e) {
+      // The Blackfire configuration file cannot be found.
+    }
+    catch (EnvNotFoundException $e) {
+      // The configured environment does not exist.
+    }
+
+    catch (Exception $e) {
+      // Some error.
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function disable() {
+    if ($this->probe) {
+      $profile = $this->blackfire->endProbe($this->probe);
+      // Get the main costs.
+      $cost = $profile->getMainCost();
+      $data = [
+        'graph' => Link::fromTextAndUrl(t('View at Blackfire site'), Url::fromUri($profile->getUrl(), ['external' => TRUE]))->toString(),
+        // Cost methods.
+        // wt.
+        'wall_time' => $cost->getWallTime() / 1000000 . ' sec',
+        // cpu.
+        'cpu_time' => $cost->getCpu(),
+        // io.
+        'io' => $cost->getIo(),
+        // nw.
+        'network' => $cost->getNetwork(),
+        // pmu.
+        'peak_memory' => $cost->getPeakMemoryUsage() / 1024 / 1024 . 'MB',
+        'memory' => $cost->getMemoryUsage() / 1024 / 1024 . 'MB',
+        'isSuccessful' => $profile->isSuccessful(),
+        'isErrored' => $profile->isErrored(),
+        'tests' => $profile->getTests(),
+        'queries' => $profile->getSqls(),
+      ];
+
+      return $data;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildProfilePage(Request $request, $id) {
+    // Build run from data.
+    $reportService = \Drupal::service('qtools_profiler.report');
+    $data = $reportService->getProfileDetails($id);
+    if (empty($data)) {
+      throw new NotFoundHttpException();
+    }
+
+    $rows = [];
+    foreach ($data as $key => $value) {
+      $rows[] = [
+        'data' => [$key, $value],
+      ];
+    }
+
+    $build['header'] = [
+      '#markup' => 'Summary',
+    ];
+    $build['table'] = [
+      '#theme' => 'table',
+      '#rows' => $rows,
+    ];
+
+    return $build;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSettingsForm(array $conf) {
+    // Id 4fd1e668-0af0-4a67-9729-9865573a4bfc.
+    // Token 71990ab3f3d146736acc3e8e68fc082098e1d07234714dd25caece9c29330d3e.
+    $form['client_id'] = [
+      '#type' => 'textfield',
+      '#title' => t('Client id'),
+      '#default_value' => $conf['profiling']['profilers']['blackfire']['client_id'] ?? '',
+      '#description' => t('Blackfire cliet id'),
+    ];
+    $form['client_token'] = [
+      '#type' => 'textfield',
+      '#title' => t('Client token'),
+      '#default_value' => $conf['profiling']['profilers']['blackfire']['client_token'] ?? '',
+      '#description' => t('Blackfire client token'),
+    ];
+    return $form;
+  }
+
+}
diff --git a/src/Plugin/Profiler/TidewaysXhprof.php b/src/Plugin/Profiler/TidewaysXhprof.php
new file mode 100644
index 0000000..f6e606d
--- /dev/null
+++ b/src/Plugin/Profiler/TidewaysXhprof.php
@@ -0,0 +1,233 @@
+<?php
+
+namespace Drupal\qtools_profiler\Plugin\Profiler;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Component\Render\FormattableMarkup;
+use Drupal\Component\Utility\Xss;
+use Drupal\Core\Url;
+use Drupal\qtools_profiler\ProfilerPluginInterface;
+use Drupal\qtools_profiler\XHProfLib\Parser\Parser;
+use Drupal\qtools_profiler\XHProfLib\Report\Report;
+use Drupal\qtools_profiler\XHProfLib\Report\ReportConstants;
+use Drupal\qtools_profiler\XHProfLib\Report\ReportInterface;
+use Drupal\qtools_profiler\XHProfLib\Run;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+
+/**
+ * Provides TidewaysXhprof profiler plugin.
+ *
+ * @Plugin(
+ *   id = "tideways_xhprof",
+ *   label = @Translation("Tideways xhprof"),
+ *   description = @Translation("Tideways xhprof php profiler.")
+ * )
+ */
+class TidewaysXhprof extends PluginBase implements ProfilerPluginInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    if (!static::isLoaded()) {
+      throw new \Exception('Php extention tideways_xhprof extention is not installed');
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isLoaded() {
+    return extension_loaded('tideways_xhprof');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSettingsForm(array $conf) {
+    $profiler_options = [
+      'FLAGS_CPU' => t('FLAGS_CPU'),
+      'FLAGS_MEMORY' => t('FLAGS_MEMORY'),
+    ];
+    $form['options'] = [
+      '#type' => 'checkboxes',
+      '#title' => t('Profiling options'),
+      '#default_value' => $conf['profiling']['profilers']['tideways_xhprof']['options'],
+      '#options' => $profiler_options,
+      '#description' => t('Support depends on particular extension'),
+    ];
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enable($options) {
+    $flags = 0;
+    if (!empty($options['options']['FLAGS_CPU'])) {
+      $flags = $flags | TIDEWAYS_XHPROF_FLAGS_CPU;
+    }
+    if (!empty($options['options']['FLAGS_MEMORY'])) {
+      $flags = $flags | TIDEWAYS_XHPROF_FLAGS_MEMORY;
+    }
+    tideways_xhprof_enable($flags);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function disable() {
+    return tideways_xhprof_disable();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildProfilePage(Request $request, $id) {
+
+    $route_name = $request->attributes->get('_route');
+
+    // Build run from data.
+    $reportService = \Drupal::service('qtools_profiler.report');
+    $data = $reportService->getProfileDetails($id);
+    if (empty($data)) {
+      throw new NotFoundHttpException();
+    }
+
+    // Parse run.
+    $run = new Run($id, 'space', $data);
+
+    // Get filter/sort.
+    $length = $request->get('length', 100);
+    $sort = $request->get('sort', 'excl_wt');
+
+    $parser = new Parser($run, $sort, NULL);
+    $report = new Report($parser);
+    $build['#title'] = t('XHProf view report for %id', ['%id' => $run->getId()]);
+    $descriptions = ReportConstants::getDescriptions();
+
+    $build['summary'] = [
+      'title' => [
+        '#type' => 'inline_template',
+        '#template' => '<h3>Summary</h3>',
+      ],
+      'table' => [
+        '#theme' => 'table',
+        '#header' => [],
+        '#rows' => $this->getSummaryRows($report, $descriptions),
+      ],
+    ];
+
+    $build['length'] = [
+      '#type' => 'inline_template',
+      '#template' => ($length == -1) ? '<h3>Displaying all functions, sorted by <em>{{ sort }}</em>.</h3>' : '<h3>Displaying top {{ length }} functions, sorted by {{ sort }}. [{{ all }}]</h3>',
+      '#context' => [
+        'length' => $length,
+        'all' => \Drupal::service('link_generator')->generate(t('show all'), Url::fromRoute($route_name, [
+          'id' => $run->getId(),
+          'length' => -1,
+        ])),
+        'sort' => Xss::filter($descriptions[$sort], []),
+      ],
+    ];
+
+    $build['table'] = [
+      '#theme' => 'table',
+      '#header' => $this->getRunHeader($report, $descriptions, $run, $route_name),
+      '#rows' => $this->getRunRows($report, $length),
+      '#attributes' => ['class' => ['responsive']],
+      '#attached' => [
+        'library' => [
+          'xhprof/xhprof',
+        ],
+      ],
+    ];
+
+    return $build;
+  }
+
+  /**
+   * Get rows summary from report.
+   */
+  protected function getSummaryRows(ReportInterface $report, $descriptions) {
+    $summaryRows = [];
+    $possibileMetrics = $report->getPossibleMetrics();
+    foreach ($report->getSummary() as $metric => $value) {
+      $key = 'Total ' . Xss::filter($descriptions[$metric], []);
+      $unit = isset($possibileMetrics[$metric]) ? $possibileMetrics[$metric][1] : '';
+
+      $value = new FormattableMarkup('@value @unit', [
+        '@value' => $value,
+        '@unit' => $unit,
+      ]);
+
+      $summaryRows[] = [
+        $key,
+        $value,
+      ];
+    }
+
+    return $summaryRows;
+  }
+
+  /**
+   * Ger run header from report.
+   */
+  protected function getRunHeader(ReportInterface $report, $descriptions, Run $run, $route_name) {
+    $headers = ['fn', 'ct', 'ct_perc'];
+
+    $metrics = $report->getMetrics();
+
+    foreach ($metrics as $metric) {
+      $headers[] = $metric;
+      $headers[] = $metric . '_perc';
+      $headers[] = 'excl_' . $metric;
+      $headers[] = 'excl_' . $metric . '_perc';
+    }
+
+    foreach ($headers as &$header) {
+      $description = strip_tags($descriptions[$header]);
+      $link = \Drupal::service('link_generator')->generate($description, Url::fromRoute($route_name, [
+        'id' => $run->getId(),
+        'length' => -1,
+        'sort' => str_replace('_perc', '', $header),
+      ]));
+      $header = new FormattableMarkup($link, []);
+    }
+
+    return $headers;
+  }
+
+  /**
+   * Get run Rows from report.
+   */
+  protected function getRunRows(ReportInterface $report, $length) {
+    $symbols = $report->getSymbols($length);
+
+    foreach ($symbols as &$symbol) {
+      $symbol[0] = $this->abbrClass($symbol[0]);
+    }
+
+    return $symbols;
+  }
+
+  /**
+   * Theme class.
+   */
+  protected function abbrClass($class) {
+    $parts = explode('\\', $class);
+    $short = array_pop($parts);
+
+    if (strlen($short) >= 40) {
+      $short = substr($short, 0, 30) . " … " . substr($short, -5);
+    }
+
+    return new FormattableMarkup('<abbr title="@class">@short</abbr>', [
+      '@class' => $class,
+      '@short' => $short,
+    ]);
+  }
+
+}
diff --git a/src/ProfilerPluginInterface.php b/src/ProfilerPluginInterface.php
new file mode 100644
index 0000000..0c237e0
--- /dev/null
+++ b/src/ProfilerPluginInterface.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\qtools_profiler;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface ProfilerPluginInterface.
+ *
+ * @package Drupal\qtools_profiler
+ */
+interface ProfilerPluginInterface extends PluginInspectionInterface {
+
+  /**
+   * Returns TRUE if this extension is loaded into the PHP interpreter.
+   *
+   * @return bool
+   *   Flag if extension loaded.
+   */
+  public static function isLoaded();
+
+  /**
+   * Enable the extension.
+   */
+  public function enable($options);
+
+  /**
+   * Disable the extension.
+   */
+  public function disable();
+
+  /**
+   * Output profile report.
+   */
+  public function buildProfilePage(Request $request, $id);
+
+  /**
+   * Retrieve settings form for profiler.
+   */
+  public function getSettingsForm(array $conf);
+
+}
diff --git a/src/ProfilerPluginManager.php b/src/ProfilerPluginManager.php
new file mode 100644
index 0000000..e83e40f
--- /dev/null
+++ b/src/ProfilerPluginManager.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\qtools_profiler;
+
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Provides Profiler plugin manager.
+ */
+class ProfilerPluginManager extends DefaultPluginManager {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct(
+      'Plugin/Profiler',
+      $namespaces,
+      $module_handler,
+      'Drupal\qtools_profiler\ProfilerPluginInterface',
+      'Drupal\Component\Annotation\Plugin',
+      ['Drupal\qtools_profiler\Annotation\Profiler']
+    );
+    $this->alterInfo('qtools_profiler_info');
+    $this->setCacheBackend($cache_backend, 'qtools_profiler_info');
+    $this->factory = new DefaultFactory($this->getDiscovery());
+  }
+
+}
diff --git a/src/ReportService.php b/src/ReportService.php
index 442e68a..6a175be 100644
--- a/src/ReportService.php
+++ b/src/ReportService.php
@@ -106,7 +106,7 @@ class ReportService {
       $query->condition('r.rid', $filters['route'], '=');
     }
     if (!empty($filters['report'])) {
-      $query->condition('response.report', 1, '=');
+      $query->condition('response.report', 0, '<>');
     }
 
     // Add grouping.
@@ -153,7 +153,7 @@ class ReportService {
       $data['uri'] = $this->renderer->renderRoot($link);
 
       $data['timestamp'] = date('Y-m-d H:i:s Z', $data['timestamp']);
-      if ($result->report > 0) {
+      if ($result->report) {
         $link = [
           '#type' => 'link',
           '#title' => $data['timestamp'],
