function RenderVideo(&$tests) { global $width, $height, $maxAspectRatio, $videoExtendTime, $biggestThumbnail, $fps, $labelHeight, $timeHeight, $rowPadding, $speed, $fractionTime; // adjust the label sizes if we have a LOT of tests $scale = 1; $count = count($tests); if ($count > 49) { $scale = 0; } elseif ($count > 36) { $scale = 0.5; } elseif ($count > 25) { $scale = 0.6; } elseif ($count > 16) { $scale = 0.7; } elseif ($count > 9) { $scale = 0.8; } // Figure out the end time of the video and // make sure all of the tests are restored. $videoEnd = 0; $all_http = true; foreach ($tests as &$test) { if (isset($test['label']) && strlen($test['label']) && substr($test['label'], 0, 7) !== 'http://') { $all_http = false; } if (isset($test['speed']) && $test['speed'] > 0 && $test['speed'] < 10) { $speed = $test['speed']; } if (isset($test['bare']) && $test['bare']) { $scale = 0; } if (isset($test['id'])) { RestoreTest($test['id']); } if (isset($test['end']) && is_numeric($test['end']) && $test['end'] > $videoEnd) { $videoEnd = $test['end']; } if (isset($test['path']) && isset($test['run']) && isset($test['cached'])) { $progress = GetVisualProgress("./{$test['path']}", $test['run'], $test['cached']); if (isset($progress) && is_array($progress) && isset($progress['frames'])) { $test['frames'] = $progress['frames']; if (count($test['frames'])) { $frame = current($test['frames']); $dim = getimagesize("./{$frame['path']}"); $size = max($dim[0], $dim[1]); if ($size > $biggestThumbnail) { $biggestThumbnail = $size; } $test['aspect'] = $dim[0] / $dim[1]; if ($test['aspect'] > $maxAspectRatio) { $maxAspectRatio = $test['aspect']; } if (stripos($frame['file'], 'ms_') !== false) { $fps = 60; //$fractionTime = 100; } } } } } if ($scale < 1) { $labelHeight = ceil($labelHeight * $scale); $timeHeight = ceil($timeHeight * $scale); $rowPadding = ceil($rowPadding * $scale); } // no need for 60fps video if we are running in slow motion if ($speed < 0.5 && $fps == 60) { $fps = 30; } // Keep the time extension constant $videoExtendTime = $videoExtendTime * $speed; if ($all_http) { foreach ($tests as &$test) { if (isset($test['label']) && strlen($test['label']) && substr($test['label'], 0, 7) === 'http://') { $test['label'] = substr($test['label'], 7); } } } if ($videoEnd > 0) { $videoEnd += $videoExtendTime; $frameCount = ceil($videoEnd * $fps / 1000 / $speed); CalculateVideoDimensions($tests); $im = imagecreatetruecolor($width, $height); if ($im !== false) { RenderFrames($tests, $frameCount, $im); imagedestroy($im); } } }
if ($test['test']['batch']) { $tests = null; if (gz_is_file("{$testPath}/tests.json")) { $legacyData = json_decode(gz_file_get_contents("{$testPath}/tests.json"), true); $tests = array(); $tests['variations'] = array(); $tests['urls'] = array(); foreach ($legacyData as &$legacyTest) { $tests['urls'][] = array('u' => $legacyTest['url'], 'id' => $legacyTest['id']); } } elseif (gz_is_file("{$testPath}/bulk.json")) { $tests = json_decode(gz_file_get_contents("{$testPath}/bulk.json"), true); } if (isset($tests)) { foreach ($tests['urls'] as &$testData) { RestoreTest($testData['id']); $path = './' . GetTestPath($testData['id']); if (!isset($hasCSV)) { $files = glob("{$path}/*{$fileType}"); if ($files && is_array($files) && count($files)) { $hasCSV = true; } else { $hasCSV = false; } } $label = $testData['l']; if (!strlen($label)) { $label = htmlspecialchars(ShortenUrl($testData['u'])); } if ($hasCSV) { if (!$sentHeader) {
} } // If there is exactly one test, populate variables so header code will pick it up. if (count($testsId) == 1) { $_GET['test'] = $testsId[0]; $_REQUEST['test'] = $testsId[0]; } include 'common.inc'; require_once 'lib/PHPStats/PHPStats.phar'; require_once 'page_data.inc'; require_once 'graph_page_data.inc'; require_once 'stat.inc'; $page_keywords = array('Graph Page Data', 'Webpagetest', 'Website Speed Test', 'Page Speed', 'comparison'); $page_description = "Graph Page Data Comparison."; foreach ($testsId as $id) { RestoreTest($id); } # We intend to change to "?tests" but also allow "?test" so as to not break existing links. # TODO(mgl): Support -l:<label> after the test IDs as in video/compare.php $chartData = array(); // @var Chart[] All charts to be graphed $testsPath = array_map("GetTestPath", $testsId); $testsInfo = array_map("GetTestInfo", $testsPath); $pagesData = array_map("loadAllPageData", $testsPath); // Whether to show first and/or repeat views. // Default to showing first view if no views are indicated in the URL. $views = array(); $rv = isset($_REQUEST['rv']) ? $_REQUEST['rv'] : 0; $fv = isset($_REQUEST['fv']) ? $_REQUEST['fv'] : 1 - $rv; if ($fv) { $views[] = 0;
if (isset($_REQUEST['searches']) && strlen($_REQUEST['searches'])) { $searches = explode(',', $_REQUEST['searches']); } $maxReqs = 0; if (isset($_REQUEST['maxReqs']) && strlen($_REQUEST['maxReqs'])) { $maxReqs = $_REQUEST['maxReqs']; } header("Content-disposition: attachment; filename={$id}_headersMatch.csv"); header("Content-type: text/csv"); // list of metrics that will be produced // for each of these, the median, average and std dev. will be calculated echo "\"Test ID\",\"Found\"\r\n"; // and now the actual data foreach ($testIds as &$testId) { $cached = 0; RestoreTest($testId); GetTestStatus($testId); $testPath = './' . GetTestPath($testId); $pageData = loadAllPageData($testPath); $medianRun = GetMedianRun($pageData, $cached); $secured = 0; $haveLocations = 1; $requests = getRequests($testId, $testPath, $medianRun, $cached, $secure, $haveLocations, false, true); // Flag indicating if we matched $matched = array(); $nSearches = count($searches); $nRecords = count($requests); if ($nRecords > $maxReqs && $maxReqs != 0) { $nRecords = $maxReqs; } for ($rec = 0; $rec < $nRecords; $rec++) {
if (count($p) >= 2) { if ($p[0] == 'r') { $test['run'] = (int) $p[1]; } if ($p[0] == 'l') { $test['label'] = $p[1]; } if ($p[0] == 'c') { $test['cached'] = (int) $p[1]; } if ($p[0] == 'e') { $test['end'] = trim($p[1]); } } } RestoreTest($test['id']); $test['path'] = GetTestPath($test['id']); $test['pageData'] = loadAllPageData($test['path']); $info = GetTestInfo($test['id']); if ($info) { if (array_key_exists('discard', $info) && $info['discard'] >= 1 && array_key_exists('priority', $info) && $info['priority'] >= 1) { $defaultInterval = 100; } $test['url'] = $info['url']; } $testInfo = parse_ini_file("./{$test['path']}/testinfo.ini", true); if ($testInfo !== FALSE) { if (array_key_exists('test', $testInfo) && array_key_exists('location', $testInfo['test'])) { $test['location'] = $testInfo['test']['location']; } if (isset($testInfo['test']) && isset($testInfo['test']['completeTime'])) {
// Compare the end-state frames across multiple tests and report how similar they are. // Only JSON responses are supported. chdir('..'); include 'common_lib.inc'; require_once 'video/visualProgress.inc.php'; $result = array('statusCode' => 200, 'data' => array()); if (isset($_REQUEST['tests'])) { $tests = explode(',', $_REQUEST['tests']); $baseline = null; foreach ($tests as $params) { if (preg_match('/(?P<id>[0-9a-zA-Z_]+)-r\\:(?P<run>[0-9]+)/', $params, $matches)) { $test = $matches['id']; $run = $matches['run']; if (ValidateTestId($test)) { RestoreTest($test); $result['data'][$test] = -1; $histogram = GetLastFrameHistogram($test, $run); if (isset($histogram)) { if (isset($baseline)) { $result['data'][$test] = CompareHistograms($histogram, $baseline); } else { $result['data'][$test] = 100; $baseline = $histogram; } } } } } } json_response($result);
/** * Parse the list of tests and identify the screen shots to compare * */ function ParseTests() { $tests = array(); global $median_metric; if (isset($_REQUEST['tests'])) { $groups = explode(',', $_REQUEST['tests']); foreach ($groups as $group) { $parts = explode('-', $group); if (count($parts) >= 1 && ValidateTestId($parts[0])) { $test = array(); $test['id'] = $parts[0]; $test['cached'] = 0; for ($i = 1; $i < count($parts); $i++) { $p = explode(':', $parts[$i]); if (count($p) >= 2) { if ($p[0] == 'r') { $test['run'] = (int) $p[1]; } if ($p[0] == 'l') { $test['label'] = $p[1]; } if ($p[0] == 'c') { $test['cached'] = (int) $p[1]; } } } RestoreTest($test['id']); $test['path'] = GetTestPath($test['id']); if (!isset($test['run'])) { $pageData = loadAllPageData($test['path']); $test['run'] = GetMedianRun($pageData, $test['cached'], $median_metric); } if (!isset($test['label'])) { $label = getLabel($test['id'], $user); if (!empty($label)) { $test['label'] = $new_label; } else { $info = GetTestInfo($test['id']); if ($info && isset($info['label']) && strlen($info['label'])) { $test['label'] = trim($info['label']); } } } if (!isset($test['label'])) { $test['label'] = $test['id']; } $cachedText = ''; if ($test['cached']) { $cachedText = '_Cached'; } $fileBase = "{$test['path']}/{$test['run']}{$cachedText}_screen"; if (is_file("{$fileBase}.png")) { $test['image'] = "{$fileBase}.png"; } elseif (is_file("{$fileBase}.jpg")) { $test['image'] = "{$fileBase}.jpg"; } if (isset($test['image'])) { $size = getimagesize($test['image']); if ($size && count($size) >= 2 && $size[0] > 0 && $size[1] > 0) { $test['width'] = $size[0]; $test['height'] = $size[1]; $tests[] = $test; } } } } } if (!count($tests)) { unset($tests); } return $tests; }
function DisplayData() { global $tests; $metrics = array('loadTime' => 'Page Load Time', 'SpeedIndex' => '<a href="https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index">Speed Index</a> (lower is better)'); echo '<br><table class="batchResults" border="1" cellpadding="15" cellspacing="0"> <tr> <th class="empty"></th>'; foreach ($tests as &$test) { RestoreTest($test['id']); $label = ''; if (array_key_exists('label', $test)) { $label = htmlspecialchars($test['label']); } echo "<th>{$label}</th>"; } echo "</tr>\n"; foreach ($metrics as $metric => $label) { echo "<tr><td class=\"right\"><b>{$label}</b></td>"; $base = null; $index = 0; foreach ($tests as &$test) { $display = ''; $value = null; if (array_key_exists('cached', $test) && array_key_exists('run', $test) && array_key_exists('pageData', $test) && is_array($test['pageData']) && array_key_exists($test['run'], $test['pageData']) && is_array($test['pageData'][$test['run']]) && array_key_exists($test['cached'], $test['pageData'][$test['run']]) && is_array($test['pageData'][$test['run']][$test['cached']]) && array_key_exists($metric, $test['pageData'][$test['run']][$test['cached']])) { $value = htmlspecialchars($test['pageData'][$test['run']][$test['cached']][$metric]); if ($metric == 'loadTime') { $display = number_format($value / 1000, 3) . 's'; } else { $display = number_format($value, 0); } } if (!$index) { $base = $value; } elseif (isset($base) && isset($value)) { $delta = $value - $base; $deltaPct = number_format(abs($delta / $base * 100), 1); if ($metric == 'loadTime') { $deltaStr = number_format(abs($delta / 1000), 3) . 's'; } else { $deltaStr = number_format(abs($delta), 0); } $deltaStr = htmlspecialchars("{$deltaStr} / {$deltaPct}%"); if ($delta > 0) { $display .= " <span class=\"bad\">(+{$deltaStr})</span>"; } elseif ($delta < 0) { $display .= " <span class=\"good\">(-{$deltaStr})</span>"; } else { $display .= "(No Change)"; } } echo "<td>{$display}</td>"; $index++; } echo "</tr>"; } echo "<tr><td class=\"right\">Full Test Result</td>"; foreach ($tests as &$test) { $img = ''; if (array_key_exists('id', $test)) { if (FRIENDLY_URLS) { $result = "/result/{$test['id']}/"; } else { $result = "/results.php?test={$test['id']}"; } $cached = ''; if ($test['cached']) { $cached = '_Cached'; } $thumbnail = "/thumbnail.php?test={$test['id']}&width=150&file={$test['run']}{$cached}_screen.jpg"; $img = "<a href=\"{$result}\"><img class=\"progress pimg\" src=\"{$thumbnail}\"><br>view test</a>"; } echo "<td>{$img}</td>"; } echo '</tr></table><br>'; $filmstrip = "/video/compare.php?tests="; foreach ($tests as &$test) { $filmstrip .= urlencode("{$test['id']}-r:{$test['run']}-c:{$test['cached']}-l:{$test['label']}") . ','; } echo "<h2>Visual Comparison (<a href=\"{$filmstrip}\">view filmstrip comparison</a>)</h2>"; }
function CollectTestResult($test, &$data) { global $benchmark; $id = $test['id']; $count = 0; echo "Reprocessing Test {$id}..."; logMsg("Reprocessing Test {$id}", "./log/reprocess-{$benchmark}.log", true); RestoreTest($id); ReprocessVideo($id); $testPath = './' . GetTestPath($id); $page_data = loadAllPageData($testPath); if (count($page_data)) { foreach ($page_data as $run => &$page_run) { foreach ($page_run as $cached => &$test_data) { $data_row = $test_data; unset($data_row['URL']); // figure out the per-type request info (todo: measure how expensive this is and see if we have a better way) $breakdown = getBreakdown($test['id'], $testPath, $run, $cached, $requests); foreach ($breakdown as $mime => &$values) { $data_row["{$mime}_requests"] = $values['requests']; $data_row["{$mime}_bytes"] = $values['bytes']; } // capture the page speed score if ($cached) { $data_row['page_speed'] = GetPageSpeedScore("{$testPath}/{$run}_Cached_pagespeed.txt"); } else { $data_row['page_speed'] = GetPageSpeedScore("{$testPath}/{$run}_pagespeed.txt"); } $data_row['url'] = $test['url']; $data_row['label'] = $test['label']; $data_row['location'] = $test['location']; $data_row['config'] = $test['config']; $data_row['cached'] = $cached; $data_row['run'] = $run; $data_row['id'] = $test['id']; $data[] = $data_row; $count++; } } } else { $data_row = array(); $data_row['url'] = $test['url']; $data_row['label'] = $test['label']; $data_row['location'] = $test['location']; $data_row['config'] = $test['config']; $data_row['id'] = $test['id']; $data[] = $data_row; } // If the test was already archived, re-archive it. $testInfo = GetTestInfo($id); if (array_key_exists('archived', $testInfo) && $testInfo['archived']) { $lock = LockTest($id); if (isset($lock)) { $testInfo = GetTestInfo($id); $testInfo['archived'] = false; SaveTestInfo($id, $testInfo); UnlockTest($lock); } ArchiveTest($id); } echo "{$count} results\n"; }
function ProcessTest($id) { global $tempDir; global $name; global $count; global $total; $ok = false; $testPath = './' . GetTestPath($id); $restored = false; if (!is_dir($testPath)) { // try restoring the test several times in case there are network issues $attempt = 0; do { $attempt++; har_log("{$id} - restoring test ({$attempt})"); RestoreTest($id); if (is_dir($testPath)) { $restored = true; } else { sleep(1); } } while (!$restored && $attempt < 120); } if (is_dir($testPath)) { har_log("{$id} - generating HAR"); $har = GenerateHAR($id, $testPath, ['bodies' => 1, 'run' => 'median', 'cached' => 0]); if (isset($har) && strlen($har)) { gz_file_put_contents("{$tempDir}/{$id}.har", $har); unset($har); $file = "{$tempDir}/{$id}.har.gz"; if (is_file($file)) { $file = realpath($file); $remoteFile = "{$name}/{$id}.har.gz"; $bucket = 'httparchive'; har_log("{$id} - Uploading to {$remoteFile}"); if (gsUpload($file, $bucket, $remoteFile)) { $ok = true; } else { har_log("{$id} - error uploading HAR"); } unlink($file); } else { har_log("{$id} - error saving HAR"); } } else { har_log("{$id} - error generating HAR"); } // clean up the test if we restored it if ($restored) { delTree($testPath, true); } } else { har_log("{$id} - error restoring test"); } return $ok; }