- <?php
- /*
- * Lokorin.com
- * Copyright 2004-2006
- * Licensed under the GNU LGPL. See COPYING for full terms.
- */
- /**
- * Describes a library that handles everything that has to do with the
- * performance monitoring of the site.
- * @author Andreas Launila
- * @version $Revision: 1.3 $
- * @package com.lokorin.lokorin.lib
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
-
- /**#@+
- * Performance type specific identifiers. The constants decide what performance
- * time that should be looked at.
- * @access public
- * @var integer
- */
- define("PERFORMANCE_DB", 1);
- define("PERFORMANCE_PAGE", 2);
- define("PERFORMANCE_PAGE_WITHOUT_DB", 3);
- define("PERFORMANCE_PER_QUERY", 4);
- define("PERFORMANCE_QUERIES", 5);
- define("PERFORMANCE_SIZE", 6);
- define("PERFORMANCE_HITS", 7);
- /**#@-*/ * Gets a top list of the performance of the specified type.
- * @param integer $selectType A performance constant describing the type of
- * performance that should be looked at.
- * @param boolean $average Whether or not the average performance should be
- * used. If true then the average performance is looked at, otherwise the
- * peak performance is looked at.
- * @param boolean $descending Whether or not the slowest performance should be
- * considered greatest. If true then the slowest performance will be shown
- * first in the list, otherwise the fastest performance will be shown
- * first.
- * @param integer $count The maximum number of entries that should be displayed
- * in the top lost. E.g. 10 means that a maximum number of 10 entries will
- * be shown. Fewer entries will be shown if there are not at least 10
- * entries to show.
- * @param integer $minLoggedData The minimum amount of times that data about
- * the returned urls have to have been requested to be included in the
- * result.
- * @return array An array with the requested uri as key and the corresponding
- * measured value in microseconds as array value. The array is sorted
- * descendingly is $slowest equals true, otherwise it's sorted
- * ascendingly.
- * @throws IllegalArgumentException If the provided select type constant is
- * not valid.
- * @access public
- */
- function getTopList($selectType, $average = true, $descending = true,
- $count = 10, $minLoggedData = 30) {
- global $db;
-
- if($descending) {
- $order = "DESC";
- } else {
- $order = "ASC";
- }
-
- $result = $db->query("SELECT `requested_uri` AS uri, round(".
- getSelectField($selectType, $average, $descending).") AS value ".
- "FROM ".TABLE_PERFORMANCE." ".
- "WHERE ".
- "(SELECT COUNT(*) FROM ".TABLE_PERFORMANCE." ".
- "WHERE `requested_uri`=uri) >= ".$db->escape($minLoggedData)." ".
- "GROUP BY `requested_uri` ".
- "ORDER BY value ".$order." LIMIT ".$count);
- $topList = array();
- while(list($uri, $time) = mysql_fetch_row($result)) {
- $topList[$uri] = $time;
- }
- return $topList;
- }
-
- /**
- * Gets the select parameter that should be used when selecting the specified
- * select type from the performance database.
- * @param integer $selectType A performance constant describing the type of
- * performance that should be looked at.
- * @param boolean $average Whether or not the average performance should be
- * used. If true then the average performance is looked at, otherwise the
- * peak performance is looked at.
- * @param boolean $descending Whether or not the slowest performance should be
- * considered greatest. If true then the slowest performance will be shown
- * first in the list, otherwise the fastest performance will be shown
- * first.
- * @return string A string that can be entered after SELECT in a query.
- * @throws IllegalArgumentException If the provided select type constant is
- * not valid.
- * @access private
- */
- function getSelectField($selectType, $average, $descending) {
- if($average) {
- $function = "round(avg(%s))";
- } else if($descending) {
- $function = "max(%s)";
- } else {
- $function = "min(%s)";
- }
-
- return getFieldExpression($selectType, $function);
- }
-
- /**
- * Gets the expression of the field that is connected to the specified select
- * type constant. The function can also wrap the expression in an optional
- * printf pattern if possible.
- * @param integer $select Type A performance constant describing the type of
- * performance that should be looked at.
- * @param string $function The printf pattern that the expression should be
- * wrapped in, if allowed by the expression. The first instance of %s will
- * be replaced by the field expression if possible, otherwise the
- * expression will be returned without being sent through the pattern.
- * @return string A field expression that counts as a valid SQL field.
- * @throws IllegalArgumentException If the provided select type constant is
- * not valid.
- * @access private
- */
- function getFieldExpression($selectType, $function = "%s") {
- switch($selectType) {
- case PERFORMANCE_DB: return sprintf($function, "`db_microseconds`");
- case PERFORMANCE_PAGE: return sprintf($function, "`elapsed_microseconds`");
- case PERFORMANCE_PAGE_WITHOUT_DB: return sprintf($function, "`elapsed_microseconds`-`db_microseconds`");
- case PERFORMANCE_PER_QUERY: return sprintf($function, "`db_microseconds`/`db_queries`");
- case PERFORMANCE_QUERIES: return sprintf($function, "`db_queries`");
- case PERFORMANCE_SIZE: return sprintf($function, "`page_size`");
- case PERFORMANCE_HITS: return "COUNT(*)";
- default:
- throw new IllegalArgumentException("Select type (".$selectType.
- ") not recognised.");
- }
- }
-
- /**
- * formats a unix timestamp into a date representation.
- * @param integer $time The unix timestamp that should be formatted.
- * @return string The date that corresponds to the given timestamp.
- * @access public
- */
- function formatTimestampToDate($time) {
- return date('d M y', $time);
- }
-
- /**
- * Formats microseconds by rewriting them as seconds.
- * @param integer $microseconds The value in microseconds that should be
- * formatted.
- * @return string The formatted value in seconds.
- * @access public
- */
- function formatMicroseconds($microseconds) {
- return round($microseconds/pow(10, 6), 1);
- }
-
- /**
- * Describes a collection of all performance data related to a specified URI.
- * @author Andreas Launila
- * @package com.lokorin.lokorin.lib
- */
- class PerformanceData {
- /**
- * The URI which the data is linked to.
- * @var string
- */
- private $uri;
- /**
- * Contains the basic statistical data, data which summarises the
- * performance. The key is the title of the data, the value is an array
- * where the key is the value's name (e.g. "min") and the value is the
- * corresponding value (e.g. "5 queries").
- * @var array
- */
- private $basicData;
- /**
- * An array containing all performance types. Type constant as array key,
- * the value is another array in which the first value is the corresponding
- * title and the second value is the unit.
- */
- private $types;
-
- /**
- * Constructor for PerformanceData.
- * @param string $uri The URI which the performance data should represent.
- * @throws IllegalArgumentException If no data was found for the specified
- * URI.
- */
- public function __construct($uri) {
- $this->uri = $uri;
- $this->basicData = array();
- $this->types = array(
- PERFORMANCE_PAGE => array("Page (with DB)", "ms"),
- PERFORMANCE_PAGE_WITHOUT_DB => array("Page (without DB)", "ms"),
- PERFORMANCE_DB => array("Database (total)", "ms"),
- PERFORMANCE_PER_QUERY => array("Database (per query)", "ms"),
- PERFORMANCE_QUERIES => array("Performed queries", "queries"),
- PERFORMANCE_SIZE => array("Page size", "bytes")
- );
-
- //Build up the fields that should be selected.
- $selectFields = "";
- foreach($this->types as $type => $titles) {
- if($selectFields != "") {
- $selectFields .= ", ";
- }
- $selectFields .= $this->getAllSelectFields($type);
- }
-
- //Query the database.
- global $db;
- $row = mysql_fetch_row($db->query("SELECT COUNT(*), ".$selectFields." ".
- "FROM ".TABLE_PERFORMANCE." ".
- "WHERE `requested_uri`=".$db->escape($this->uri)));
-
- //Record the result.
- $this->basicData["Hits"] = array("Total" => $row[0]);
- if($row[0] == 0) {
- //No data has been recorded.
- throw new IllegalArgumentException("No data was found for the URI (".
- $this->uri.")");
- }
- unset($row[0]);
- $i = 1;
- foreach($this->types as $type => $titles) {
- $pattern = "%s ".$titles[1];
- $this->basicData[$titles[0]] = array(
- "Minimum" => sprintf($pattern, $row[$i + 0]),
- "Average" => sprintf($pattern, $row[$i + 1]),
- "Maximum" => sprintf($pattern, $row[$i + 2])
- );
- $i += 3;
- }
- }
-
- /**
- * Gets the select fields for the min, average and max values (in that
- * order) for the specified select type.
- * @param integer $selectType A performance constant describing the type of
- * performance that should be looked at.
- * @return string A string that can be entered after SELECT in a query.
- */
- private function getAllSelectFields($selectType) {
- return getSelectField($selectType, false, false).", ".
- getSelectField($selectType, true, true).", ".
- getSelectField($selectType, false, true);
- }
-
- /**
- * Gets the most basic statistical data, data which summarises the
- * performance.
- * @return array The key is the title of the data, the value is an array
- * where the key is the value's name (e.g. "min") and the value is the
- * corresponding value (e.g. "5 queries").
- */
- public function getBasicData() {
- return $this->basicData;
- }
-
- /**
- * Gets the URI that the performance data is linked to.
- * @return string A uniform resource identifier.
- */
- public function getUri() {
- return $this->uri;
- }
-
- /**
- * Gets a graph that displays all the recorded statistics as a function of
- * time. E.g. all sizes known for the page are displayed as a function of
- * time. All functions are displayed in the same graph.
- * @return resource An image resource.
- */
- public function getGraph() {
- global $db;
- doInclude("lib_graphs");
-
- $graph = new Graph();
- //Define the palette.
- $graph->addColor("lgreen", 238, 0, 204);
- $graph->addColor("orange", 204, 102, 0);
- $graph->addColor("dgreen", 48, 116, 84);
-
- //The types that should be displayed with colors as values.
- $typeColors = array(
- PERFORMANCE_PAGE => "lgreen",
- PERFORMANCE_PAGE_WITHOUT_DB => "orange",
- PERFORMANCE_DB => "dgreen"
- );
-
- //Add all the functions.
- $maxValue = 0;
- foreach($this->types as $type => $titles) {
- if(!in_array($type, array_keys($typeColors))) {
- continue;
- }
- $function = $this->getFunction($type);
- if(max($function) > $maxValue) {
- $maxValue = max($function);
- }
- $graph->addFunction($titles[0], $function, $typeColors[$type]);
- }
-
- $paramMarkers = array();
- $functionMarkers = array();
-
- //Construct the parameter markers.
- $idFields = array("requested_uri" => $this->uri);
- $first = $db->querySelectFirst(TABLE_PERFORMANCE, "started",
- $db->buildSqlSelector($idFields)."ORDER BY started DESC LIMIT 1");
- $firstYear = date('Y', $first);
- $lastYear = date('Y', time());
- for($year = $firstYear; $year <= $lastYear; $year++) {
- for($month = 1; $month <= 12; $month += 2) {
- $paramMarkers[] = mktime(0, 0, 0, $month, 1, $year);
- }
- }
-
- //Construct the value markers.
- for($i = 0; $i<$maxValue; $i += 100000) {
- $functionMarkers[] = $i;
- }
-
- return $graph->getGraph("white", "black", $paramMarkers,
- $functionMarkers, "formatTimestampToDate", "formatMicroseconds");
- }
-
- /**
- * Gets the function for a specific select type.
- * @param integer $selectType The type of performance data that the
- * function should represent.
- * @return array An array of measurments. The key is the timestamp when the
- * value was measured, the value is the measured value.
- */
- private function getFunction($selectType) {
- global $db;
-
- $result = $db->query("SELECT DISTINCT round(`started`/(3600*24)) AS time, ".
- "round(avg(".getFieldExpression($selectType).")) AS value ".
- "FROM ".TABLE_PERFORMANCE." ".
- "WHERE requested_uri=".$db->escape($this->uri)." ".
- "GROUP BY time ".
- "ORDER BY time ASC");
- $values = array();
- while(list($time, $value) = mysql_fetch_row($result)) {
- $values[$time] = $value;
- }
- return $values;
- }
- }
-
- ?>