blob: bc13459515227c38b1257ab934ea05cbb0df5755 [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
5#include "perf_tool.h"
6
Ahmad Sharif3abea3c2013-05-13 20:43:04 -07007#include <fstream>
8
Ben Chan9953a592014-02-05 23:32:00 -08009#include <base/strings/string_split.h>
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070010
11#include "cpu_info_parser.h"
Ahmad Sharifae1714d2013-01-17 11:29:37 -080012#include "process_with_output.h"
13
Ben Chan55903dd2014-04-24 00:29:04 -070014using base::StringPrintf;
15
Ahmad Shariff5597f62013-04-25 12:25:41 -070016namespace {
17
18// Location of quipper on ChromeOS.
19const char kQuipperLocation[] = "/usr/bin/quipper";
20
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070021// This is the key in /proc/cpuinfo whose value is the model name of the CPU.
22const char kCPUModelNameKey[] = "model name";
Ahmad Shariff5597f62013-04-25 12:25:41 -070023
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070024// Processor model name substrings for which we have perf commands.
25const char* kCPUOddsFiles[] = {
26 "unknown",
27 "core",
28 "arm",
29};
Ahmad Shariff5597f62013-04-25 12:25:41 -070030
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070031// Prefix path to attach to the CPU odds file.
Ahmad Sharifbdb33912013-07-16 11:44:49 -040032const char kCPUOddsFilePrefix[] = "/etc/perf_commands/";
Ahmad Shariff5597f62013-04-25 12:25:41 -070033
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070034// Suffix to attach to the CPU odds file.
35const char kCPUOddsFileSuffix[] = ".txt";
Ahmad Shariff5597f62013-04-25 12:25:41 -070036
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070037// Goes through the list of kCPUOddsFiles, and if the any of those strings is a
38// substring of the |cpu_model_name|, returns that string. If no matches are
39// found, returns the first string of |kCPUOddsFiles| ("unknown").
40void GetOddsFilenameForCPU(const std::string& cpu_model_name,
41 std::string* odds_filename) {
42 std::string lowered_cpu_model_name = StringToLowerASCII(cpu_model_name);
43 for (size_t i = 0; i < arraysize(kCPUOddsFiles); ++i) {
44 if (lowered_cpu_model_name.find(kCPUOddsFiles[i]) != std::string::npos) {
45 *odds_filename = kCPUOddsFiles[i];
46 return;
47 }
48 }
49 *odds_filename = kCPUOddsFiles[0];
Ahmad Shariff5597f62013-04-25 12:25:41 -070050}
51
52} // namespace
53
Ahmad Sharifae1714d2013-01-17 11:29:37 -080054namespace debugd {
55
Ahmad Shariff5597f62013-04-25 12:25:41 -070056PerfTool::PerfTool() {
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070057 std::string cpu_model_name;
58 debugd::CPUInfoParser cpu_info_parser;
59 cpu_info_parser.GetKey(kCPUModelNameKey, &cpu_model_name);
60 std::string odds_filename;
61 GetOddsFilenameForCPU(cpu_model_name, &odds_filename);
62 std::string odds_file_path = std::string(kCPUOddsFilePrefix) +
63 odds_filename +
64 kCPUOddsFileSuffix;
65 random_selector_.SetOddsFromFile(odds_file_path);
Ahmad Shariff5597f62013-04-25 12:25:41 -070066}
Ahmad Sharifae1714d2013-01-17 11:29:37 -080067
68PerfTool::~PerfTool() { }
69
70// Tool methods have the same signature as the generated DBus adaptors. Most
71// pertinently, this means they take their DBus::Error argument as a non-const
72// reference (hence the NOLINT). Tool methods are generally written in
73// can't-fail style, since their output is usually going to be displayed to the
74// user; instead of returning a DBus exception, we tend to return a string
75// indicating what went wrong.
Ahmad Shariff5597f62013-04-25 12:25:41 -070076std::vector<uint8> PerfTool::GetRichPerfData(const uint32_t& duration_secs,
77 DBus::Error& error) { // NOLINT
78 std::string perf_command_line;
79 random_selector_.GetNext(&perf_command_line);
80 std::string output_string;
81 GetPerfDataHelper(duration_secs, perf_command_line, error, &output_string);
82 return std::vector<uint8>(output_string.begin(), output_string.end());
83}
84
85void PerfTool::GetPerfDataHelper(const uint32_t& duration_secs,
86 const std::string& perf_command_line,
Ahmad Sharifae1714d2013-01-17 11:29:37 -080087 DBus::Error& error,
88 std::string* data_string) { // NOLINT
Ahmad Sharifae1714d2013-01-17 11:29:37 -080089 // This whole method is synchronous, so we create a subprocess, let it run to
90 // completion, then gather up its output to return it.
91 ProcessWithOutput process;
92 process.SandboxAs("root", "root");
93 if (!process.Init())
94 *data_string = "<process init failed>";
95 // If you're going to add switches to a command, have a look at the Process
96 // interface; there's support for adding options specifically.
Ahmad Shariff5597f62013-04-25 12:25:41 -070097 process.AddArg(kQuipperLocation);
98 process.AddArg(StringPrintf("%u", duration_secs));
99 process.AddArg(perf_command_line);
Ahmad Sharifae1714d2013-01-17 11:29:37 -0800100 // Run the process to completion. If the process might take a while, you may
101 // have to make this asynchronous using .Start().
102 int status = process.Run();
103 if (status != 0)
104 *data_string = StringPrintf("<process exited with status: %d", status);
105 process.GetOutput(data_string);
106}
107
108}; // namespace debugd
109