OSDN Git Service

Merge "Fix Darwin build (by not building)."
[android-x86/system-extras.git] / perfprofd / configreader.cc
1 /*
2 **
3 ** Copyright 2015, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include <assert.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #include <algorithm>
23 #include <cstring>
24 #include <sstream>
25
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28
29 #include "configreader.h"
30
31 //
32 // Config file path
33 //
34 static const char *config_file_path =
35     "/data/data/com.google.android.gms/files/perfprofd.conf";
36
37 ConfigReader::ConfigReader()
38     : trace_config_read(false)
39 {
40   addDefaultEntries();
41 }
42
43 ConfigReader::~ConfigReader()
44 {
45 }
46
47 const char *ConfigReader::getConfigFilePath()
48 {
49   return config_file_path;
50 }
51
52 void ConfigReader::setConfigFilePath(const char *path)
53 {
54   config_file_path = strdup(path);
55   LOG(INFO) << "config file path set to " << config_file_path;
56 }
57
58 //
59 // Populate the reader with the set of allowable entries
60 //
61 void ConfigReader::addDefaultEntries()
62 {
63   // Average number of seconds between perf profile collections (if
64   // set to 100, then over time we want to see a perf profile
65   // collected every 100 seconds). The actual time within the interval
66   // for the collection is chosen randomly.
67   addUnsignedEntry("collection_interval", 14400, 100, UINT32_MAX);
68
69   // Use the specified fixed seed for random number generation (unit
70   // testing)
71   addUnsignedEntry("use_fixed_seed", 0, 0, UINT32_MAX);
72
73   // For testing purposes, number of times to iterate through main
74   // loop.  Value of zero indicates that we should loop forever.
75   addUnsignedEntry("main_loop_iterations", 0, 0, UINT32_MAX);
76
77   // Destination directory (where to write profiles). This location
78   // chosen since it is accessible to the uploader service.
79   addStringEntry("destination_directory", "/data/misc/perfprofd");
80
81   // Config directory (where to read configs).
82   addStringEntry("config_directory", "/data/data/com.google.android.gms/files");
83
84   // Full path to 'perf' executable.
85   addStringEntry("perf_path", "/system/xbin/simpleperf");
86
87   // Desired sampling period (passed to perf -c option). Small
88   // sampling periods can perturb the collected profiles, so enforce
89   // min/max.
90   addUnsignedEntry("sampling_period", 500000, 5000, UINT32_MAX);
91
92   // Length of time to collect samples (number of seconds for 'perf
93   // record -a' run).
94   addUnsignedEntry("sample_duration", 3, 2, 600);
95
96   // If this parameter is non-zero it will cause perfprofd to
97   // exit immediately if the build type is not userdebug or eng.
98   // Currently defaults to 1 (true).
99   addUnsignedEntry("only_debug_build", 1, 0, 1);
100
101   // If the "mpdecision" service is running at the point we are ready
102   // to kick off a profiling run, then temporarily disable the service
103   // and hard-wire all cores on prior to the collection run, provided
104   // that the duration of the recording is less than or equal to the value of
105   // 'hardwire_cpus_max_duration'.
106   addUnsignedEntry("hardwire_cpus", 1, 0, 1);
107   addUnsignedEntry("hardwire_cpus_max_duration", 5, 1, UINT32_MAX);
108
109   // Maximum number of unprocessed profiles we can accumulate in the
110   // destination directory. Once we reach this limit, we continue
111   // to collect, but we just overwrite the most recent profile.
112   addUnsignedEntry("max_unprocessed_profiles", 10, 1, UINT32_MAX);
113
114   // If set to 1, pass the -g option when invoking 'perf' (requests
115   // stack traces as opposed to flat profile).
116   addUnsignedEntry("stack_profile", 0, 0, 1);
117
118   // For unit testing only: if set to 1, emit info messages on config
119   // file parsing.
120   addUnsignedEntry("trace_config_read", 0, 0, 1);
121
122   // Control collection of various additional profile tags
123   addUnsignedEntry("collect_cpu_utilization", 1, 0, 1);
124   addUnsignedEntry("collect_charging_state", 1, 0, 1);
125   addUnsignedEntry("collect_booting", 1, 0, 1);
126   addUnsignedEntry("collect_camera_active", 0, 0, 1);
127
128   // If true, use an ELF symbolizer to on-device symbolize.
129   addUnsignedEntry("use_elf_symbolizer", 1, 0, 1);
130
131   // If true, use libz to compress the output proto.
132   addUnsignedEntry("compress", 0, 0, 1);
133
134   // If true, send the proto to dropbox instead to a file.
135   addUnsignedEntry("dropbox", 0, 0, 1);
136 }
137
138 void ConfigReader::addUnsignedEntry(const char *key,
139                                     unsigned default_value,
140                                     unsigned min_value,
141                                     unsigned max_value)
142 {
143   std::string ks(key);
144   CHECK(u_entries.find(ks) == u_entries.end() &&
145         s_entries.find(ks) == s_entries.end())
146       << "internal error -- duplicate entry for key " << key;
147   values vals;
148   vals.minv = min_value;
149   vals.maxv = max_value;
150   u_info[ks] = vals;
151   u_entries[ks] = default_value;
152 }
153
154 void ConfigReader::addStringEntry(const char *key, const char *default_value)
155 {
156   std::string ks(key);
157   CHECK(u_entries.find(ks) == u_entries.end() &&
158         s_entries.find(ks) == s_entries.end())
159       << "internal error -- duplicate entry for key " << key;
160   CHECK(default_value != nullptr) << "internal error -- bad default value for key " << key;
161   s_entries[ks] = std::string(default_value);
162 }
163
164 unsigned ConfigReader::getUnsignedValue(const char *key) const
165 {
166   std::string ks(key);
167   auto it = u_entries.find(ks);
168   CHECK(it != u_entries.end());
169   return it->second;
170 }
171
172 bool ConfigReader::getBoolValue(const char *key) const
173 {
174   std::string ks(key);
175   auto it = u_entries.find(ks);
176   CHECK(it != u_entries.end());
177   return it->second != 0;
178 }
179
180 std::string ConfigReader::getStringValue(const char *key) const
181 {
182   std::string ks(key);
183   auto it = s_entries.find(ks);
184   CHECK(it != s_entries.end());
185   return it->second;
186 }
187
188 void ConfigReader::overrideUnsignedEntry(const char *key, unsigned new_value)
189 {
190   std::string ks(key);
191   auto it = u_entries.find(ks);
192   CHECK(it != u_entries.end());
193   values vals;
194   auto iit = u_info.find(key);
195   CHECK(iit != u_info.end());
196   vals = iit->second;
197   CHECK(new_value >= vals.minv && new_value <= vals.maxv);
198   it->second = new_value;
199   LOG(INFO) << "option " << key << " overridden to " << new_value;
200 }
201
202
203 //
204 // Parse a key=value pair read from the config file. This will issue
205 // warnings or errors to the system logs if the line can't be
206 // interpreted properly.
207 //
208 void ConfigReader::parseLine(const char *key,
209                              const char *value,
210                              unsigned linecount)
211 {
212   assert(key);
213   assert(value);
214
215   auto uit = u_entries.find(key);
216   if (uit != u_entries.end()) {
217     unsigned uvalue = 0;
218     if (isdigit(value[0]) == 0 || sscanf(value, "%u", &uvalue) != 1) {
219       LOG(WARNING) << "line " << linecount << ": malformed unsigned value (ignored)";
220     } else {
221       values vals;
222       auto iit = u_info.find(key);
223       assert(iit != u_info.end());
224       vals = iit->second;
225       if (uvalue < vals.minv || uvalue > vals.maxv) {
226         LOG(WARNING) << "line " << linecount << ": "
227                      << "specified value " << uvalue << " for '" << key << "' "
228                      << "outside permitted range [" << vals.minv << " " << vals.maxv
229                      << "] (ignored)";
230       } else {
231         if (trace_config_read) {
232           LOG(INFO) << "option " << key << " set to " << uvalue;
233         }
234         uit->second = uvalue;
235       }
236     }
237     trace_config_read = (getUnsignedValue("trace_config_read") != 0);
238     return;
239   }
240
241   auto sit = s_entries.find(key);
242   if (sit != s_entries.end()) {
243     if (trace_config_read) {
244       LOG(INFO) << "option " << key << " set to " << value;
245     }
246     sit->second = std::string(value);
247     return;
248   }
249
250   LOG(WARNING) << "line " << linecount << ": unknown option '" << key << "' ignored";
251 }
252
253 static bool isblank(const std::string &line)
254 {
255   auto non_space = [](char c) { return isspace(c) == 0; };
256   return std::find_if(line.begin(), line.end(), non_space) == line.end();
257 }
258
259 bool ConfigReader::readFile()
260 {
261   std::string contents;
262   if (! android::base::ReadFileToString(config_file_path, &contents)) {
263     return false;
264   }
265
266   std::stringstream ss(contents);
267   std::string line;
268   for (unsigned linecount = 1;
269        std::getline(ss,line,'\n');
270        linecount += 1)
271   {
272
273     // comment line?
274     if (line[0] == '#') {
275       continue;
276     }
277
278     // blank line?
279     if (isblank(line.c_str())) {
280       continue;
281     }
282
283     // look for X=Y assignment
284     auto efound = line.find('=');
285     if (efound == std::string::npos) {
286       LOG(WARNING) << "line " << linecount << ": line malformed (no '=' found)";
287       continue;
288     }
289
290     std::string key(line.substr(0, efound));
291     std::string value(line.substr(efound+1, std::string::npos));
292
293     parseLine(key.c_str(), value.c_str(), linecount);
294   }
295
296   return true;
297 }
298
299 void ConfigReader::FillConfig(Config* config) {
300   config->collection_interval_in_s = getUnsignedValue("collection_interval");
301
302   config->use_fixed_seed = getUnsignedValue("use_fixed_seed");
303
304   config->main_loop_iterations = getUnsignedValue("main_loop_iterations");
305
306   config->destination_directory = getStringValue("destination_directory");
307
308   config->config_directory = getStringValue("config_directory");
309
310   config->perf_path = getStringValue("perf_path");
311
312   config->sampling_period = getUnsignedValue("sampling_period");
313
314   config->sample_duration_in_s = getUnsignedValue("sample_duration");
315
316   config->only_debug_build = getBoolValue("only_debug_build");
317
318   config->hardwire_cpus = getBoolValue("hardwire_cpus");
319   config->hardwire_cpus_max_duration_in_s = getUnsignedValue("hardwire_cpus_max_duration");
320
321   config->max_unprocessed_profiles = getUnsignedValue("max_unprocessed_profiles");
322
323   config->stack_profile = getBoolValue("stack_profile");
324
325   config->trace_config_read = getBoolValue("trace_config_read");
326
327   config->collect_cpu_utilization = getBoolValue("collect_cpu_utilization");
328   config->collect_charging_state = getBoolValue("collect_charging_state");
329   config->collect_booting = getBoolValue("collect_booting");
330   config->collect_camera_active = getBoolValue("collect_camera_active");
331
332   config->process = -1;
333   config->use_elf_symbolizer = getBoolValue("use_elf_symbolizer");
334   config->compress = getBoolValue("compress");
335   config->send_to_dropbox = getBoolValue("dropbox");
336 }