mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 17:56:43 +02:00
Working on an automated performance test
This commit is contained in:
parent
4b7a4e80ff
commit
f3e5306f90
8 changed files with 324 additions and 4 deletions
11
examples/tests/playaPerformanceTest.js
Normal file
11
examples/tests/playaPerformanceTest.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
var qml = Script.resolvePath('playaPerformanceTest.qml');
|
||||||
|
qmlWindow = new OverlayWindow({
|
||||||
|
title: 'Test Qml',
|
||||||
|
source: qml,
|
||||||
|
height: 320,
|
||||||
|
width: 640,
|
||||||
|
toolWindow: false,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
|
||||||
|
|
193
examples/tests/playaPerformanceTest.qml
Normal file
193
examples/tests/playaPerformanceTest.qml
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
width: parent ? parent.width : 100
|
||||||
|
height: parent ? parent.height : 100
|
||||||
|
|
||||||
|
signal sendToScript(var message);
|
||||||
|
property var values: [];
|
||||||
|
property var host: AddressManager.hostname
|
||||||
|
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
Window.domainChanged.connect(function(newDomain){
|
||||||
|
if (newDomain !== root.host) {
|
||||||
|
root.host = AddressManager.hostname;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onHostChanged: {
|
||||||
|
if (root.running) {
|
||||||
|
if (host !== "Dreaming" && host !== "Playa") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("PERF new domain " + host)
|
||||||
|
if (host === "Dreaming") {
|
||||||
|
AddressManager.handleLookupString("Playa");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host === "Playa") {
|
||||||
|
console.log("PERF starting timers and frame timing");
|
||||||
|
// If we've arrived, start running the test
|
||||||
|
FrameTimings.start();
|
||||||
|
rotationTimer.start();
|
||||||
|
stopTimer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTest() {
|
||||||
|
console.log("PERF startTest()");
|
||||||
|
root.running = true
|
||||||
|
console.log("PERF current host: " + AddressManager.hostname)
|
||||||
|
// If we're already in playa, we need to go somewhere else...
|
||||||
|
if ("Playa" === AddressManager.hostname) {
|
||||||
|
console.log("PERF Navigating to dreaming")
|
||||||
|
AddressManager.handleLookupString("Dreaming/0,0,0");
|
||||||
|
} else {
|
||||||
|
console.log("PERF Navigating to playa")
|
||||||
|
AddressManager.handleLookupString("Playa");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopTest() {
|
||||||
|
console.log("PERF stopTest()");
|
||||||
|
root.running = false;
|
||||||
|
stopTimer.stop();
|
||||||
|
rotationTimer.stop();
|
||||||
|
FrameTimings.finish();
|
||||||
|
root.values = FrameTimings.getValues();
|
||||||
|
AddressManager.handleLookupString("Dreaming/0,0,0");
|
||||||
|
resultGraph.requestPaint();
|
||||||
|
console.log("PERF Value Count: " + root.values.length);
|
||||||
|
console.log("PERF Max: " + FrameTimings.max);
|
||||||
|
console.log("PERF Min: " + FrameTimings.min);
|
||||||
|
console.log("PERF Avg: " + FrameTimings.mean);
|
||||||
|
console.log("PERF StdDev: " + FrameTimings.standardDeviation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function yaw(a) {
|
||||||
|
var y = -Math.sin( a / 2.0 );
|
||||||
|
var w = Math.cos( a / 2.0 );
|
||||||
|
var l = Math.sqrt((y * y) + (w * w));
|
||||||
|
return Qt.quaternion(w / l, 0, y / l, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotate() {
|
||||||
|
MyAvatar.setOrientationVar(yaw(Date.now() / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool running: false
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: stopTimer
|
||||||
|
interval: 30 * 1000
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
onTriggered: stopTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: rotationTimer
|
||||||
|
interval: 100
|
||||||
|
repeat: true
|
||||||
|
running: false
|
||||||
|
onTriggered: rotate();
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row
|
||||||
|
anchors { left: parent.left; right: parent.right; }
|
||||||
|
spacing: 8
|
||||||
|
Button {
|
||||||
|
text: root.running ? "Stop" : "Run"
|
||||||
|
onClicked: root.running ? stopTest() : startTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rectangle {
|
||||||
|
// anchors { left: parent.left; right: parent.right; top: row.bottom; topMargin: 8; bottom: parent.bottom; }
|
||||||
|
// //anchors.fill: parent
|
||||||
|
// color: "#7fff0000"
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Return the maximum value from a set of values
|
||||||
|
function vv(i, max) {
|
||||||
|
var perValue = values.length / max;
|
||||||
|
var start = Math.floor(perValue * i);
|
||||||
|
var end = Math.min(values.length, Math.floor(start + perValue));
|
||||||
|
var result = 0;
|
||||||
|
for (var j = start; j <= end; ++j) {
|
||||||
|
result = Math.max(result, values[j]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
id: resultGraph
|
||||||
|
anchors { left: parent.left; right: parent.right; top: row.bottom; margins: 16; bottom: parent.bottom; }
|
||||||
|
property real maxValue: 200;
|
||||||
|
property real perFrame: 10000;
|
||||||
|
property real k1: (5 / maxValue) * height;
|
||||||
|
property real k2: (10 / maxValue) * height;
|
||||||
|
property real k3: (100 / maxValue) * height;
|
||||||
|
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d");
|
||||||
|
if (values.length === 0) {
|
||||||
|
ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//ctx.setTransform(1, 0, 0, -1, 0, 0);
|
||||||
|
ctx.fillStyle = Qt.rgba(0, 0, 0, 1);
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
ctx.strokeStyle= "gray";
|
||||||
|
ctx.lineWidth="1";
|
||||||
|
ctx.beginPath();
|
||||||
|
for (var i = 0; i < width; ++i) {
|
||||||
|
var value = vv(i, width); //values[Math.min(i, values.length - 1)];
|
||||||
|
value /= 10000;
|
||||||
|
value /= maxValue;
|
||||||
|
ctx.moveTo(i, height);
|
||||||
|
ctx.lineTo(i, height - (height * value));
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle= "green";
|
||||||
|
ctx.lineWidth="2";
|
||||||
|
ctx.beginPath();
|
||||||
|
var lineHeight = height - k1;
|
||||||
|
ctx.moveTo(0, lineHeight);
|
||||||
|
ctx.lineTo(width, lineHeight);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle= "yellow";
|
||||||
|
ctx.lineWidth="2";
|
||||||
|
ctx.beginPath();
|
||||||
|
lineHeight = height - k2;
|
||||||
|
ctx.moveTo(0, lineHeight);
|
||||||
|
ctx.lineTo(width, lineHeight);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.strokeStyle= "red";
|
||||||
|
ctx.lineWidth="2";
|
||||||
|
ctx.beginPath();
|
||||||
|
lineHeight = height - k3;
|
||||||
|
ctx.moveTo(0, lineHeight);
|
||||||
|
ctx.lineTo(width, lineHeight);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,8 @@
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "InterfaceParentFinder.h"
|
#include "InterfaceParentFinder.h"
|
||||||
|
|
||||||
|
#include "FrameTimingsScriptingInterface.h"
|
||||||
|
|
||||||
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||||
// FIXME seems to be broken.
|
// FIXME seems to be broken.
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
@ -1334,6 +1336,8 @@ void Application::initializeGL() {
|
||||||
InfoView::show(INFO_HELP_PATH, true);
|
InfoView::show(INFO_HELP_PATH, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||||
|
|
||||||
extern void setupPreferences();
|
extern void setupPreferences();
|
||||||
|
|
||||||
void Application::initializeUi() {
|
void Application::initializeUi() {
|
||||||
|
@ -1378,6 +1382,8 @@ void Application::initializeUi() {
|
||||||
rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
|
rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
|
||||||
rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
|
rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
|
||||||
rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
rootContext->setContextProperty("Preferences", DependencyManager::get<Preferences>().data());
|
||||||
|
rootContext->setContextProperty("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||||
|
rootContext->setContextProperty("FrameTimings", &_frameTimingsScriptingInterface);
|
||||||
|
|
||||||
rootContext->setContextProperty("TREE_SCALE", TREE_SCALE);
|
rootContext->setContextProperty("TREE_SCALE", TREE_SCALE);
|
||||||
rootContext->setContextProperty("Quat", new Quat());
|
rootContext->setContextProperty("Quat", new Quat());
|
||||||
|
@ -1421,6 +1427,7 @@ void Application::initializeUi() {
|
||||||
rootContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
|
rootContext->setContextProperty("Reticle", getApplicationCompositor().getReticleInterface());
|
||||||
|
|
||||||
rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
rootContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
||||||
|
|
||||||
|
|
||||||
_glWidget->installEventFilter(offscreenUi.data());
|
_glWidget->installEventFilter(offscreenUi.data());
|
||||||
offscreenUi->setMouseTranslator([=](const QPointF& pt) {
|
offscreenUi->setMouseTranslator([=](const QPointF& pt) {
|
||||||
|
@ -1463,9 +1470,9 @@ void Application::initializeUi() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Application::paintGL() {
|
void Application::paintGL() {
|
||||||
updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
// Some plugins process message events, potentially leading to
|
// Some plugins process message events, potentially leading to
|
||||||
// re-entering a paint event. don't allow further processing if this
|
// re-entering a paint event. don't allow further processing if this
|
||||||
// happens
|
// happens
|
||||||
|
@ -1483,6 +1490,7 @@ void Application::paintGL() {
|
||||||
_frameCount++;
|
_frameCount++;
|
||||||
_frameCounter.increment();
|
_frameCounter.increment();
|
||||||
|
|
||||||
|
auto lastPaintBegin = usecTimestampNow();
|
||||||
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
|
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
|
||||||
PerformanceTimer perfTimer("paintGL");
|
PerformanceTimer perfTimer("paintGL");
|
||||||
|
|
||||||
|
@ -1735,6 +1743,9 @@ void Application::paintGL() {
|
||||||
batch.resetStages();
|
batch.resetStages();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||||
|
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::runTests() {
|
void Application::runTests() {
|
||||||
|
|
53
interface/src/FrameTimingsScriptingInterface.cpp
Normal file
53
interface/src/FrameTimingsScriptingInterface.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/04/04
|
||||||
|
// Copyright 2013-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
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "FrameTimingsScriptingInterface.h"
|
||||||
|
|
||||||
|
#include <TextureCache.h>
|
||||||
|
|
||||||
|
void FrameTimingsScriptingInterface::start() {
|
||||||
|
_values.clear();
|
||||||
|
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(0);
|
||||||
|
_values.reserve(8192);
|
||||||
|
_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameTimingsScriptingInterface::addValue(uint64_t value) {
|
||||||
|
if (_active) {
|
||||||
|
_values.push_back(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameTimingsScriptingInterface::finish() {
|
||||||
|
_active = false;
|
||||||
|
uint64_t total = 0;
|
||||||
|
_min = std::numeric_limits<uint64_t>::max();
|
||||||
|
_max = std::numeric_limits<uint64_t>::lowest();
|
||||||
|
size_t count = _values.size();
|
||||||
|
for (auto i = 0; i < count; ++i) {
|
||||||
|
const uint64_t& value = _values[i];
|
||||||
|
_max = std::max(_max, value);
|
||||||
|
_min = std::min(_min, value);
|
||||||
|
total += value;
|
||||||
|
}
|
||||||
|
_mean = (float)total / (float)count;
|
||||||
|
float deviationTotal = 0;
|
||||||
|
for (auto i = 0; i < count; ++i) {
|
||||||
|
float deviation = _values[i] - _mean;
|
||||||
|
deviationTotal += deviation*deviation;
|
||||||
|
}
|
||||||
|
_stdDev = sqrt(deviationTotal / (float)count);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList FrameTimingsScriptingInterface::getValues() const {
|
||||||
|
QVariantList result;
|
||||||
|
for (const auto& v : _values) {
|
||||||
|
result << v;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
38
interface/src/FrameTimingsScriptingInterface.h
Normal file
38
interface/src/FrameTimingsScriptingInterface.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016/04/04
|
||||||
|
// Copyright 2013-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
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
class FrameTimingsScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(float mean READ getMean CONSTANT)
|
||||||
|
Q_PROPERTY(float max READ getMax CONSTANT)
|
||||||
|
Q_PROPERTY(float min READ getMin CONSTANT)
|
||||||
|
Q_PROPERTY(float standardDeviation READ getStandardDeviation CONSTANT)
|
||||||
|
public:
|
||||||
|
Q_INVOKABLE void start();
|
||||||
|
Q_INVOKABLE void addValue(uint64_t value);
|
||||||
|
Q_INVOKABLE void finish();
|
||||||
|
Q_INVOKABLE QVariantList getValues() const;
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t getMax() const { return _max; }
|
||||||
|
uint64_t getMin() const { return _min; }
|
||||||
|
float getStandardDeviation() const { return _stdDev; }
|
||||||
|
float getMean() const { return _mean; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<uint64_t> _values;
|
||||||
|
bool _active { false };
|
||||||
|
uint64_t _max { 0 };
|
||||||
|
uint64_t _min { 0 };
|
||||||
|
float _stdDev { 0 };
|
||||||
|
float _mean { 0 };
|
||||||
|
};
|
|
@ -204,6 +204,15 @@ MyAvatar::~MyAvatar() {
|
||||||
_lookAtTargetAvatar.reset();
|
_lookAtTargetAvatar.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) {
|
||||||
|
Avatar::setOrientation(quatFromVariant(newOrientationVar));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant MyAvatar::getOrientationVar() const {
|
||||||
|
return quatToVariant(Avatar::getOrientation());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void MyAvatar::simulateAttachments(float deltaTime) {
|
void MyAvatar::simulateAttachments(float deltaTime) {
|
||||||
// don't update attachments here, do it in harvestResultsFromPhysicsSimulation()
|
// don't update attachments here, do it in harvestResultsFromPhysicsSimulation()
|
||||||
|
|
|
@ -105,6 +105,10 @@ public:
|
||||||
// thread safe
|
// thread safe
|
||||||
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE void setOrientationVar(const QVariant& newOrientationVar);
|
||||||
|
Q_INVOKABLE QVariant getOrientationVar() const;
|
||||||
|
|
||||||
|
|
||||||
// Pass a recent sample of the HMD to the avatar.
|
// Pass a recent sample of the HMD to the avatar.
|
||||||
// This can also update the avatar's position to follow the HMD
|
// This can also update the avatar's position to follow the HMD
|
||||||
// as it moves through the world.
|
// as it moves through the world.
|
||||||
|
|
|
@ -52,7 +52,8 @@ GLBackend::GLTexture::GLTexture(const Texture& texture) :
|
||||||
_target(gpuToGLTextureType(texture)),
|
_target(gpuToGLTextureType(texture)),
|
||||||
_size(0),
|
_size(0),
|
||||||
_virtualSize(0),
|
_virtualSize(0),
|
||||||
_numLevels(texture.maxMip() + 1),
|
_numLevels(1),
|
||||||
|
//_numLevels(texture.maxMip() + 1),
|
||||||
_gpuTexture(texture)
|
_gpuTexture(texture)
|
||||||
{
|
{
|
||||||
Backend::incrementTextureGPUCount();
|
Backend::incrementTextureGPUCount();
|
||||||
|
@ -254,7 +255,7 @@ void GLBackend::GLTexture::transfer() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_gpuTexture.isAutogenerateMips()) {
|
if (_gpuTexture.isAutogenerateMips()) {
|
||||||
glGenerateMipmap(_target);
|
//glGenerateMipmap(_target);
|
||||||
(void)CHECK_GL_ERROR();
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,7 +436,7 @@ void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
|
||||||
glActiveTexture(GL_TEXTURE0 + bindingSlot);
|
glActiveTexture(GL_TEXTURE0 + bindingSlot);
|
||||||
glBindTexture(object->_target, object->_texture);
|
glBindTexture(object->_target, object->_texture);
|
||||||
|
|
||||||
glGenerateMipmap(object->_target);
|
//glGenerateMipmap(object->_target);
|
||||||
|
|
||||||
if (freeSlot < 0) {
|
if (freeSlot < 0) {
|
||||||
// If had to use slot 0 then restore state
|
// If had to use slot 0 then restore state
|
||||||
|
|
Loading…
Reference in a new issue