Skip to content

Commit 59d3e1d

Browse files
thanmGerrit Code Review
authored andcommitted
Merge "Support for additional profile annotations."
2 parents bd827df + 8c7c7db commit 59d3e1d

File tree

8 files changed

+651
-286
lines changed

8 files changed

+651
-286
lines changed

perfprofd/Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ LOCAL_SRC_FILES := \
2929
quipper/perf_reader.cc \
3030
quipper/perf_parser.cc \
3131
perf_data_converter.cc \
32+
configreader.cc \
3233
cpuconfig.cc \
3334
perfprofdcore.cc \
3435

perfprofd/configreader.cc

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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 <stdio.h>
19+
#include <stdlib.h>
20+
#include <sstream>
21+
22+
#include <base/file.h>
23+
24+
#include "configreader.h"
25+
#include "perfprofdutils.h"
26+
27+
//
28+
// Config file path
29+
//
30+
static const char *config_file_path =
31+
"/data/data/com.google.android.gms/files/perfprofd.conf";
32+
33+
ConfigReader::ConfigReader()
34+
: trace_config_read(false)
35+
{
36+
addDefaultEntries();
37+
}
38+
39+
ConfigReader::~ConfigReader()
40+
{
41+
}
42+
43+
const char *ConfigReader::getConfigFilePath()
44+
{
45+
return config_file_path;
46+
}
47+
48+
void ConfigReader::setConfigFilePath(const char *path)
49+
{
50+
config_file_path = strdup(path);
51+
W_ALOGI("config file path set to %s", config_file_path);
52+
}
53+
54+
//
55+
// Populate the reader with the set of allowable entries
56+
//
57+
void ConfigReader::addDefaultEntries()
58+
{
59+
// Average number of seconds between perf profile collections (if
60+
// set to 100, then over time we want to see a perf profile
61+
// collected every 100 seconds). The actual time within the interval
62+
// for the collection is chosen randomly.
63+
addUnsignedEntry("collection_interval", 14400, 100, UINT32_MAX);
64+
65+
// Use the specified fixed seed for random number generation (unit
66+
// testing)
67+
addUnsignedEntry("use_fixed_seed", 0, 0, UINT32_MAX);
68+
69+
// For testing purposes, number of times to iterate through main
70+
// loop. Value of zero indicates that we should loop forever.
71+
addUnsignedEntry("main_loop_iterations", 0, 0, UINT32_MAX);
72+
73+
// Destination directory (where to write profiles). This location
74+
// chosen since it is accessible to the uploader service.
75+
addStringEntry("destination_directory", "/data/misc/perfprofd");
76+
77+
// Config directory (where to read configs).
78+
addStringEntry("config_directory", "/data/data/com.google.android.gms/files");
79+
80+
// Full path to 'perf' executable.
81+
addStringEntry("perf_path", "/system/xbin/simpleperf");
82+
83+
// Desired sampling period (passed to perf -c option). Small
84+
// sampling periods can perturb the collected profiles, so enforce
85+
// min/max.
86+
addUnsignedEntry("sampling_period", 500000, 5000, UINT32_MAX);
87+
88+
// Length of time to collect samples (number of seconds for 'perf
89+
// record -a' run).
90+
addUnsignedEntry("sample_duration", 3, 2, 600);
91+
92+
// If this parameter is non-zero it will cause perfprofd to
93+
// exit immediately if the build type is not userdebug or eng.
94+
// Currently defaults to 1 (true).
95+
addUnsignedEntry("only_debug_build", 1, 0, 1);
96+
97+
// If the "mpdecision" service is running at the point we are ready
98+
// to kick off a profiling run, then temporarily disable the service
99+
// and hard-wire all cores on prior to the collection run, provided
100+
// that the duration of the recording is less than or equal to the value of
101+
// 'hardwire_cpus_max_duration'.
102+
addUnsignedEntry("hardwire_cpus", 1, 0, 1);
103+
addUnsignedEntry("hardwire_cpus_max_duration", 5, 1, UINT32_MAX);
104+
105+
// Maximum number of unprocessed profiles we can accumulate in the
106+
// destination directory. Once we reach this limit, we continue
107+
// to collect, but we just overwrite the most recent profile.
108+
addUnsignedEntry("max_unprocessed_profiles", 10, 1, UINT32_MAX);
109+
110+
// If set to 1, pass the -g option when invoking 'perf' (requests
111+
// stack traces as opposed to flat profile).
112+
addUnsignedEntry("stack_profile", 0, 0, 1);
113+
114+
// For unit testing only: if set to 1, emit info messages on config
115+
// file parsing.
116+
addUnsignedEntry("trace_config_read", 0, 0, 1);
117+
118+
// Control collection of various additional profile tags
119+
addUnsignedEntry("collect_cpu_utilization", 1, 0, 1);
120+
addUnsignedEntry("collect_charging_state", 1, 0, 1);
121+
addUnsignedEntry("collect_booting", 1, 0, 1);
122+
addUnsignedEntry("collect_camera_active", 0, 0, 1);
123+
}
124+
125+
void ConfigReader::addUnsignedEntry(const char *key,
126+
unsigned default_value,
127+
unsigned min_value,
128+
unsigned max_value)
129+
{
130+
std::string ks(key);
131+
if (u_entries.find(ks) != u_entries.end() ||
132+
s_entries.find(ks) != s_entries.end()) {
133+
W_ALOGE("internal error -- duplicate entry for key %s", key);
134+
exit(9);
135+
}
136+
values vals;
137+
vals.minv = min_value;
138+
vals.maxv = max_value;
139+
u_info[ks] = vals;
140+
u_entries[ks] = default_value;
141+
}
142+
143+
void ConfigReader::addStringEntry(const char *key, const char *default_value)
144+
{
145+
std::string ks(key);
146+
if (u_entries.find(ks) != u_entries.end() ||
147+
s_entries.find(ks) != s_entries.end()) {
148+
W_ALOGE("internal error -- duplicate entry for key %s", key);
149+
exit(9);
150+
}
151+
if (default_value == nullptr) {
152+
W_ALOGE("internal error -- bad default value for key %s", key);
153+
exit(9);
154+
}
155+
s_entries[ks] = std::string(default_value);
156+
}
157+
158+
unsigned ConfigReader::getUnsignedValue(const char *key) const
159+
{
160+
std::string ks(key);
161+
auto it = u_entries.find(ks);
162+
assert(it != u_entries.end());
163+
return it->second;
164+
}
165+
166+
std::string ConfigReader::getStringValue(const char *key) const
167+
{
168+
std::string ks(key);
169+
auto it = s_entries.find(ks);
170+
assert(it != s_entries.end());
171+
return it->second;
172+
}
173+
174+
void ConfigReader::overrideUnsignedEntry(const char *key, unsigned new_value)
175+
{
176+
std::string ks(key);
177+
auto it = u_entries.find(ks);
178+
assert(it != u_entries.end());
179+
values vals;
180+
auto iit = u_info.find(key);
181+
assert(iit != u_info.end());
182+
vals = iit->second;
183+
assert(new_value >= vals.minv && new_value <= vals.maxv);
184+
it->second = new_value;
185+
W_ALOGI("option %s overridden to %u", key, new_value);
186+
}
187+
188+
189+
//
190+
// Parse a key=value pair read from the config file. This will issue
191+
// warnings or errors to the system logs if the line can't be
192+
// interpreted properly.
193+
//
194+
void ConfigReader::parseLine(const char *key,
195+
const char *value,
196+
unsigned linecount)
197+
{
198+
assert(key);
199+
assert(value);
200+
201+
auto uit = u_entries.find(key);
202+
if (uit != u_entries.end()) {
203+
unsigned uvalue = 0;
204+
if (isdigit(value[0]) == 0 || sscanf(value, "%u", &uvalue) != 1) {
205+
W_ALOGW("line %d: malformed unsigned value (ignored)", linecount);
206+
} else {
207+
values vals;
208+
auto iit = u_info.find(key);
209+
assert(iit != u_info.end());
210+
vals = iit->second;
211+
if (uvalue < vals.minv || uvalue > vals.maxv) {
212+
W_ALOGW("line %d: specified value %u for '%s' "
213+
"outside permitted range [%u %u] (ignored)",
214+
linecount, uvalue, key, vals.minv, vals.maxv);
215+
} else {
216+
if (trace_config_read) {
217+
W_ALOGI("option %s set to %u", key, uvalue);
218+
}
219+
uit->second = uvalue;
220+
}
221+
}
222+
trace_config_read = (getUnsignedValue("trace_config_read") != 0);
223+
return;
224+
}
225+
226+
auto sit = s_entries.find(key);
227+
if (sit != s_entries.end()) {
228+
if (trace_config_read) {
229+
W_ALOGI("option %s set to %s", key, value);
230+
}
231+
sit->second = std::string(value);
232+
return;
233+
}
234+
235+
W_ALOGW("line %d: unknown option '%s' ignored", linecount, key);
236+
}
237+
238+
static bool isblank(const std::string &line)
239+
{
240+
for (std::string::const_iterator it = line.begin(); it != line.end(); ++it)
241+
{
242+
if (isspace(*it) == 0) {
243+
return false;
244+
}
245+
}
246+
return true;
247+
}
248+
249+
bool ConfigReader::readFile()
250+
{
251+
std::string contents;
252+
if (! android::base::ReadFileToString(config_file_path, &contents)) {
253+
return false;
254+
}
255+
256+
std::stringstream ss(contents);
257+
std::string line;
258+
for (unsigned linecount = 1;
259+
std::getline(ss,line,'\n');
260+
linecount += 1)
261+
{
262+
263+
// comment line?
264+
if (line[0] == '#') {
265+
continue;
266+
}
267+
268+
// blank line?
269+
if (isblank(line.c_str())) {
270+
continue;
271+
}
272+
273+
// look for X=Y assignment
274+
auto efound = line.find('=');
275+
if (efound == std::string::npos) {
276+
W_ALOGW("line %d: line malformed (no '=' found)", linecount);
277+
continue;
278+
}
279+
280+
std::string key(line.substr(0, efound));
281+
std::string value(line.substr(efound+1, std::string::npos));
282+
283+
parseLine(key.c_str(), value.c_str(), linecount);
284+
}
285+
286+
return true;
287+
}

perfprofd/configreader.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
#ifndef SYSTEM_EXTRAS_PERFPROFD_CONFIGREADER_H_
19+
#define SYSTEM_EXTRAS_PERFPROFD_CONFIGREADER_H_
20+
21+
#include <string>
22+
#include <map>
23+
24+
//
25+
// This table describes the perfprofd config file syntax in terms of
26+
// key/value pairs. Values come in two flavors: strings, or unsigned
27+
// integers. In the latter case the reader sets allowable
28+
// minimum/maximum for the setting.
29+
//
30+
class ConfigReader {
31+
32+
public:
33+
ConfigReader();
34+
~ConfigReader();
35+
36+
// Ask for the current setting of a config item
37+
unsigned getUnsignedValue(const char *key) const;
38+
std::string getStringValue(const char *key) const;
39+
40+
// read the specified config file, applying any settings it contains
41+
// returns true for successful read, false if conf file cannot be opened.
42+
bool readFile();
43+
44+
// set/get path to config file
45+
static void setConfigFilePath(const char *path);
46+
static const char *getConfigFilePath();
47+
48+
// override a config item (for unit testing purposes)
49+
void overrideUnsignedEntry(const char *key, unsigned new_value);
50+
51+
private:
52+
void addUnsignedEntry(const char *key,
53+
unsigned default_value,
54+
unsigned min_value,
55+
unsigned max_value);
56+
void addStringEntry(const char *key, const char *default_value);
57+
void addDefaultEntries();
58+
void parseLine(const char *key, const char *value, unsigned linecount);
59+
60+
typedef struct { unsigned minv, maxv; } values;
61+
std::map<std::string, values> u_info;
62+
std::map<std::string, unsigned> u_entries;
63+
std::map<std::string, std::string> s_entries;
64+
bool trace_config_read;
65+
};
66+
67+
#endif

perfprofd/perf_profile.proto

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,19 @@ message AndroidPerfProfile {
9999
// to first value from /proc/loadavg multiplied by 100 then
100100
// converted to int32
101101
optional int32 sys_load_average = 6;
102+
103+
// At the point when the profile was collected, was a camera active?
104+
optional bool camera_active = 7;
105+
106+
// At the point when the profile was collected, was the device still booting?
107+
optional bool booting = 8;
108+
109+
// At the point when the profile was collected, was the device plugged into
110+
// a charger?
111+
optional bool on_charger = 9;
112+
113+
// CPU utilization measured prior to profile collection (expressed as
114+
// 100 minus the idle percentage).
115+
optional int32 cpu_utilization = 10;
116+
102117
}

0 commit comments

Comments
 (0)