blob: acccded4a51021083c2b5fc1fa5e6e628e6944d7 [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
Ben Chan9953a592014-02-05 23:32:00 -08007#include <base/strings/string_split.h>
Simon Que21bb7902014-07-28 16:17:20 -07008#include <base/strings/string_util.h>
9
10#include <algorithm>
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070011
12#include "cpu_info_parser.h"
Ahmad Sharifae1714d2013-01-17 11:29:37 -080013#include "process_with_output.h"
14
Ben Chan55903dd2014-04-24 00:29:04 -070015using base::StringPrintf;
16
Ahmad Shariff5597f62013-04-25 12:25:41 -070017namespace {
18
19// Location of quipper on ChromeOS.
20const char kQuipperLocation[] = "/usr/bin/quipper";
21
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070022// This is the key in /proc/cpuinfo whose value is the model name of the CPU.
23const char kCPUModelNameKey[] = "model name";
Ahmad Shariff5597f62013-04-25 12:25:41 -070024
Simon Que21bb7902014-07-28 16:17:20 -070025// This is registered trademark symbol that appears in model name strings.
26const char kRegisteredTrademarkSymbol[] = "(R)";
27
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070028// Processor model name substrings for which we have perf commands.
29const char* kCPUOddsFiles[] = {
30 "unknown",
31 "core",
Simon Que21bb7902014-07-28 16:17:20 -070032 "celeron-2955u",
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070033 "arm",
34};
Ahmad Shariff5597f62013-04-25 12:25:41 -070035
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070036// Prefix path to attach to the CPU odds file.
Ahmad Sharifbdb33912013-07-16 11:44:49 -040037const char kCPUOddsFilePrefix[] = "/etc/perf_commands/";
Ahmad Shariff5597f62013-04-25 12:25:41 -070038
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070039// Suffix to attach to the CPU odds file.
40const char kCPUOddsFileSuffix[] = ".txt";
Ahmad Shariff5597f62013-04-25 12:25:41 -070041
Simon Que21bb7902014-07-28 16:17:20 -070042// Converts an CPU model name string into a format that can be used as a file
43// name. The rules are:
44// - Replace spaces with hyphens.
45// - Strip all "(R)" symbols.
46// - Convert to lower case.
47std::string ModelNameToFileName(const std::string& model_name) {
48 std::string result = model_name;
49 std::replace(result.begin(), result.end(), ' ', '-');
50 ReplaceSubstringsAfterOffset(&result, 0, kRegisteredTrademarkSymbol, "");
51 return StringToLowerASCII(result);
52}
53
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070054// Goes through the list of kCPUOddsFiles, and if the any of those strings is a
55// substring of the |cpu_model_name|, returns that string. If no matches are
56// found, returns the first string of |kCPUOddsFiles| ("unknown").
57void GetOddsFilenameForCPU(const std::string& cpu_model_name,
58 std::string* odds_filename) {
Simon Que21bb7902014-07-28 16:17:20 -070059 std::string adjusted_model_name = ModelNameToFileName(cpu_model_name);
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070060 for (size_t i = 0; i < arraysize(kCPUOddsFiles); ++i) {
Simon Que21bb7902014-07-28 16:17:20 -070061 if (adjusted_model_name.find(kCPUOddsFiles[i]) != std::string::npos) {
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070062 *odds_filename = kCPUOddsFiles[i];
63 return;
64 }
65 }
66 *odds_filename = kCPUOddsFiles[0];
Ahmad Shariff5597f62013-04-25 12:25:41 -070067}
68
69} // namespace
70
Ahmad Sharifae1714d2013-01-17 11:29:37 -080071namespace debugd {
72
Ahmad Shariff5597f62013-04-25 12:25:41 -070073PerfTool::PerfTool() {
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070074 std::string cpu_model_name;
75 debugd::CPUInfoParser cpu_info_parser;
76 cpu_info_parser.GetKey(kCPUModelNameKey, &cpu_model_name);
77 std::string odds_filename;
78 GetOddsFilenameForCPU(cpu_model_name, &odds_filename);
Ben Chana0011d82014-05-13 00:19:29 -070079 std::string odds_file_path =
80 std::string(kCPUOddsFilePrefix) + odds_filename + kCPUOddsFileSuffix;
Ahmad Sharif3abea3c2013-05-13 20:43:04 -070081 random_selector_.SetOddsFromFile(odds_file_path);
Ahmad Shariff5597f62013-04-25 12:25:41 -070082}
Ahmad Sharifae1714d2013-01-17 11:29:37 -080083
84PerfTool::~PerfTool() { }
85
Ahmad Shariff5597f62013-04-25 12:25:41 -070086std::vector<uint8> PerfTool::GetRichPerfData(const uint32_t& duration_secs,
Ben Chana0011d82014-05-13 00:19:29 -070087 DBus::Error* error) {
Ahmad Shariff5597f62013-04-25 12:25:41 -070088 std::string perf_command_line;
89 random_selector_.GetNext(&perf_command_line);
90 std::string output_string;
91 GetPerfDataHelper(duration_secs, perf_command_line, error, &output_string);
92 return std::vector<uint8>(output_string.begin(), output_string.end());
93}
94
95void PerfTool::GetPerfDataHelper(const uint32_t& duration_secs,
96 const std::string& perf_command_line,
Ben Chana0011d82014-05-13 00:19:29 -070097 DBus::Error* error,
98 std::string* data_string) {
Ahmad Sharifae1714d2013-01-17 11:29:37 -080099 // This whole method is synchronous, so we create a subprocess, let it run to
100 // completion, then gather up its output to return it.
101 ProcessWithOutput process;
102 process.SandboxAs("root", "root");
103 if (!process.Init())
104 *data_string = "<process init failed>";
105 // If you're going to add switches to a command, have a look at the Process
106 // interface; there's support for adding options specifically.
Ahmad Shariff5597f62013-04-25 12:25:41 -0700107 process.AddArg(kQuipperLocation);
108 process.AddArg(StringPrintf("%u", duration_secs));
109 process.AddArg(perf_command_line);
Ahmad Sharifae1714d2013-01-17 11:29:37 -0800110 // Run the process to completion. If the process might take a while, you may
111 // have to make this asynchronous using .Start().
112 int status = process.Run();
113 if (status != 0)
114 *data_string = StringPrintf("<process exited with status: %d", status);
115 process.GetOutput(data_string);
116}
117
Ben Chana0011d82014-05-13 00:19:29 -0700118} // namespace debugd