blob: 1c7909b30ba4bd65469e34f53f2464c66b911bf5 [file] [log] [blame]
Ahmad Sharifae1714d2013-01-17 11:29:37 -08001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Alex Vakulenko262be3f2014-07-30 15:25:50 -07005#include "debugd/src/perf_tool.h"
Ahmad Sharifae1714d2013-01-17 11:29:37 -08006
David Sharpe01f7252015-06-30 16:24:05 -07007#include <base/strings/string_number_conversions.h>
Ben Chan9953a592014-02-05 23:32:00 -08008#include <base/strings/string_split.h>
Simon Que21bb7902014-07-28 16:17:20 -07009#include <base/strings/string_util.h>
Simon Que795327b2015-03-16 17:42:35 -070010#include <sys/utsname.h>
Simon Que21bb7902014-07-28 16:17:20 -070011
12#include <algorithm>
David Sharpe01f7252015-06-30 16:24:05 -070013#include <map>
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070014
Alex Vakulenko262be3f2014-07-30 15:25:50 -070015#include "debugd/src/process_with_output.h"
Ahmad Sharifae1714d2013-01-17 11:29:37 -080016
Ben Chan55903dd2014-04-24 00:29:04 -070017using base::StringPrintf;
18
David Sharpe01f7252015-06-30 16:24:05 -070019namespace debugd {
20
Ahmad Shariff5597f62013-04-25 12:25:41 -070021namespace {
22
David Sharp61901312015-08-05 13:32:07 -070023const char kUnsupportedPerfToolErrorName[] =
24 "org.chromium.debugd.error.UnsupportedPerfTool";
25
Ahmad Shariff5597f62013-04-25 12:25:41 -070026// Location of quipper on ChromeOS.
27const char kQuipperLocation[] = "/usr/bin/quipper";
28
Simon Queecb08352015-10-02 17:38:12 -070029enum PerfSubcommand {
30 PERF_COMMAND_RECORD,
31 PERF_COMMAND_STAT,
32 PERF_COMMAND_MEM,
33 PERF_COMMAND_UNSUPPORTED,
34};
35
36// Returns one of the above enums given an vector of perf arguments, starting
37// with "perf" itself in |args[0]|.
38PerfSubcommand GetPerfSubcommandType(const std::vector<std::string>& args) {
39 if (args[0] == "perf" && args.size() > 1) {
40 if (args[1] == "record")
41 return PERF_COMMAND_RECORD;
42 if (args[1] == "stat")
43 return PERF_COMMAND_STAT;
44 if (args[1] == "mem")
45 return PERF_COMMAND_MEM;
46 }
47
48 return PERF_COMMAND_UNSUPPORTED;
49}
50
Ahmad Shariff5597f62013-04-25 12:25:41 -070051} // namespace
52
David Sharp131e86b2015-11-17 12:55:31 -080053PerfTool::PerfTool() {}
Ahmad Sharifae1714d2013-01-17 11:29:37 -080054
David Sharp61901312015-08-05 13:32:07 -070055int PerfTool::GetPerfOutput(const uint32_t& duration_secs,
56 const std::vector<std::string>& perf_args,
57 std::vector<uint8_t>* perf_data,
58 std::vector<uint8_t>* perf_stat,
59 DBus::Error* error) {
Simon Queecb08352015-10-02 17:38:12 -070060 PerfSubcommand subcommand = GetPerfSubcommandType(perf_args);
61 if (subcommand == PERF_COMMAND_UNSUPPORTED) {
David Sharp61901312015-08-05 13:32:07 -070062 error->set(kUnsupportedPerfToolErrorName,
Simon Queecb08352015-10-02 17:38:12 -070063 "perf_args must begin with {\"perf\", \"record\"}, "
64 " {\"perf\", \"stat\"}, or {\"perf\", \"mem\"}");
David Sharp61901312015-08-05 13:32:07 -070065 return -1;
66 }
67
Simon Queac5f9cf2015-06-20 13:50:22 -070068 std::string output_string;
69 int result =
70 GetPerfOutputHelper(duration_secs, perf_args, error, &output_string);
71
Simon Queecb08352015-10-02 17:38:12 -070072 switch (subcommand) {
73 case PERF_COMMAND_RECORD:
74 case PERF_COMMAND_MEM:
Simon Queac5f9cf2015-06-20 13:50:22 -070075 perf_data->assign(output_string.begin(), output_string.end());
Simon Queecb08352015-10-02 17:38:12 -070076 break;
77 case PERF_COMMAND_STAT:
Simon Queac5f9cf2015-06-20 13:50:22 -070078 perf_stat->assign(output_string.begin(), output_string.end());
Simon Queecb08352015-10-02 17:38:12 -070079 break;
80 default:
81 // Discard the output.
82 break;
83 }
Simon Queac5f9cf2015-06-20 13:50:22 -070084
85 return result;
86}
87
Simon Queac5f9cf2015-06-20 13:50:22 -070088int PerfTool::GetPerfOutputHelper(const uint32_t& duration_secs,
89 const std::vector<std::string>& perf_args,
90 DBus::Error* error,
91 std::string* data_string) {
Ahmad Sharifae1714d2013-01-17 11:29:37 -080092 // This whole method is synchronous, so we create a subprocess, let it run to
93 // completion, then gather up its output to return it.
94 ProcessWithOutput process;
95 process.SandboxAs("root", "root");
96 if (!process.Init())
97 *data_string = "<process init failed>";
98 // If you're going to add switches to a command, have a look at the Process
99 // interface; there's support for adding options specifically.
Ahmad Shariff5597f62013-04-25 12:25:41 -0700100 process.AddArg(kQuipperLocation);
101 process.AddArg(StringPrintf("%u", duration_secs));
David Sharpdada3d02015-02-09 18:24:48 -0800102 for (const auto& arg : perf_args) {
103 process.AddArg(arg);
104 }
Ahmad Sharifae1714d2013-01-17 11:29:37 -0800105 // Run the process to completion. If the process might take a while, you may
106 // have to make this asynchronous using .Start().
107 int status = process.Run();
108 if (status != 0)
109 *data_string = StringPrintf("<process exited with status: %d", status);
110 process.GetOutput(data_string);
Simon Queac5f9cf2015-06-20 13:50:22 -0700111
112 return status;
Ahmad Sharifae1714d2013-01-17 11:29:37 -0800113}
114
Ben Chana0011d82014-05-13 00:19:29 -0700115} // namespace debugd