/**
* Calculate the progress for all of the images in a given directory
*/
function GetVisualProgress($testPath, $run, $cached, $options = null, $end = null, $startOffset = null)
{
    // TODO: in the long run this function might get redundant as the version below is more flexible
    $frames = null;
    $testPath = $testPath[0] == '.' || $testPath[0] == "/" ? $testPath : "./{$testPath}";
    $localPaths = new TestPaths($testPath, $run, $cached);
    $testInfo = GetTestInfo($testPath);
    $completed = IsTestRunComplete($run, $testInfo);
    return GetVisualProgressForStep($localPaths, $completed, $options, $end, $startOffset);
}
Example #2
0
/**
 * @param TestPaths $localPaths Paths for this run/step to get the CPU time for
 * @param int $endTime End time to consider (optional, will be retrieved from requests otherwise)
 * @return array
 */
function GetDevToolsCPUTimeForStep($localPaths, $endTime = 0)
{
    if (!$endTime) {
        require_once __DIR__ . '/page_data.inc';
        $runCompleted = IsTestRunComplete($localPaths->getRunNumber(), $testInfo);
        $pageData = loadPageStepData($localPaths, $runCompleted);
        if (isset($pageData) && is_array($pageData) && isset($pageData['fullyLoaded'])) {
            $endTime = $pageData['fullyLoaded'];
        }
    }
    $times = null;
    $ver = 3;
    $cacheFile = $localPaths->devtoolsCPUTimeCacheFile($ver);
    if (gz_is_file($cacheFile)) {
        $cache = json_decode(gz_file_get_contents($cacheFile), true);
    }
    if (isset($cache) && is_array($cache) && isset($cache[$endTime])) {
        $times = $cache[$endTime];
    } else {
        $cpu = DevToolsGetCPUSlicesForStep($localPaths);
        if (isset($cpu) && is_array($cpu) && isset($cpu['main_thread']) && isset($cpu['slices'][$cpu['main_thread']]) && isset($cpu['slice_usecs'])) {
            $busy = 0;
            $times = array();
            if (!$endTime && isset($cpu['total_usecs'])) {
                $endTime = $cpu['total_usecs'] / 1000;
            }
            foreach ($cpu['slices'][$cpu['main_thread']] as $name => $slices) {
                $last_slice = min(intval(ceil($endTime * 1000 / $cpu['slice_usecs'])), count($slices));
                $times[$name] = 0;
                for ($i = 0; $i < $last_slice; $i++) {
                    $times[$name] += $slices[$i] / 1000.0;
                }
                $busy += $times[$name];
                $times[$name] = intval(round($times[$name]));
            }
            $times['Idle'] = max($endTime - intval(round($busy)), 0);
        }
        // Cache the result
        if (!isset($cache) || !is_array($cache)) {
            $cache = array();
        }
        $cache[$endTime] = $times;
        gz_file_put_contents($cacheFile, json_encode($cache));
    }
    return $times;
}
/**
* Calculate the progress for all of the images in a given directory
*/
function GetVisualProgress($testPath, $run, $cached, $options = null, $end = null, $startOffset = null)
{
    $frames = null;
    if (substr($testPath, 0, 1) !== '.') {
        $testPath = './' . $testPath;
    }
    $testInfo = GetTestInfo($testPath);
    $completed = IsTestRunComplete($run, $testInfo);
    $video_directory = "{$testPath}/video_{$run}";
    if ($cached) {
        $video_directory .= '_cached';
    }
    $cache_file = "{$testPath}/{$run}.{$cached}.visual.dat";
    if (!isset($startOffset)) {
        $startOffset = 0;
    }
    $visual_data_file = "{$testPath}/llab_{$run}.{$cached}.visual.dat";
    if (gz_is_file($visual_data_file)) {
        $visual_data = json_decode(gz_file_get_contents($visual_data_file), true);
        // see if we are processing an externally-uploaded visual data file
        if (isset($visual_data['timespans']['page_load']['startOffset'])) {
            $startOffset += $visual_data['timespans']['page_load']['startOffset'];
        }
    }
    $dirty = false;
    $current_version = VIDEO_CODE_VERSION;
    if (isset($end)) {
        if (is_numeric($end)) {
            $end = (int) ($end * 1000);
        } else {
            unset($end);
        }
    }
    if (!isset($end) && !isset($options) && gz_is_file($cache_file)) {
        $frames = json_decode(gz_file_get_contents($cache_file), true);
        if (!array_key_exists('frames', $frames) || !array_key_exists('version', $frames)) {
            unset($frames);
        } elseif (array_key_exists('version', $frames) && $frames['version'] !== $current_version) {
            unset($frames);
        }
    }
    $base_path = substr($video_directory, 1);
    if ((!isset($frames) || !count($frames)) && (is_dir($video_directory) || gz_is_file("{$testPath}/{$run}.{$cached}.histograms.json"))) {
        $frames = array('version' => $current_version);
        $frames['frames'] = array();
        $dirty = true;
        if (is_dir($video_directory)) {
            $files = scandir($video_directory);
            $last_file = null;
            $first_file = null;
            $previous_file = null;
            foreach ($files as $file) {
                if (strpos($file, 'frame_') !== false && strpos($file, '.hist') === false) {
                    $parts = explode('_', $file);
                    if (count($parts) >= 2) {
                        $time = (int) $parts[1] * 100 - $startOffset;
                        if ($time >= 0 && (!isset($end) || $time <= $end)) {
                            if (isset($previous_file) && !array_key_exists(0, $frames['frames']) && $time > 0) {
                                $frames['frames'][0] = array('path' => "{$base_path}/{$previous_file}", 'file' => $previous_file);
                                $first_file = $previous_file;
                            } elseif (!isset($first_file)) {
                                $first_file = $file;
                            }
                            $last_file = $file;
                            $frames['frames'][$time] = array('path' => "{$base_path}/{$file}", 'file' => $file);
                        }
                        $previous_file = $file;
                    }
                } elseif (strpos($file, 'ms_') !== false && strpos($file, '.hist') === false) {
                    $parts = explode('_', $file);
                    if (count($parts) >= 2) {
                        $time = intval($parts[1]) - $startOffset;
                        if ($time >= 0 && (!isset($end) || $time <= $end)) {
                            if (isset($previous_file) && !array_key_exists(0, $frames['frames']) && $time > 0) {
                                $frames['frames'][0] = array('path' => "{$base_path}/{$previous_file}", 'file' => $previous_file);
                                $first_file = $previous_file;
                            } elseif (!isset($first_file)) {
                                $first_file = $file;
                            }
                            $last_file = $file;
                            $frames['frames'][$time] = array('path' => "{$base_path}/{$file}", 'file' => $file);
                        }
                        $previous_file = $file;
                    }
                }
            }
            if (count($frames['frames']) == 1) {
                foreach ($frames['frames'] as $time => &$frame) {
                    $frame['progress'] = 100;
                    $frames['complete'] = $time;
                }
            } elseif (isset($first_file) && strlen($first_file) && isset($last_file) && strlen($last_file) && count($frames['frames'])) {
                $histograms = null;
                if (gz_is_file("{$testPath}/{$run}.{$cached}.histograms.json")) {
                    $histograms = json_decode(gz_file_get_contents("{$testPath}/{$run}.{$cached}.histograms.json"), true);
                }
                $start_histogram = GetImageHistogram("{$video_directory}/{$first_file}", $options, $histograms);
                $final_histogram = GetImageHistogram("{$video_directory}/{$last_file}", $options, $histograms);
                foreach ($frames['frames'] as $time => &$frame) {
                    $histogram = GetImageHistogram("{$video_directory}/{$frame['file']}", $options, $histograms);
                    $frame['progress'] = CalculateFrameProgress($histogram, $start_histogram, $final_histogram, 5);
                    if ($frame['progress'] == 100 && !array_key_exists('complete', $frames)) {
                        $frames['complete'] = $time;
                    }
                }
            }
        } elseif (gz_is_file("{$testPath}/{$run}.{$cached}.histograms.json")) {
            $raw = json_decode(gz_file_get_contents("{$testPath}/{$run}.{$cached}.histograms.json"), true);
            $histograms = array();
            foreach ($raw as $h) {
                if (isset($h['time']) && isset($h['histogram'])) {
                    $histograms[$h['time']] = $h['histogram'];
                }
            }
            ksort($histograms, SORT_NUMERIC);
            $final_histogram = end($histograms);
            $start_histogram = reset($histograms);
            foreach ($histograms as $time => $histogram) {
                $frames['frames'][$time] = array();
                $progress = CalculateFrameProgress($histogram, $start_histogram, $final_histogram, 5);
                $frames['frames'][$time]['progress'] = $progress;
                if ($progress == 100 && !isset($frames['complete'])) {
                    $frames['complete'] = $time;
                }
            }
        }
    }
    if (isset($frames) && !array_key_exists('SpeedIndex', $frames)) {
        $dirty = true;
        $frames['SpeedIndex'] = CalculateSpeedIndex($frames);
    }
    if (isset($frames)) {
        $frames['visualComplete'] = 0;
        foreach ($frames['frames'] as $time => &$frame) {
            if ($frame['progress'] > 0 && !array_key_exists('startRender', $frames)) {
                $frames['startRender'] = $time;
            }
            if (!$frames['visualComplete'] && $frame['progress'] == 100) {
                $frames['visualComplete'] = $time;
            }
            // fix up the frame paths in case we have a cached version referencing a relay path
            if (isset($frame['path'])) {
                $frame['path'] = $base_path . '/' . basename($frame['path']);
            }
        }
    }
    if ($completed && !isset($end) && !isset($options) && $dirty && isset($frames) && count($frames)) {
        gz_file_put_contents($cache_file, json_encode($frames));
    }
    return $frames;
}
Example #4
0
 /**
  * @param int $run The run to check if complete
  * @return bool True if the test run is complete, false otherwise
  */
 public function isRunComplete($run)
 {
     // TODO: move implementation here
     return $run <= $this->getRuns() && IsTestRunComplete($run, $this->rawData['testinfo']);
 }
/**
* Calculate the progress for all of the images in a given directory
*/
function GetVisualProgress($testPath, $run, $cached, $options = null, $end = null, $startOffset = null)
{
    $frames = null;
    if (substr($testPath, 0, 1) !== '.') {
        $testPath = './' . $testPath;
    }
    $testInfo = GetTestInfo($testPath);
    $completed = IsTestRunComplete($run, $testInfo);
    $video_directory = "{$testPath}/video_{$run}";
    if ($cached) {
        $video_directory .= '_cached';
    }
    $cache_file = "{$testPath}/{$run}.{$cached}.visual.dat";
    if (!isset($startOffset)) {
        $startOffset = 0;
    }
    $dirty = false;
    $current_version = VIDEO_CODE_VERSION;
    if (isset($end)) {
        if (is_numeric($end)) {
            $end = (int) ($end * 1000);
        } else {
            unset($end);
        }
    }
    if (!isset($end) && !isset($options) && gz_is_file($cache_file)) {
        $frames = json_decode(gz_file_get_contents($cache_file), true);
        if (!array_key_exists('frames', $frames) || !array_key_exists('version', $frames)) {
            unset($frames);
        } elseif (array_key_exists('version', $frames) && $frames['version'] !== $current_version) {
            unset($frames);
        }
    }
    if ((!isset($frames) || !count($frames)) && is_dir($video_directory)) {
        $frames = array('version' => $current_version);
        $frames['frames'] = array();
        $dirty = true;
        $base_path = substr($video_directory, 1);
        $files = scandir($video_directory);
        $last_file = null;
        $first_file = null;
        $previous_file = null;
        foreach ($files as $file) {
            if (strpos($file, 'frame_') !== false && strpos($file, '.hist') === false) {
                $parts = explode('_', $file);
                if (count($parts) >= 2) {
                    $time = (int) $parts[1] * 100 - $startOffset;
                    if ($time >= 0 && (!isset($end) || $time <= $end)) {
                        if (isset($previous_file) && !array_key_exists(0, $frames['frames']) && $time > 0) {
                            $frames['frames'][0] = array('path' => "{$base_path}/{$previous_file}", 'file' => $previous_file);
                            $first_file = $previous_file;
                        } elseif (!isset($first_file)) {
                            $first_file = $file;
                        }
                        $last_file = $file;
                        $frames['frames'][$time] = array('path' => "{$base_path}/{$file}", 'file' => $file);
                    }
                    $previous_file = $file;
                }
            } elseif (strpos($file, 'ms_') !== false && strpos($file, '.hist') === false) {
                $parts = explode('_', $file);
                if (count($parts) >= 2) {
                    $time = intval($parts[1]) - $startOffset;
                    if ($time >= 0 && (!isset($end) || $time <= $end)) {
                        if (isset($previous_file) && !array_key_exists(0, $frames['frames']) && $time > 0) {
                            $frames['frames'][0] = array('path' => "{$base_path}/{$previous_file}", 'file' => $previous_file);
                            $first_file = $previous_file;
                        } elseif (!isset($first_file)) {
                            $first_file = $file;
                        }
                        $last_file = $file;
                        $frames['frames'][$time] = array('path' => "{$base_path}/{$file}", 'file' => $file);
                    }
                    $previous_file = $file;
                }
            }
        }
        if (count($frames['frames']) == 1) {
            foreach ($frames['frames'] as $time => &$frame) {
                $frame['progress'] = 100;
                $frames['complete'] = $time;
            }
        } elseif (isset($first_file) && strlen($first_file) && isset($last_file) && strlen($last_file) && count($frames['frames'])) {
            $start_histogram = GetImageHistogram("{$video_directory}/{$first_file}", $options);
            $final_histogram = GetImageHistogram("{$video_directory}/{$last_file}", $options);
            foreach ($frames['frames'] as $time => &$frame) {
                $histogram = GetImageHistogram("{$video_directory}/{$frame['file']}", $options);
                $frame['progress'] = CalculateFrameProgress($histogram, $start_histogram, $final_histogram, 5);
                if ($frame['progress'] == 100 && !array_key_exists('complete', $frames)) {
                    $frames['complete'] = $time;
                }
            }
        }
    }
    if (isset($frames) && !array_key_exists('SpeedIndex', $frames)) {
        $dirty = true;
        $frames['SpeedIndex'] = CalculateSpeedIndex($frames);
    }
    if (isset($frames)) {
        $frames['visualComplete'] = 0;
        foreach ($frames['frames'] as $time => &$frame) {
            if ($frame['progress'] > 0 && !array_key_exists('startRender', $frames)) {
                $frames['startRender'] = $time;
            }
            if ($frame['progress'] == 100) {
                $frames['visualComplete'] = $time;
                break;
            }
        }
    }
    $devTools = GetDevToolsProgress($testPath, $run, $cached);
    if (isset($devTools)) {
        if (!isset($frames)) {
            $frames = array();
        }
        $frames['DevTools'] = $devTools;
    }
    if ($completed && !isset($end) && !isset($options) && $dirty && isset($frames) && count($frames)) {
        gz_file_put_contents($cache_file, json_encode($frames));
    }
    return $frames;
}
/**
* Calculate the visual progress and speed index from the dev tools timeline trace
* 
* @param mixed $testPath
* @param mixed $run
* @param mixed $cached
*/
function GetDevToolsProgress($testPath, $run, $cached)
{
    $progress = GetCachedDevToolsProgress($testPath, $run, $cached);
    if (!isset($progress) || !is_array($progress)) {
        $testInfo = GetTestInfo($testPath);
        $completed = IsTestRunComplete($run, $testInfo);
        $startOffset = null;
        if (GetTimeline($testPath, $run, $cached, $timeline, $startOffset)) {
            $cachedText = '';
            if ($cached) {
                $cachedText = '_Cached';
            }
            $console_log_file = "{$testPath}/{$run}{$cachedText}_console_log.json";
            $console_log = array();
            $progress = array();
            $startTime = 0;
            $fullScreen = 0;
            $regions = array();
            $viewport = null;
            if (DevToolsHasLayout($timeline, $viewport)) {
                $didLayout = false;
                $didReceiveResponse = false;
            } else {
                $didLayout = true;
                $didReceiveResponse = true;
            }
            $startTimes = array();
            $progress['processing'] = array();
            foreach ($timeline as &$entry) {
                if (array_key_exists('method', $entry)) {
                    if (array_key_exists('params', $entry) && !array_key_exists($entry['method'], $startTimes)) {
                        if (array_key_exists('timestamp', $entry['params'])) {
                            $startTimes[$entry['method']] = $entry['params']['timestamp'];
                        } elseif (array_key_exists('record', $entry['params']) && array_key_exists('startTime', $entry['params']['record'])) {
                            $startTimes[$entry['method']] = $entry['params']['record']['startTime'];
                        }
                    }
                } elseif (array_key_exists('timestamp', $entry) && !array_key_exists('timestamp', $startTimes)) {
                    $startTimes['timestamp'] = $entry['timestamp'];
                }
                $frame = '0';
                ProcessPaintEntry($entry, $fullScreen, $regions, $frame, $didLayout, $didReceiveResponse, $viewport);
                if (!isset($entry['params']['record']['thread']) || $entry['params']['record']['thread'] == 0) {
                    GetTimelineProcessingTimes($entry, $progress['processing'], $processing_start, $processing_end);
                }
                if (DevToolsMatchEvent('Console.messageAdded', $entry) && array_key_exists('message', $entry['params']) && is_array($entry['params']['message'])) {
                    $console_log[] = $entry['params']['message'];
                }
            }
            if (!gz_is_file($console_log_file)) {
                gz_file_put_contents($console_log_file, json_encode($console_log));
            }
            if (count($progress['processing'])) {
                $proc_total = 0.0;
                foreach ($progress['processing'] as $type => &$procTime) {
                    $proc_total += $procTime;
                    $procTime = intval(round($procTime));
                }
                $progress['processing']['Idle'] = 0;
                if (isset($processing_start) && isset($processing_end) && $processing_end > $processing_start) {
                    $proc_elapsed = $processing_end - $processing_start;
                    if ($proc_elapsed > $proc_total) {
                        $progress['processing']['Idle'] = intval(round($proc_elapsed - $proc_total));
                    }
                }
            } else {
                unset($progress['processing']);
            }
            foreach ($startTimes as $time) {
                if (!$startTime || $time < $startTime) {
                    $startTime = $time;
                }
            }
            $regionCount = count($regions);
            if ($regionCount) {
                $paintEvents = array();
                $total = 0.0;
                foreach ($regions as $name => &$region) {
                    $area = $region['width'] * $region['height'];
                    $updateCount = floatval(count($region['times']));
                    $incrementalImpact = floatval($area) / $updateCount;
                    // only count full screen paints for half their value
                    if ($area == $fullScreen) {
                        $incrementalImpact /= 2;
                    }
                    foreach ($region['times'] as $time) {
                        $total += $incrementalImpact;
                        $elapsed = (int) ($time - $startTime);
                        if (!array_key_exists($elapsed, $paintEvents)) {
                            $paintEvents[$elapsed] = $incrementalImpact;
                        } else {
                            $paintEvents[$elapsed] += $incrementalImpact;
                        }
                    }
                }
                if (count($paintEvents)) {
                    ksort($paintEvents, SORT_NUMERIC);
                    $current = 0.0;
                    $lastTime = 0.0;
                    $lastProgress = 0.0;
                    $progress['SpeedIndex'] = 0.0;
                    $progress['VisuallyComplete'] = 0;
                    $progress['StartRender'] = 0;
                    $progress['VisualProgress'] = array();
                    foreach ($paintEvents as $time => $increment) {
                        $current += $increment;
                        $currentProgress = floatval(floatval($current) / floatval($total));
                        $currentProgress = floatval(round($currentProgress * 100) / 100.0);
                        $elapsed = $time - $lastTime;
                        $siIncrement = floatval($elapsed) * (1.0 - $lastProgress);
                        $progress['SpeedIndex'] += $siIncrement;
                        $progress['VisualProgress'][$time] = $currentProgress;
                        $progress['VisuallyComplete'] = $time;
                        if (!$progress['StartRender']) {
                            $progress['StartRender'] = $time;
                        }
                        $lastProgress = $currentProgress;
                        $lastTime = $time;
                        if ($currentProgress >= 1.0) {
                            break;
                        }
                    }
                }
            }
            if ($completed && isset($progress) && is_array($progress)) {
                SavedCachedDevToolsProgress($testPath, $run, $cached, $progress);
            }
        }
    }
    return $progress;
}