Add a sketch of a test_perf script

This script isn't quite working, but it's valuable to checkpoint the work at
this point. I'm coordinating with the chromeperf.appspot.com folks to get the
server to accept the data.

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/702603005
This commit is contained in:
Adam Barth
2014-11-04 16:45:43 -08:00
parent 100f37194c
commit 3d14b06ca9
11 changed files with 183 additions and 157 deletions

View File

@@ -4,14 +4,14 @@ function PerfRunner(options) {
this.iterationsRemaining_ = options.iterations || 10;
this.results_ = [];
this.setup_ = options.setup;
this.logLines_ = [];
}
PerfRunner.prototype.log = function(line) {
console.log(line);
this.logLines_.push(line);
};
PerfRunner.prototype.recordResult = function(result) {
console.log(result);
this.results_.push(result);
};
@@ -82,6 +82,7 @@ PerfRunner.prototype.logStatistics = function(title) {
PerfRunner.prototype.finish = function () {
this.logStatistics("Time:");
internals.notifyTestComplete(this.logLines_.join('\n'));
}
module.exports = PerfRunner;

View File

@@ -8,15 +8,7 @@ import cherrypy
import json
import os
import staticdirindex
BUILD_DIRECTORY = 'out'
CONFIG_DIRECTORY = 'Debug'
SRC_ROOT = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir,
os.pardir))
SKY_ROOT = os.path.join(SRC_ROOT, 'sky')
GEN_ROOT = os.path.join(SRC_ROOT, BUILD_DIRECTORY, CONFIG_DIRECTORY, 'gen')
import skypy.paths as paths
def skydir(section="", dir="", path="", **kwargs):
if cherrypy.request.params.get('format') is None:
@@ -63,15 +55,15 @@ def main():
},
'/mojo/public': {
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.join(GEN_ROOT, 'mojo', 'public'),
'tools.staticdir.dir': os.path.join(paths.GEN_ROOT, 'mojo', 'public'),
},
'/mojo/services': {
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.join(GEN_ROOT, 'mojo', 'services'),
'tools.staticdir.dir': os.path.join(paths.GEN_ROOT, 'mojo', 'services'),
},
'/sky/services': {
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.join(GEN_ROOT, 'sky', 'services'),
'tools.staticdir.dir': os.path.join(paths.GEN_ROOT, 'sky', 'services'),
},
}
cherrypy.quickstart(config=config)

View File

@@ -4,27 +4,22 @@
# found in the LICENSE file.
import argparse
import logging
import os
import skypy.paths as paths
import socket;
import subprocess
import sys
import urlparse
import logging
import socket;
OUT_DIR = 'out'
CONFIG_NAME = 'Debug'
SKY_TOOLS_DIRECTORY = os.path.abspath(os.path.join(__file__, os.pardir))
MOJO_ROOT = os.path.abspath(os.path.join(SKY_TOOLS_DIRECTORY, os.pardir,
os.pardir))
MOJO_SHELL_PATH = os.path.join(MOJO_ROOT, OUT_DIR, CONFIG_NAME, 'mojo_shell')
SUPPORTED_MIME_TYPES = [
'text/html',
'text/sky',
'text/plain',
]
class SkyDebugger(object):
def __init__(self):
self._sky_server = None
@@ -38,8 +33,8 @@ class SkyDebugger(object):
HTTP_PORT = 9999
path = os.path.abspath(path)
if os.path.commonprefix([path, MOJO_ROOT]) == MOJO_ROOT:
server_root = MOJO_ROOT
if os.path.commonprefix([path, paths.SRC_ROOT]) == paths.SRC_ROOT:
server_root = paths.SRC_ROOT
else:
server_root = os.path.dirname(path)
logging.warn(
@@ -53,7 +48,7 @@ class SkyDebugger(object):
HTTP_PORT)
else:
server_command = [
os.path.join(SKY_TOOLS_DIRECTORY, 'sky_server'),
os.path.join(paths.SKY_TOOLS_DIRECTORY, 'sky_server'),
server_root,
str(HTTP_PORT),
]
@@ -72,7 +67,7 @@ class SkyDebugger(object):
content_handlers = ['%s,%s' % (mime_type, 'mojo://sky_viewer/')
for mime_type in SUPPORTED_MIME_TYPES]
shell_command = [
MOJO_SHELL_PATH,
paths.MOJO_SHELL_PATH,
'--v=1',
'--content-handlers=%s' % ','.join(content_handlers),
'--url-mappings=mojo:window_manager=mojo:sky_debugger',

View File

@@ -0,0 +1,3 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

View File

@@ -0,0 +1,14 @@
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
BUILD_DIRECTORY = 'out'
CONFIG_DIRECTORY = 'Debug'
SRC_ROOT = os.path.abspath(os.path.join(__file__,
os.pardir, os.pardir, os.pardir, os.pardir))
SKY_ROOT = os.path.join(SRC_ROOT, 'sky')
GEN_ROOT = os.path.join(SRC_ROOT, BUILD_DIRECTORY, CONFIG_DIRECTORY, 'gen')
SKY_TOOLS_DIRECTORY = os.path.join(SRC_ROOT, 'sky', 'tools')
MOJO_SHELL_PATH = os.path.join(SRC_ROOT, BUILD_DIRECTORY, CONFIG_DIRECTORY, 'mojo_shell')

View File

@@ -1,40 +1,110 @@
#!/usr/bin/env python
# Copyright (C) 2012 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Run performance tests."""
import os
import re
import skypy.paths as paths
import subprocess
import requests
import logging
import sys
from webkitpy.performance_tests.perftestsrunner import PerfTestsRunner
SUPPORTED_MIME_TYPES = [
'text/html',
'text/sky',
'text/plain',
]
HTTP_PORT = 9999
if '__main__' == __name__:
logging.basicConfig(level=logging.INFO, format="%(message)s")
DASHBOARD_URL = 'https://chromeperf.appspot.com/add_point'
sys.exit(PerfTestsRunner().run())
def sky_tester_command(url):
content_handlers = ['%s,%s' % (mime_type, 'mojo://sky_viewer/')
for mime_type in SUPPORTED_MIME_TYPES]
return [
paths.MOJO_SHELL_PATH,
'--args-for=mojo://native_viewport_service/ --use-headless-config --use-osmesa',
'--args-for=mojo://window_manager/ %s' % url,
'--content-handlers=%s' % ','.join(content_handlers),
'--url-mappings=mojo:window_manager=mojo://sky_tester/',
'mojo:window_manager',
]
def start_sky_server(port):
return subprocess.Popen([
os.path.join(paths.SKY_TOOLS_DIRECTORY, 'sky_server'),
paths.SRC_ROOT,
str(port),
])
def values_from_output(output):
# Parse out the raw values from the PerfRunner output:
# values 90, 89, 93 ms
# We'll probably need a fancier parser at some point.
match = re.search(r'values (.+) ms', output, flags=re.MULTILINE)
return map(float, match.group(1).split(', '))
def create_json_blob(values):
revision = subprocess.check_output(["git", "show-ref", "HEAD", "-s"]).strip()
return {
"master": "master.mojo.perf",
"bot": "sky-release",
"point_id": 123456, # FIXME: We need to generate a monotonicly increasing number somehow.
"versions": {
"mojo": revision
},
"chart_data": {
"format_version": "1.0",
"benchmark_name": "layout.simple-blocks",
"charts": {
"warm_times": {
"traces": {
"layout.simple-blocks": {
"type": "list_of_scalar_values",
"values": values,
},
}
}
}
}
}
def send_json_to_dashboard(json):
requests.post(DASHBOARD_URL, params={ 'data': json })
class PerfHarness(object):
def __init__(self):
self._sky_server = None
def _start_server(self):
self._sky_server = start_sky_server(HTTP_PORT)
def main(self):
test = 'http://localhost:9999/sky/benchmarks/layout/simple-blocks.sky'
self._start_server()
output = subprocess.check_output(sky_tester_command(test))
values = values_from_output(output)
json = create_json_blob(values)
send_json_to_dashboard(json)
def shutdown(self):
if self._sky_server:
self._sky_server.terminate()
if __name__ == '__main__':
harness = PerfHarness()
try:
harness.main()
except (KeyboardInterrupt, SystemExit):
pass
finally:
harness.shutdown()

View File

@@ -6,8 +6,6 @@ shared_library("tester") {
output_name = "sky_tester"
sources = [
"test_harness.cc",
"test_harness.h",
"test_observer_impl.cc",
"test_observer_impl.h",
"test_runner.cc",

View File

@@ -1,49 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sky/tools/tester/test_harness.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include <iostream>
namespace sky {
namespace tester {
namespace {
std::string WaitForURL() {
std::string url;
std::cin >> url;
return url;
}
} // namespace
TestHarness::TestHarness(mojo::View* container)
: container_(container),
weak_ptr_factory_(this) {
std::cout << "#READY\n";
std::cout.flush();
}
TestHarness::~TestHarness() {
}
void TestHarness::ScheduleRun() {
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&TestHarness::Run, weak_ptr_factory_.GetWeakPtr()));
}
void TestHarness::Run() {
DCHECK(!test_runner_);
test_runner_.reset(new TestRunner(this, container_, WaitForURL()));
}
void TestHarness::OnTestComplete() {
test_runner_.reset();
ScheduleRun();
}
} // namespace tester
} // namespace sky

View File

@@ -1,39 +0,0 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SKY_TOOLS_TESTER_TEST_HARNESS_H_
#define SKY_TOOLS_TESTER_TEST_HARNESS_H_
#include "base/memory/weak_ptr.h"
#include "sky/tools/tester/test_runner.h"
namespace mojo{
class View;
}
namespace sky {
namespace tester {
class TestHarness : public TestRunnerClient {
public:
explicit TestHarness(mojo::View* container);
virtual ~TestHarness();
void ScheduleRun();
private:
void Run();
void OnTestComplete() override;
mojo::View* container_;
scoped_ptr<TestRunner> test_runner_;
base::WeakPtrFactory<TestHarness> weak_ptr_factory_;
MOJO_DISALLOW_COPY_AND_ASSIGN(TestHarness);
};
} // namespace tester
} // namespace sky
#endif // SKY_TOOLS_TESTER_TEST_HARNESS_H_

View File

@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <iostream>
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "mojo/application/application_runner_chromium.h"
#include "mojo/public/c/system/main.h"
#include "mojo/public/cpp/application/application_delegate.h"
@@ -14,27 +17,41 @@
#include "mojo/services/public/interfaces/input_events/input_events.mojom.h"
#include "mojo/services/window_manager/window_manager_app.h"
#include "mojo/services/window_manager/window_manager_delegate.h"
#include "sky/tools/tester/test_harness.h"
#include "sky/tools/tester/test_runner.h"
namespace sky {
namespace tester {
namespace {
std::string WaitForURL() {
std::string url;
std::cin >> url;
return url;
}
} // namespace
class SkyTester : public mojo::ApplicationDelegate,
public mojo::ViewManagerDelegate,
public mojo::WindowManagerDelegate,
public mojo::ViewObserver {
public mojo::ViewObserver,
public TestRunnerClient {
public:
SkyTester()
: window_manager_app_(new mojo::WindowManagerApp(this, this)),
view_manager_(NULL),
root_(NULL),
content_(NULL) {}
content_(NULL),
weak_ptr_factory_(this) {}
virtual ~SkyTester() {}
private:
// Overridden from mojo::ApplicationDelegate:
virtual void Initialize(mojo::ApplicationImpl* impl) override {
window_manager_app_->Initialize(impl);
if (impl->args().size() >= 2)
url_from_args_ = impl->args()[1];
}
virtual bool ConfigureIncomingConnection(
mojo::ApplicationConnection* connection) override {
@@ -56,8 +73,9 @@ class SkyTester : public mojo::ApplicationDelegate,
content_->SetBounds(root_->bounds());
root_->AddChild(content_);
test_harness_.reset(new TestHarness(content_));
test_harness_->ScheduleRun();
std::cout << "#READY\n";
std::cout.flush();
ScheduleRun();
}
// Overridden from WindowManagerDelegate:
@@ -82,12 +100,35 @@ class SkyTester : public mojo::ApplicationDelegate,
content_->SetBounds(new_bounds);
}
void ScheduleRun() {
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&SkyTester::Run, weak_ptr_factory_.GetWeakPtr()));
}
void Run() {
DCHECK(!test_runner_);
std::string url = url_from_args_.length() ? url_from_args_ : WaitForURL();
test_runner_.reset(new TestRunner(this, content_, url));
}
void OnTestComplete() override {
test_runner_.reset();
if (url_from_args_.length())
exit(0);
ScheduleRun();
}
scoped_ptr<mojo::WindowManagerApp> window_manager_app_;
std::string url_from_args_;
mojo::ViewManager* view_manager_;
mojo::View* root_;
mojo::View* content_;
scoped_ptr<TestHarness> test_harness_;
scoped_ptr<TestRunner> test_runner_;
base::WeakPtrFactory<SkyTester> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SkyTester);
};