initial domain-check script

This commit is contained in:
Howard Stearns 2016-10-03 10:29:33 -07:00
parent 0ee1156e5c
commit ee801f4cc2

View file

@ -0,0 +1,201 @@
"use strict";
/*jslint vars: true, plusplus: true*/
/*globals Script, MyAvatar, Quat, Render, ScriptDiscoveryService, Window, LODManager, Entities, print*/
//
// loadedMachine.js
// scripts/developer/tests/
//
// Created by Howard Stearns on 6/6/16.
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// Confirms that the specified domain is operating within specified constraints.
var MINIMUM_DESKTOP_FRAMERATE = 57; // frames per second
var MINIMUM_HMD_FRAMERATE = 86;
var EXPECTED_DESKTOP_FRAMERATE = 60;
var EXPECTED_HMD_FRAMERATE = 90;
var MAXIMUM_LOAD_TIME = 60; // seconds
var MINIMUM_AVATARS = 25; // FIXME: not implemented yet. Requires agent scripts. Idea is to have them organize themselves to the right number.
var version = 1;
function debug() {
print.apply(null, [].concat.apply(['hrs fixme', version], [].map.call(arguments, JSON.stringify)));
}
var emptyishPlace = 'empty';
var cachePlaces = ['localhost', 'Welcome'];
var isInCachePlace = cachePlaces.indexOf(location.hostname) >= 0;
var defaultPlace = isInCachePlace ? 'Playa' : location.hostname;
var prompt = "domain-check.js version " + version + "\n\nWhat place should we enter?";
debug(cachePlaces, isInCachePlace, defaultPlace, prompt);
var entryPlace = Window.prompt(prompt, defaultPlace);
var fail = false, results = "";
function addResult(label, actual, minimum, maximum) {
if ((minimum !== undefined) && (actual < minimum)) {
fail = true;
}
if ((maximum !== undefined) && (actual > maximum)) {
fail = true;
}
results += "\n" + label + ": " + actual + " (" + ((100 * actual) / (maximum || minimum)).toFixed(0) + "%)";
}
function giveReport() {
Window.alert(entryPlace + (fail ? " FAILED" : " OK") + "\n" + results);
}
// Tests are performed domain-wide, at full LOD
var initialLodIsAutomatic = LODManager.getAutomaticLODAdjust();
var LOD = 32768 * 400;
LODManager.setAutomaticLODAdjust(false);
LODManager.setOctreeSizeScale(LOD);
Script.scriptEnding.connect(function () { LODManager.setAutomaticLODAdjust(initialLodIsAutomatic); });
function startTwirl(targetRotation, degreesPerUpdate, interval, strafeDistance, optionalCallback) {
var initialRotation = Quat.safeEulerAngles(MyAvatar.orientation).y;
var accumulatedRotation = 0;
function tick() {
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, accumulatedRotation + initialRotation, 0);
if (strafeDistance) {
MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(strafeDistance, Quat.getRight(MyAvatar.orientation)));
}
accumulatedRotation += degreesPerUpdate;
if (accumulatedRotation >= targetRotation) {
return optionalCallback && optionalCallback();
}
Script.setTimeout(tick, interval);
}
tick();
}
function doLoad(place, continuationWithLoadTime) { // Go to place and call continuationWithLoadTime(loadTimeInSeconds)
var start = Date.now(), timeout, onDownloadUpdate, finishedTwirl = false, loadTime;
function clearHandlers() {
debug('clearHandlers');
Stats.downloadsPendingChanged.disconnect(onDownloadUpdate);
Stats.downloadsChanged.disconnect(onDownloadUpdate);
}
function waitForLoad(flag) {
debug('entry', place, 'initial downloads/pending', Stats.downloads, Stats.downloadsPending);
location.hostChanged.disconnect(waitForLoad);
timeout = Script.setTimeout(function () {
debug('downloads timeout', Date());
clearHandlers();
Window.alert("Timeout during " + place + " load. FAILED");
Script.stop();
}, MAXIMUM_LOAD_TIME * 1000);
startTwirl(360, 6, 90, null, function () {
finishedTwirl = true;
if (loadTime) {
continuationWithLoadTime(loadTime);
}
});
Stats.downloadsPendingChanged.connect(onDownloadUpdate);
Stats.downloadsChanged.connect(onDownloadUpdate);
}
function isLoading() {
// FIXME: This tells us when download are completed, but it doesn't tell us when the objects are parsed and loaded.
// We really want something like _physicsEnabled, but that isn't signalled.
return Stats.downloads || Stats.downloadsPending;
}
onDownloadUpdate = function onDownloadUpdate() {
debug('update downloads/pending', Stats.downloads, Stats.downloadsPending);
if (isLoading()) {
return;
}
Script.clearTimeout(timeout);
clearHandlers();
loadTime = (Date.now() - start) / 1000;
if (finishedTwirl) {
continuationWithLoadTime(loadTime);
}
};
function doit() {
debug('go', place);
location.hostChanged.connect(waitForLoad);
location.handleLookupString(place);
}
if (location.placename.toLowerCase() === place.toLowerCase()) {
location.handleLookupString(emptyishPlace);
Script.setTimeout(doit, 1000);
} else {
doit();
}
}
var config = Render.getConfig("Stats");
function doRender(continuation) {
var start = Date.now(), frames = 0;
function onNewStats() { // Accumulates frames on signal during load test
frames++;
}
config.newStats.connect(onNewStats);
startTwirl(720, 1, 15, 0.08, function () {
var end = Date.now();
config.newStats.disconnect(onNewStats);
addResult('frame rate', 1000 * frames / (end - start),
HMD.active ? MINIMUM_HMD_FRAMERATE : MINIMUM_DESKTOP_FRAMERATE,
HMD.active ? EXPECTED_HMD_FRAMERATE : EXPECTED_DESKTOP_FRAMERATE);
continuation();
});
}
function maybePrepareCache(continuation) {
var prepareCache = Window.confirm("Prepare cache?\n\n\
Should we start with all and only those items cached that are encountered when visiting:\n" + cachePlaces.join(', ') + "\n\
If 'yes', cache will be cleared and we will visit these two, with a turn in each, and wait for everything to be loaded.\n\
You would want to say 'no' (and make other preparations) if you were testing these places.");
if (prepareCache) {
location.handleLookupString(emptyishPlace);
Window.alert("Please do menu Edit->Reload Content (Clears all caches) and THEN press 'ok'.");
function loadNext() {
var place = cachePlaces.shift();
doLoad(place, function (prepTime) {
debug(place, 'ready', prepTime);
if (cachePlaces.length) {
loadNext();
} else {
continuation();
}
});
}
loadNext();
} else {
continuation();
}
}
function maybeRunTribbles(continuation) {
if (Window.confirm("Run tribbles?\n\n\
At most, only one participant should say yes.")) {
Script.load('http://howard-stearns.github.io/models/scripts/tests/performance/tribbles.js'); // FIXME: replace with AWS
Script.setTimeout(continuation, 3000);
} else {
continuation();
}
}
if (!entryPlace) {
Window.alert("domain-check.js cancelled");
Script.stop();
} else {
maybePrepareCache(function (prepTime) {
debug('cache ready', prepTime);
doLoad(entryPlace, function (loadTime) {
addResult("load time", loadTime, undefined, MAXIMUM_LOAD_TIME);
maybeRunTribbles(function () {
doRender(function () {
giveReport();
Script.stop();
});
});
});
});
}
Script.scriptEnding.connect(function () { print("domain-check completed"); });