blob: 2cea848498fa5a64806ae40cdeef8270e50d8134 [file] [log] [blame] [edit]
// Copyright 2015 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdio>
#include <map>
#include "base/command_line.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "cobalt/base/c_val.h"
#include "cobalt/base/wrap_main.h"
#include "cobalt/browser/application.h"
#include "cobalt/browser/switches.h"
namespace {
// How many seconds to wait after starting the application before taking the
// snapshot of CVal values.
const int kSecondsToWait = 20;
// The list of CVals we are interested in reporting.
//
// Note that if you add an item to this list, you should also add a column
// to the stats tracking table in the database. Please see the document titled
// "Adding a SnapshotAppStats column" on the Cobalt intranet home page for
// examples on how to add a new column.
// The naming convention for CVal columns in the database are the same as the
// name of the CVal except with the dots removed and the CVal name converted to
// camel case. For example, "DOM.TokenLists" would become "dOMTokenLists".
//
// A document that explains how to modify the database in more detail can be
// found called "Dashboard TDD" on the Cobalt intranet home page.
const char* g_cvals_to_snapshot[] = {
"Count.DOM.Nodes",
"Count.DOM.TokenLists",
"Count.XHR",
"Memory.ArrayBuffer",
"Memory.CPU.Exe",
"Memory.CPU.Used",
"Memory.GraphicsPS3.Fixed.Size",
"Memory.JS",
"Memory.MainWebModule.ImageCache.Size",
"Memory.MainWebModule.RemoteTypefaceCache.Size",
"Memory.Media.AudioDecoder",
"Memory.Media.MediaSource.CPU.Fixed.Capacity",
"Memory.Media.VideoDecoder",
"Memory.XHR",
};
PRINTF_FORMAT(1, 2) void Output(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
std::vfprintf(stdout, fmt, ap);
va_end(ap);
std::fflush(stdout);
}
typedef std::map<std::string, std::string> CValsMap;
// Returns all CVals along with their values.
CValsMap GetAllCValValues() {
base::CValManager* cvm = base::CValManager::GetInstance();
std::set<std::string> cvals = cvm->GetOrderedCValNames();
CValsMap cvals_with_values;
for (std::set<std::string>::iterator iter = cvals.begin();
iter != cvals.end(); ++iter) {
base::Optional<std::string> cval_value = cvm->GetValueAsString(*iter);
if (cval_value) {
cvals_with_values[*iter] = *cval_value;
}
}
return cvals_with_values;
}
// Grab a snapshot of all current CVals and their values and then output them
// so that they can be analyzed by humans and inserted into a database where
// the values can be graphed.
void DoStatsSnapshot(cobalt::browser::Application* application) {
Output("---Benchmark Results Start---\n");
Output("{\n");
Output(" \"LiveYouTubeAfter%dSecondsStatsSnapshot\": {\n", kSecondsToWait);
CValsMap cval_values = GetAllCValValues();
bool have_printed_results = false;
for (size_t i = 0; i < arraysize(g_cvals_to_snapshot); ++i) {
CValsMap::iterator found = cval_values.find(g_cvals_to_snapshot[i]);
if (found != cval_values.end()) {
if (have_printed_results) {
Output(",\n");
} else {
have_printed_results = true;
}
Output(" \"%s\": %s", found->first.c_str(), found->second.c_str());
}
}
Output("\n");
Output(" }\n");
Output("}\n");
Output("---Benchmark Results End---\n");
application->Quit();
}
} // namespace
namespace {
cobalt::browser::Application* g_application = NULL;
base::Thread* g_snapshot_thread = NULL;
void StartApplication(int /*argc*/, char* /*argv*/ [], const char* /*link*/,
const base::Closure& quit_closure) {
logging::SetMinLogLevel(100);
// Use null storage for our savegame so that we don't persist state from
// one run to another, which makes the measurements more deterministic (e.g.
// we will not consistently register for experiments via cookies).
base::CommandLine::ForCurrentProcess()->AppendSwitch(
cobalt::browser::switches::kNullSavegame);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
cobalt::browser::switches::kDebugConsoleMode, "off");
// Create the application object just like is done in the Cobalt main app.
g_application =
new cobalt::browser::Application(quit_closure, false /*should_preload*/);
// Create a thread to start a timer for kSecondsToWait seconds after which
// we will take a snapshot of the CVals at that time and then quit the
// application.
g_snapshot_thread = new base::Thread("StatsSnapshot");
g_snapshot_thread->Start();
g_snapshot_thread->message_loop()->task_runner()->PostDelayedTask(
FROM_HERE, base::Bind(&DoStatsSnapshot, g_application),
base::TimeDelta::FromSeconds(kSecondsToWait));
}
void StopApplication() {
g_snapshot_thread->Stop();
delete g_application;
g_application = NULL;
}
} // namespace
COBALT_WRAP_BASE_MAIN(StartApplication, StopApplication);