# sqlite-object-cache/1.6.0/includes/lib/class-sqlite-object-cache-statistics.php

SQLite Object Cache, version 1.6.0. 683 lines.

- Page: https://pluginprobe.com/plugins/sqlite-object-cache/1.6.0/code/includes/lib/class-sqlite-object-cache-statistics.php
- Raw: https://pluginprobe.com/plugins/sqlite-object-cache/1.6.0/raw/includes/lib/class-sqlite-object-cache-statistics.php
- Modified: 2025-10-05T22:24:30+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/sqlite-object-cache/1.6.0/code/includes/lib/class-sqlite-object-cache-statistics.php#L10-L20`.

```php
<?php
/**
 * Statistics class file.
 *
 * @package SQLite Object Cache
 */

if ( ! defined( 'ABSPATH' ) ) {
  exit;
}

/**
 * statistics class.
 */
class SQLite_Object_Cache_Statistics {

  /**
   * Associative array with selected cache items names most frequent first.
   *
   * @var array
   */
  public $selected_names;
  /**
   * Associative array with descriptive statistics.
   *
   * @var array
   */
  public $descriptions;
  /**
   * Show the overrun message.
   * @var bool Overrun detected, show message.
   */
  private $overrun_message = false;
  /**
   * @var string
   */
  private $start_time;
  /**
   * @var string
   */
  private $end_time;
  /**
   * @var array
   */
  private $options;

  /**
   * @var int Maximum number of cache items to include in size toble.
   */
  private $max_scan = 1000000;

  public function __construct( $options ) {
    $this->options = $options;
  }

  /**
   * Initialize and load data.
   *
   * @return void
   * @throws Exception Announce database failure.
   */
  public function init() {
    global $wp_object_cache;

    $first = PHP_INT_MAX;
    $last  = PHP_INT_MIN;

    $selected_names        = array();
    $elapseds              = array();
    $opens                 = array();
    $selects               = array();
    $gets                  = array();
    $get_multiples         = array();
    $get_multiple_keys     = array();
    $inserts               = array();
    $deletes               = array();
    $checkpoints           = array();
    $RAMratios             = array();
    $DISKratios            = array();
    $DISKLookupsPerRequest = array();
    $SavesPerRequest       = array();
    $DBMSqueriesPerRequest = array();
    $RAM                   = array();
    $APCufetchhit          = array();
    $APCufetchmiss         = array();
    $APCustore             = array();


    if ( ! method_exists( $wp_object_cache, 'sqlite_load_statistics' ) ) {
      return;
    }

    if ( method_exists( $wp_object_cache, 'sqlite_remove_expired' ) ) {
      $wp_object_cache->sqlite_remove_expired();
    }

    echo '<!-- apcusalt: ' . $wp_object_cache->apcusalt . '-->' . PHP_EOL;
    foreach ( $wp_object_cache->sqlite_load_statistics() as $data ) {
      $first                   = min( $data->time, $first );
      $last                    = max( $data->time, $last );
      $DISKLookupsPerRequest[] = $data->DISKhits + $data->DISKmisses;
      if ( ( $data->RAMhits + $data->RAMmisses ) > 0 ) {
        $RAMratio    = $data->RAMhits / ( $data->RAMhits + $data->RAMmisses );
        $RAMratios[] = $RAMratio;
      }
      if ( ( $data->APCuhits + $data->APCumisses ) > 0 ) {
        $APCUratio    = $data->APCuhits / ( $data->APCuhits + $data->APCumisses );
        $APCUratios[] = $APCUratio;
      }
      if ( ( $data->DISKhits + $data->DISKmisses ) > 0 ) {
        $DISKratio    = $data->DISKhits / ( $data->DISKhits + $data->DISKmisses );
        $DISKratios[] = $DISKratio;
      }
      $opens []    = $data->open;
      $elapseds [] = $data->elapsed * 1E-9;
      $RAM []      = $data->RAM / ( 1024 * 1024 );
      array_push( $selects, ...$data->selects );
      array_push( $gets, ...$data->gets );
      array_push( $get_multiples, ...$data->get_multiples );
      array_push( $get_multiple_keys, ...$data->get_multiple_keys );
      array_push( $inserts, ...$data->inserts );
      array_push( $APCufetchhit, ...$data->APCufetchhit );
      array_push( $APCufetchmiss, ...$data->APCufetchmiss );
      array_push( $APCustore, ...$data->APCustore );
      $SavesPerRequest [] = count( $data->inserts );
      if ( property_exists( $data, 'DBMSqueries' ) && is_numeric( $data->DBMSqueries ) ) {
        $DBMSqueriesPerRequest [] = $data->DBMSqueries;
      }
      array_push( $deletes, ...$data->deletes );
      array_push( $checkpoints, ...$data->checkpoints );

      $this->truncate_if_too_long( $DISKLookupsPerRequest );
      $this->truncate_if_too_long( $RAMratios );
      $this->truncate_if_too_long( $DISKratios );
      $this->truncate_if_too_long( $APCUratios );
      $this->truncate_if_too_long( $opens );
      $this->truncate_if_too_long( $elapseds );
      $this->truncate_if_too_long( $selects );
      $this->truncate_if_too_long( $gets );
      $this->truncate_if_too_long( $get_multiples );
      $this->truncate_if_too_long( $get_multiple_keys );
      $this->truncate_if_too_long( $inserts );
      $this->truncate_if_too_long( $SavesPerRequest );
      $this->truncate_if_too_long( $DBMSqueriesPerRequest );
      $this->truncate_if_too_long( $deletes );
      $this->truncate_if_too_long( $checkpoints );
      $this->truncate_if_too_long( $RAM );
      $this->truncate_if_too_long( $APCufetchhit );
      $this->truncate_if_too_long( $APCufetchmiss );
      $this->truncate_if_too_long( $APCustore );

      if ( property_exists( $data, 'select_names' ) && is_array( $data->select_names ) ) {
        foreach ( $data->select_names as $name ) {
          if ( ! array_key_exists( $name, $selected_names ) ) {
            $selected_names[ $name ] = 0;
          }
          $selected_names[ $name ] ++;
        }
      }
    }
    $duration = $last - $first;
    if ( $duration > 0 ) {
      $this->scale( $opens );
      $this->scale( $selects );
      $this->scale( $gets );
      $this->scale( $get_multiples );
      $this->scale( $inserts );
      $this->scale( $deletes );
      $this->scale( $APCufetchhit );
      $this->scale( $APCufetchmiss );
      $this->scale( $APCustore );


      arsort( $selected_names );
      $descriptions = array(
        __( 'RAM hit ratio', 'sqlite-object-cache' )           => $this->descriptive_stats( $RAMratios ),
        __( 'APCu hit ratio', 'sqlite-object-cache' )          => $this->descriptive_stats( $APCUratios ),
        __( 'SQLite hit ratio', 'sqlite-object-cache' )        => $this->descriptive_stats( $DISKratios ),
        __( 'SQLite lookups/request', 'sqlite-object-cache' )  => $this->descriptive_stats( $DISKLookupsPerRequest ),
        __( 'SQLite saves/request', 'sqlite-object-cache' )    => $this->descriptive_stats( $SavesPerRequest ),
        __( 'MySQL queries/request', 'sqlite-object-cache' )   => $this->descriptive_stats( $DBMSqueriesPerRequest ),
        __( 'Request durations (sec)', 'sqlite-object-cache' ) => $this->descriptive_stats( $elapseds ),
        __( 'Peak RAM usage (MiB)', 'sqlite-object-cache' )    => $this->descriptive_stats( $RAM ),
        __( 'Initialization times', 'sqlite-object-cache' )    => $this->descriptive_stats( $opens ),
        __( 'Get times', 'sqlite-object-cache' )               => $this->descriptive_stats( $gets ),
        __( 'GetMult times', 'sqlite-object-cache' )           => $this->descriptive_stats( $get_multiples ),
        __( 'GetMult keys', 'sqlite-object-cache' )            => $this->descriptive_stats( $get_multiple_keys ),
        __( 'Save times', 'sqlite-object-cache' )              => $this->descriptive_stats( $inserts ),
        __( 'Delete times', 'sqlite-object-cache' )            => $this->descriptive_stats( $deletes ),
        __( 'Checkpoint times (sec)', 'sqlite-object-cache' )  => $this->descriptive_stats( $checkpoints ),
        __( 'APCu hit times', 'sqlite-object-cache' )          => $this->descriptive_stats( $APCufetchhit ),
        __( 'APCu miss times', 'sqlite-object-cache' )         => $this->descriptive_stats( $APCufetchmiss ),
        __( 'APCu save times', 'sqlite-object-cache' )         => $this->descriptive_stats( $APCustore ),
        __( 'SQLite hit times', 'sqlite-object-cache' )        => $this->descriptive_stats( $selects ),

      );

      $this->descriptions   = $descriptions;
      $this->selected_names = $selected_names;
      $this->start_time     = $this->format_datestamp( $first );
      $this->end_time       = $this->format_datestamp( $last );
    }
  }

  /**
   * Truncate an array to a particular length.
   *
   * @param array $observations The array to truncate in place.
   * @param int $limit Target array length.
   *
   * @return void
   */
  public function truncate_if_too_long( &$observations, $limit = 999999 ) {
    if ( is_array( $observations ) && count( $observations ) > $limit ) {
      $this->overrun_message = true;
      array_splice( $observations, $limit );
    }
  }

  /**
   * Descriptive statistics for an array of numbers.
   *
   * @param mixed $a The array.
   *
   * @return array
   */
  public function descriptive_stats( &$a ) {
    $a = is_array( $a ) ? $a : array();
    sort( $a );
    $min = $this->minimum( $a );
    $max = $this->maximum( $a );

    return array(
      'n'      => count( $a ),
      '[min'   => $min,
      'p1'     => $this->percentile( $a, 0.01 ),
      'p5'     => $this->percentile( $a, 0.05 ),
      //'p33'     => $this->percentile( $a, 0.33 ),
      'median' => $this->percentile( $a, 0.5 ),
      'mean'   => $this->mean( $a ),
      //'p67'    => $this->percentile( $a, 0.67 ),
      'p95'    => $this->percentile( $a, 0.95 ),
      'p99'    => $this->percentile( $a, 0.99 ),
      'max]'   => $max,
      'mad'    => $this->mad( $a ),
      'stdev'  => $this->stdev( $a ),
      'range'  => $max - $min,
    );
  }

  /**
   * The smallest value in an array.
   *
   * @param array $a The array. Must be sorted.
   *
   * @return mixed|null
   */
  public function minimum( array $a ) {

    return count( $a ) > 0 ? $a[0] : null;
  }

  /**
   * The largest value in an array.
   *
   * @param array $a The array. Must be sorted.
   *
   * @return mixed|null
   */
  public function maximum( array $a ) {

    return count( $a ) > 0 ? $a[ count( $a ) - 1 ] : null;
  }

  /** Percentile.
   *
   * @param array $a dataset. Must be sorted.
   * @param number $p percentile as fraction 0-1.
   *
   * @return float
   */
  public function percentile( array $a, $p ) {
    $n = count( $a );
    if ( ! $n ) {
      return null;
    }
    $i = (int) floor( $n * $p );
    if ( $i >= $n ) {
      $i = $n - 1;
    }

    return $a[ $i ];
  }

  /**
   * Arithmetic mean.
   *
   * @param array $a dataset.
   *
   * @return number
   */
  public function mean( array $a ) {
    $n = count( $a );
    if ( ! $n ) {
      return null;
    }
    if ( 1 === $n ) {
      return $a[0];
    }
    $acc = 0;
    foreach ( $a as $v ) {
      $acc += $v;
    }

    return $acc / $n;
  }

  /**
   * Mean absolute deviation.
   *
   * @param array $a dataset.
   *
   * @return float|int|null
   */
  public function mad( array $a ) {
    $n = count( $a );
    if ( ! $n ) {
      return null;
    }
    if ( 1 === $n ) {
      return 0.0;
    }
    $acc = 0;
    foreach ( $a as $v ) {
      $acc += $v;
    }
    $mean = $acc / $n;
    $acc  = 0;
    foreach ( $a as $v ) {
      $acc += abs( $v - $mean );
    }

    return $acc / $n;
  }

  /**
   * Standard deviation.
   *
   * @param array $a dataset.
   *
   * @return float|null
   */
  public function stdev( $a ) {
    $n = count( $a );
    if ( ! $n ) {
      return null;
    }
    if ( 1 === $n ) {
      return 0.0;
    }
    $sum   = 0.0;
    $sumsq = 0.0;
    foreach ( $a as $v ) {
      $sum   += $v;
      $sumsq += ( $v * $v );
    }
    $mean = $sum / $n;

    return sqrt( ( $sumsq / $n ) - ( $mean * $mean ) );
  }

  /**
   * Render the statistics display.
   *
   * @return void
   */
  public function render() {

    echo '<h3>' . esc_html__( 'Cache performance', 'sqlite-object-cache' ) . '</h3>';
    if ( is_array( $this->descriptions ) ) {
      echo '<p>' . esc_html( sprintf(
                             /* translators:  1 start time   2 end time both in localized format */
                               __( 'From %1$s to %2$s.', 'sqlite-object-cache' ),
                               $this->start_time, $this->end_time ) . ' ' . __( 'Times in microseconds, checkpoint and request durations in seconds.', 'sqlite-object-cache' ) ) . '</p>' . PHP_EOL;
      echo '<table class="sql-object-cache-stats descriptive striped">' . PHP_EOL;
      foreach ( $this->descriptions as $stat => $description ) {
        if ( ! is_array( $description ) || ! array_key_exists( 'n', $description ) || $description['n'] <= 0 ) {
          continue;
        }
        echo '<thead><tr>';
        echo '<th scope="col"></th>';
        foreach ( $description as $item => $value ) {
          echo '<th scope="col" class="right">' . esc_html( $item ) . '</th>' . PHP_EOL;
        }
        echo '</tr></thead>' . PHP_EOL;
        break;
      }
      echo '<tbody>' . PHP_EOL;

      foreach ( $this->descriptions as $stat => $description ) {
        if ( ! is_array( $description ) || ! array_key_exists( 'n', $description ) || $description['n'] <= 0 ) {
          continue;
        }
        echo '<tr>';
        echo '<th scope="row">' . esc_html( $stat ) . '</th>';
        $decimals = 0;
        foreach ( $description as $value ) {
          echo '<td>' . esc_html( number_format_i18n( $value ?: 0.0, $decimals ) ) . '</td>';
          $decimals = 2;
        }
        echo '</tr>' . PHP_EOL;
      }
      echo '</tr></tbody>' . PHP_EOL;
      foreach ( $this->descriptions as $stat => $description ) {
        if ( ! is_array( $description ) || ! array_key_exists( 'n', $description ) || $description['n'] <= 0 ) {
          continue;
        }
        echo '<tfoot><tr>';
        echo '<th scope="col"></th>';
        foreach ( $description as $item => $value ) {
          echo '<th scope="col" class="right">' . esc_html( $item ) . '</th>' . PHP_EOL;
        }
        echo '</tr></tfoot>' . PHP_EOL;
        break;
      }
      echo '</table>' . PHP_EOL;
      if ( $this->overrun_message ) {
        echo '<p>';
        esc_html_e( 'Some statistics were not processed. Processing them all uses too much RAM.', 'sqlite-object-cache' );
        echo ' ';
        esc_html_e( 'Try measuring a smaller random sample of requests.', 'sqlite-object-cache' );
        echo '</p>' . PHP_EOL;
        $this->overrun_message = false;
      }
    } else {
      if ( is_array( $this->options ) && array_key_exists( 'capture', $this->options ) && 'on' === $this->options['capture'] ) {
        echo '<p>' . esc_html__( 'No cache performance statistics have been captured.', 'sqlite-object-cache' ) . ' ';
        $message    =
          /* translators: 1: a percentage */
          __( 'The plugin is capturing a random sample of %s%% of requests. It is possible no samples have yet been captured.', 'sqlite-object-cache' );
        $samplerate = is_numeric( $this->options['samplerate'] ) ? $this->options['samplerate'] : 1;
        echo esc_html( sprintf( $message, $samplerate ) ) . '</p>';
      } else {
        echo '<p>' . esc_html__( 'Cache performance measurement is not enabled.', 'sqlite-object-cache' ) . ' ';
        echo esc_html__( 'You may enable it on the Settings tab.', 'sqlite-object-cache' ) . '</p>';
      }
    }

    if ( is_array( $this->selected_names ) && count( $this->selected_names ) > 0 ) {

      $names = $this->selected_names;
      uksort( $names, function ( $a, $b ) {
        /* Descending order of frequency */
        if ( $this->selected_names[ $a ] !== $this->selected_names[ $b ] ) {
          return $this->selected_names[ $a ] > $this->selected_names[ $b ] ? - 1 : 1;
        }
        $as = explode( '|', $a, 2 );
        $bs = explode( '|', $b, 2 );
        /* Ascending order by group name */
        if ( $as[0] !== $bs[0] ) {
          return strnatcmp( $as[0], $bs[0] );
        }
        /* Ascending order by key name, handling numeric keys correctly. */
        if ( is_numeric( $as[1] ) && is_numeric( $bs[1] ) ) {
          if ( (float) $as[1] === (float) $bs[1] ) {
            return 0;
          }

          return ( (float) $as[1] ) < ( (float) $bs[1] ) ? - 1 : 1;
        }

        return strnatcmp( $as[1], $bs[1] );
      } );

      echo '<h3>' . esc_html__( 'Most frequently looked up cache items', 'sqlite-object-cache' ) . '</h3>' . PHP_EOL;

      echo '<table class="sql-object-cache-items">' . PHP_EOL;
      $count_threshold = - 1;
      $first           = true;
      foreach ( $names as $name => $count ) {
        if ( $first ) {
          echo '<thead><tr>';
          echo '<th scope="col">' . esc_html__( "Cache Group", 'sqlite-object-cache' ) . '</th>';
          echo '<th scope="col">' . esc_html__( "Cache Key", 'sqlite-object-cache' ) . '</th>';
          echo '<th scope="col">' . esc_html__( "Count", 'sqlite-object-cache' ) . '</th>';
          echo '</tr></thead><tbody>' . PHP_EOL;
          $count_threshold = (int) ( $count * 0.7 );
          $first           = false;
        }
        if ( $count < $count_threshold ) {
          break;
        }
        $splits = explode( '|', $name, 2 );
        echo '<tr>';
        echo '<td>' . esc_html( $splits[0] ) . '</td>';
        echo '<td>' . esc_html( $splits[1] ) . '</td>';
        echo '<td>' . esc_html( $count ) . '</td>';
        echo '</tr>' . PHP_EOL;
      }
    }
    echo '</tbody></table>';
  }

  /**
   * Render the usage display.
   *
   * @return void
   */
  public function render_usage() {

    global $wp_object_cache;
    if ( ! method_exists( $wp_object_cache, 'sqlite_load_usages' ) ) {
      return;
    }

    echo '<h3>' . esc_html__( 'Cache usage', 'sqlite-object-cache' ) . '</h3>';
    $grouplength = array();
    $groupcount  = array();
    $length      = 0;
    $count       = 0;
    $earliest    = PHP_INT_MAX;
    $latest      = PHP_INT_MIN;

    try {

      foreach ( $wp_object_cache->sqlite_load_usages( true ) as $item ) {
        $length += $item->length;
        $count ++;
        $ts       = $item->expires;
        $earliest = min( $earliest, $ts );
        $latest   = max( $latest, $ts );
        $splits   = explode( '|', $item->name, 2 );
        $group    = $splits[0];
        $group    = preg_replace( '/^([^_]+)_.+_(relationships)$/', '\1-*-\2', $group );
        $group    = preg_replace( '/_[ 0-9._]+$/', '_*', $group );
        if ( ! array_key_exists( $group, $grouplength ) ) {
          $grouplength[ $group ] = 0;
          $groupcount[ $group ]  = 0;
        }
        $grouplength[ $group ] += $item->length;
        $groupcount[ $group ] ++;
        if ( $count >= $this->max_scan ) {
          echo '<p>' . esc_html(
              sprintf(
              /* translators: 1 a localized number of cache items. */
                __( 'Only showing sizes for the first %1$s cache items.', 'sqlite-object-cache' ),
                number_format_i18n( $this->max_scan, 0 ) ) ) . '</p>';
          break;
        }
      }
    } catch ( Exception $ex ) {
      echo '<p>' . esc_html__( 'Cannot load some or all cache items.', 'sqlite-object-cache' ) . '</p>';
    }

    if ( $count > 0 ) {
      $groups = array_keys( $grouplength );
      sort( $groups );

      echo '<p>' . esc_html( sprintf(
                             /* translators:  1 start time   2 end time both in localized format */
                               __( 'Expirations from %1$s to %2$s.', 'sqlite-object-cache' ),
                               $this->format_datestamp( $earliest ), $this->format_datestamp( $latest ) ) . ' ' . __( 'Sizes in MiB.', 'sqlite-object-cache' ) ) . '</p>' . PHP_EOL;

      echo '<table class="sql-object-cache-stats striped">' . PHP_EOL;
      /* table headers */
      echo '<thead><tr>';
      echo '<th scope="col" class="right">' . esc_html__( 'Cache Group', 'sqlite-object-cache' ) . '</th>';
      echo '<th scope="col" class="right">' . esc_html__( 'Items', 'sqlite-object-cache' ) . '</th>';
      echo '<th scope="col" class="right">' . esc_html__( 'Size', 'sqlite-object-cache' ) . '</th>';
      echo '</tr></thead><tbody>' . PHP_EOL;

      if ( method_exists( $wp_object_cache, 'sqlite_sizes' ) ) {
        $sizes     = $wp_object_cache->sqlite_sizes();
        $pagesize  = $sizes['page_size'];
        $filesize  = $sizes['total_pages'];
        $freesize  = $sizes['free_pages'];
        $usedsize  = $filesize - $freesize;
        $statssize = $sizes['stats_size'];
        $mmapsize  = $sizes['mmap_size'];

        $has_apcu = defined( 'WP_SQLITE_OBJECT_CACHE_APCU' ) && WP_SQLITE_OBJECT_CACHE_APCU
                    && function_exists( 'apcu_enabled' ) && apcu_enabled();

        if ( $has_apcu ) {
          $stat         = apcu_cache_info( true );
          $apcu_entries = $stat['num_entries'];
          $apcu_mem     = $stat['mem_size'] / ( 1024 * 1024 );
          /* filesize row */
          echo '<tr>';
          echo '<th scope="row" class="right">' . esc_html__( 'APCu RAM Usage', 'sqlite-object-cache' ) . '</th>';
          echo '<td class="right">' . esc_html( number_format_i18n( $apcu_entries ) ) . '</td>';
          echo '<td class="right">' . esc_html( number_format_i18n( $apcu_mem, 3 ) ) . '</td>';
          echo '</tr>' . PHP_EOL;
        }

        /* filesize row */
        if ( $usedsize ) {
          echo '<tr>';
          echo '<th scope="row" class="right">' . esc_html__( 'SQLite Disk Pages Used', 'sqlite-object-cache' ) . '</th>';
          echo '<td class="right">' . esc_html( number_format_i18n( $usedsize ) ) . '</td>';
          $sizemib = ( $usedsize * $pagesize ) / ( 1024.0 * 1024.0 );
          echo '<td class="right">' . esc_html( number_format_i18n( $sizemib, 3 ) ) . '</td>';
          echo '</tr>' . PHP_EOL;
        }
        /* freesize row */
        if ( $freesize ) {
          echo '<tr>';
          echo '<th scope="row" class="right">' . esc_html__( 'SQLite Disk Pages Free', 'sqlite-object-cache' ) . '</th>';
          echo '<td class="right">' . esc_html( number_format_i18n( $freesize ) ) . '</td>';
          $sizemib = ( $freesize * $pagesize ) / ( 1024 * 1024 );
          echo '<td class="right">' . esc_html( number_format_i18n( $sizemib, 3 ) ) . '</td>';
          echo '</tr>' . PHP_EOL;
        }
        /* memory-mapped row */
        if ( $mmapsize ) {
          echo '<tr>';
          echo '<th scope="row" class="right">' . esc_html__( 'SQLite Memory mapped', 'sqlite-object-cache' ) . '</th>';
          echo '<td class="right"></td>';
          $sizemib = $mmapsize / ( 1024 * 1024 );
          echo '<td class="right">' . esc_html( number_format_i18n( $sizemib, 3 ) ) . '</td>';
          echo '</tr>' . PHP_EOL;
        }
        /* statssize row */
        if ( $statssize ) {
          $statsitems = $sizes['stats_items'];
          echo '<tr>';
          echo '<th scope="row" class="right">' . esc_html__( 'Statistics', 'sqlite-object-cache' ) . '</th>';
          echo '<td class="right">' . esc_html( number_format_i18n( $statsitems ) ) . '</td>';
          $sizemib = $statssize / ( 1024 * 1024 );
          echo '<td class="right">' . esc_html( number_format_i18n( $sizemib, 3 ) ) . '</td>';
          echo '</tr>' . PHP_EOL;
        }
      }

      /* totals row */
      echo '<tr>';
      echo '<th scope="row" class="right">' . esc_html__( 'All Groups', 'sqlite-object-cache' ) . '</th>';
      echo '<td class="right total">' . esc_html( number_format_i18n( $count, 0 ) ) . '</td>';
      $sizemib = $length / ( 1024 * 1024 );
      echo '<td class="right total">' . esc_html( number_format_i18n( $sizemib, 3 ) ) . '</td>';
      echo '</tr>' . PHP_EOL;
      foreach ( $groups as $group ) {
        /* detail row */
        echo '<tr>';
        echo '<td class="right">' . esc_html( $group ) . '</td>';
        echo '<td class="right">' . esc_html( number_format_i18n( $groupcount[ $group ], 0 ) ) . '</td>';
        $sizemib = $grouplength[ $group ] / ( 1024 * 1024 );
        echo '<td class="right">' . esc_html( number_format_i18n( $sizemib, 3 ) ) . '</td>';
        echo '</tr>' . PHP_EOL;
      }

      echo '</tbody></table>' . PHP_EOL;
    } else {
      echo '<p>' . esc_html__( 'No cache items found.', 'sqlite-object-cache' ) . '</p>';
    }
  }

  /**
   * Format a UNIX timestamp using WP settings.
   *
   * @param $stamp
   *
   * @return false|string
   */
  private
  function format_datestamp(
    $stamp
  ) {
    $date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );

    return wp_date( $date_format, (int) $stamp );
  }

  private function scale( array &$observations, $scale = 0.001 ) {
    if ( is_array( $observations ) ) {
      foreach ( $observations as $key => $val ) {
        $observations[ $key ] = $val * $scale;

      }
    }
  }
}

```
