blob: 79d845870afeba300f663319b1c50287980496d2 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/task.h>
#include <lib/async/cpp/time.h>
#include <lib/fxl/command_line.h>
#include <lib/fxl/log_settings_command_line.h>
#include <lib/fxl/strings/string_number_conversions.h>
#include <trace-provider/provider.h>
#include <trace/event.h>
static constexpr int kDefaultCount = 1;
static constexpr int kDefaultDelaySeconds = 2;
static constexpr int kDefaultDurationSeconds = 10;
static const char* prog_name;
static void PrintHelp(FILE* f) {
fprintf(f, "Usage: %s [options]\n", prog_name);
fprintf(f, "Options:\n");
fprintf(f, " --help Duh ...\n");
fprintf(f, " --count=COUNT Specify number of records per iteration\n");
fprintf(f, " The default is %d.\n", kDefaultCount);
fprintf(f, " --delay=SECONDS Delay SECONDS before starting\n");
fprintf(f, " This is useful until TO-650 is fixed.\n");
fprintf(f, " The default is %d.\n", kDefaultDelaySeconds);
fprintf(f, " --duration=SECONDS Specify time to run, in seconds\n");
fprintf(f, " The default is %d.\n",
kDefaultDurationSeconds);
fprintf(f,
" --quiet[=LEVEL] Set quietness level (opposite of verbose)\n");
fprintf(f, " --verbose[=LEVEL] Set debug verbosity level\n");
}
static void RunStressTestIteration(int count) {
// Simulate some kind of workload.
FXL_LOG(INFO) << "Doing work!";
static const char kSomethingCategory[] = "stress:something";
static const char kWithZeroArgs[] = "with-zero-args";
static const char kWithOneArg[] = "with-one-arg";
static const char kWithTwoArgs[] = "with-two-args";
for (int i = 0; i < count; ++i) {
// Add some variety.
const char* event_name = nullptr;
switch (i % 3) {
case 0:
event_name = kWithZeroArgs;
TRACE_DURATION_BEGIN(kSomethingCategory, event_name);
break;
case 1:
event_name = kWithOneArg;
TRACE_DURATION_BEGIN(kSomethingCategory, event_name, "k1", 1);
break;
case 2:
event_name = kWithTwoArgs;
TRACE_DURATION_BEGIN(kSomethingCategory, event_name, "k1", 1, "k2",
2.0);
break;
default:
__UNREACHABLE;
}
zx::nanosleep(zx::deadline_after(zx::usec(1)));
TRACE_DURATION_END(kSomethingCategory, event_name);
}
}
int main(int argc, char** argv) {
prog_name = argv[0];
auto cl = fxl::CommandLineFromArgcArgv(argc, argv);
if (!fxl::SetLogSettingsFromCommandLine(cl))
return 1;
if (cl.HasOption("help", nullptr)) {
PrintHelp(stdout);
return EXIT_SUCCESS;
}
int count = kDefaultCount;
int delay = kDefaultDelaySeconds;
int duration = kDefaultDurationSeconds;
std::string arg;
if (cl.GetOptionValue("count", &arg)) {
if (!fxl::StringToNumberWithError<int>(arg, &count) || count < 0) {
FXL_LOG(ERROR) << "Invalid count: " << arg;
return EXIT_FAILURE;
}
}
if (cl.GetOptionValue("delay", &arg)) {
if (!fxl::StringToNumberWithError<int>(arg, &delay) || delay < 0) {
FXL_LOG(ERROR) << "Invalid delay: " << arg;
return EXIT_FAILURE;
}
}
if (cl.GetOptionValue("duration", &arg)) {
if (!fxl::StringToNumberWithError<int>(arg, &duration) || duration < 0) {
FXL_LOG(ERROR) << "Invalid duration: " << arg;
return EXIT_FAILURE;
}
}
// Use a separate loop for the provider.
// This is in anticipation of double-buffering support.
async::Loop provider_loop(&kAsyncLoopConfigNoAttachToThread);
provider_loop.StartThread("TraceProvider");
trace::TraceProvider provider(provider_loop.dispatcher());
if (delay > 0) {
FXL_LOG(INFO) << "Trace stressor delaying " << delay << " seconds ...";
zx::nanosleep(zx::deadline_after(zx::sec(delay)));
}
async::Loop loop(&kAsyncLoopConfigAttachToThread);
zx::time start_time = async::Now(loop.dispatcher());
zx::time quit_time = start_time + zx::sec(duration);
FXL_LOG(INFO) << "Trace stressor doing work for " << duration
<< " seconds ...";
int iteration = 0;
async::TaskClosure task([&loop, &task, &iteration, count, quit_time] {
TRACE_DURATION("stress:example", "Doing Work!", "iteration", ++iteration);
RunStressTestIteration(count);
zx::nanosleep(zx::deadline_after(zx::msec(500)));
// Stop if quitting.
zx::time now = async::Now(loop.dispatcher());
if (now > quit_time) {
loop.Quit();
return;
}
// Schedule more work in a little bit.
task.PostForTime(loop.dispatcher(), now + zx::msec(200));
});
task.PostForTime(loop.dispatcher(), start_time);
loop.Run();
FXL_LOG(INFO) << "Trace stressor finished";
// Cleanly shutdown the provider thread.
provider_loop.Quit();
provider_loop.JoinThreads();
return EXIT_SUCCESS;
}