summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2018-03-30 02:56:08 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-03-30 02:56:08 +0000
commit09ad261e387886214bb2fae25ac6d3ace18d898b (patch)
treeb575aeed51c6ab0c75ac85bd72414d18eb7389eb
parentcd3c54452bd0fab8214f8915313c83ac46d9c697 (diff)
parent7f85bff629e68efd3f5127fc43edddcadfecb007 (diff)
downloadextras-09ad261e387886214bb2fae25ac6d3ace18d898b.tar.gz
Merge changes I3415d7c1,I0931a59c,Iae2a74f8,I2cad55f2
* changes: Perfprofd: Move dropbox functionality into core Perfprofd: Move proto to its own static library Perfprofd: Factor out the command-line-based loop Perfprofd: Move dropbox code to its own static library
-rw-r--r--perfprofd/Android.bp45
-rw-r--r--perfprofd/binder_interface/Android.bp3
-rw-r--r--perfprofd/binder_interface/perfprofd_binder.cc82
-rw-r--r--perfprofd/config.h3
-rw-r--r--perfprofd/configreader.cc4
-rw-r--r--perfprofd/dropbox/Android.bp52
-rw-r--r--perfprofd/dropbox/dropbox.cc129
-rw-r--r--perfprofd/dropbox/dropbox.h37
-rw-r--r--perfprofd/dropbox/dropbox_host.cc35
-rw-r--r--perfprofd/perfprofd_cmdline.cc255
-rw-r--r--perfprofd/perfprofd_cmdline.h39
-rw-r--r--perfprofd/perfprofdcore.cc244
-rw-r--r--perfprofd/perfprofdcore.h21
-rw-r--r--perfprofd/perfprofdmain.cc1
-rw-r--r--perfprofd/tests/Android.bp5
-rw-r--r--perfprofd/tests/perfprofd_test.cc1
16 files changed, 633 insertions, 323 deletions
diff --git a/perfprofd/Android.bp b/perfprofd/Android.bp
index 9b55fbda..243477a3 100644
--- a/perfprofd/Android.bp
+++ b/perfprofd/Android.bp
@@ -66,6 +66,41 @@ cc_defaults {
}
}
+// Static library for the record proto and its I/O.
+
+cc_library_static {
+ name: "libperfprofd_record_proto",
+ defaults: [
+ "perfprofd_defaults",
+ ],
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+
+ static_libs: [
+ "libbase",
+ "libprotobuf-cpp-lite",
+ "libquipper",
+ "libz",
+ ],
+ srcs: [
+ "perfprofd_io.cc",
+ "perfprofd_record.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ include_dirs: ["external/perf_data_converter/src/quipper"],
+ type: "lite",
+ },
+
+ export_include_dirs: ["."], // Really only the -fwd.h.
+ export_static_lib_headers: ["libquipper"],
+}
+
//
// Static library containing guts of AWP daemon.
//
@@ -87,23 +122,19 @@ cc_defaults {
"libsimpleperf_elf_read",
],
whole_static_libs: [
+ "libperfprofd_dropbox",
+ "libperfprofd_record_proto",
"libquipper",
],
srcs: [
- "perfprofd_record.proto",
"perf_data_converter.cc",
"configreader.cc",
"cpuconfig.cc",
"perfprofdcore.cc",
- "perfprofd_io.cc",
+ "perfprofd_cmdline.cc",
"symbolizer.cc"
],
- proto: {
- export_proto_headers: true,
- include_dirs: ["external/perf_data_converter/src/quipper"],
- type: "lite",
- },
cflags: [
"-Wno-gnu-anonymous-struct",
],
diff --git a/perfprofd/binder_interface/Android.bp b/perfprofd/binder_interface/Android.bp
index d7bff41b..c40036bd 100644
--- a/perfprofd/binder_interface/Android.bp
+++ b/perfprofd/binder_interface/Android.bp
@@ -30,9 +30,6 @@ cc_library_static {
"libperfprofdcore",
"libprotobuf-cpp-lite",
],
- shared_libs: [
- "libservices",
- ],
srcs: [
"perfprofd_binder.cc",
":perfprofd_aidl",
diff --git a/perfprofd/binder_interface/perfprofd_binder.cc b/perfprofd/binder_interface/perfprofd_binder.cc
index eeb53602..87e0c5f6 100644
--- a/perfprofd/binder_interface/perfprofd_binder.cc
+++ b/perfprofd/binder_interface/perfprofd_binder.cc
@@ -35,7 +35,6 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
-#include <android/os/DropBoxManager.h>
#include <binder/BinderService.h>
#include <binder/IResultReceiver.h>
#include <binder/Status.h>
@@ -49,6 +48,7 @@
#include "perfprofd_record.pb.h"
#include "config.h"
+#include "dropbox.h"
#include "perfprofdcore.h"
#include "perfprofd_io.h"
@@ -60,8 +60,6 @@ using Status = ::android::binder::Status;
class BinderConfig : public Config {
public:
- bool send_to_dropbox = false;
-
bool is_profiling = false;
void Sleep(size_t seconds) override {
@@ -97,8 +95,6 @@ class BinderConfig : public Config {
// Copy base fields.
*static_cast<Config*>(this) = static_cast<const Config&>(rhs);
- send_to_dropbox = rhs.send_to_dropbox;
-
return *this;
}
@@ -151,79 +147,21 @@ class PerfProfdNativeService : public BinderService<PerfProfdNativeService>,
int seq_ = 0;
};
-static Status WriteDropboxFile(android::perfprofd::PerfprofdRecord* encodedProfile,
- Config* config) {
- android::base::unique_fd tmp_fd;
- {
- char path[PATH_MAX];
- snprintf(path,
- sizeof(path),
- "%s%cdropboxtmp-XXXXXX",
- config->destination_directory.c_str(),
- OS_PATH_SEPARATOR);
- tmp_fd.reset(mkstemp(path));
- if (tmp_fd.get() == -1) {
- PLOG(ERROR) << "Could not create temp file " << path;
- return Status::fromExceptionCode(1, "Could not create temp file");
- }
- if (unlink(path) != 0) {
- PLOG(WARNING) << "Could not unlink binder temp file";
- }
- }
-
- // Dropbox takes ownership of the fd, and if it is not readonly,
- // a selinux violation will occur. Get a read-only version.
- android::base::unique_fd read_only;
- {
- char fdpath[64];
- snprintf(fdpath, arraysize(fdpath), "/proc/self/fd/%d", tmp_fd.get());
- read_only.reset(open(fdpath, O_RDONLY | O_CLOEXEC));
- if (read_only.get() < 0) {
- PLOG(ERROR) << "Could not create read-only fd";
- return Status::fromExceptionCode(1, "Could not create read-only fd");
- }
- }
-
- constexpr bool kCompress = true; // Ignore the config here. Dropbox will always end up
- // compressing the data, might as well make the temp
- // file smaller and help it out.
- using DropBoxManager = android::os::DropBoxManager;
- constexpr int kDropboxFlags = DropBoxManager::IS_GZIPPED;
-
- if (!SerializeProtobuf(encodedProfile, std::move(tmp_fd), kCompress)) {
- return Status::fromExceptionCode(1, "Could not serialize to temp file");
- }
-
- sp<DropBoxManager> dropbox(new DropBoxManager());
- return dropbox->addFile(String16("perfprofd"), read_only.release(), kDropboxFlags);
-}
-
bool PerfProfdNativeService::BinderHandler(
android::perfprofd::PerfprofdRecord* encodedProfile,
Config* config) {
CHECK(config != nullptr);
+ if (encodedProfile == nullptr) {
+ return false;
+ }
+
if (static_cast<BinderConfig*>(config)->send_to_dropbox) {
- size_t size = encodedProfile->ByteSize();
- Status status;
- if (size < 1024 * 1024) {
- // For a small size, send as a byte buffer directly.
- std::unique_ptr<uint8_t[]> data(new uint8_t[size]);
- encodedProfile->SerializeWithCachedSizesToArray(data.get());
-
- using DropBoxManager = android::os::DropBoxManager;
- sp<DropBoxManager> dropbox(new DropBoxManager());
- status = dropbox->addData(String16("perfprofd"),
- data.get(),
- size,
- 0);
- } else {
- // For larger buffers, we need to go through the filesystem.
- status = WriteDropboxFile(encodedProfile, config);
+ std::string error_msg;
+ if (!dropbox::SendToDropbox(encodedProfile, config->destination_directory, &error_msg)) {
+ LOG(WARNING) << "Failed dropbox submission: " << error_msg;
+ return false;
}
- if (!status.isOk()) {
- LOG(WARNING) << "Failed dropbox submission: " << status.toString8();
- }
- return status.isOk();
+ return true;
}
if (encodedProfile == nullptr) {
diff --git a/perfprofd/config.h b/perfprofd/config.h
index 4c1f12b1..774f7e86 100644
--- a/perfprofd/config.h
+++ b/perfprofd/config.h
@@ -96,6 +96,9 @@ struct Config {
// If true, use libz to compress the output proto.
bool compress = true;
+ // If true, send the proto to dropbox instead to a file.
+ bool send_to_dropbox = false;
+
// Sleep for the given number of seconds.
virtual void Sleep(size_t seconds) = 0;
diff --git a/perfprofd/configreader.cc b/perfprofd/configreader.cc
index f7d6fd29..d3396b33 100644
--- a/perfprofd/configreader.cc
+++ b/perfprofd/configreader.cc
@@ -130,6 +130,9 @@ void ConfigReader::addDefaultEntries()
// If true, use libz to compress the output proto.
addUnsignedEntry("compress", 0, 0, 1);
+
+ // If true, send the proto to dropbox instead to a file.
+ addUnsignedEntry("dropbox", 0, 0, 1);
}
void ConfigReader::addUnsignedEntry(const char *key,
@@ -329,4 +332,5 @@ void ConfigReader::FillConfig(Config* config) {
config->process = -1;
config->use_elf_symbolizer = getBoolValue("use_elf_symbolizer");
config->compress = getBoolValue("compress");
+ config->send_to_dropbox = getBoolValue("dropbox");
}
diff --git a/perfprofd/dropbox/Android.bp b/perfprofd/dropbox/Android.bp
new file mode 100644
index 00000000..c3b8f3b8
--- /dev/null
+++ b/perfprofd/dropbox/Android.bp
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// Static library for dropbox submission.
+//
+cc_library_static {
+ name: "libperfprofd_dropbox",
+ defaults: [
+ "perfprofd_defaults",
+ ],
+ host_supported: true,
+
+ export_include_dirs: ["."],
+ static_libs: [
+ "libbase",
+ "libperfprofd_record_proto",
+ "libprotobuf-cpp-lite",
+ ],
+ target: {
+ android: {
+ srcs: [
+ "dropbox.cc",
+ ],
+ static_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ shared_libs: [
+ "libservices",
+ ],
+ },
+ host: {
+ srcs: [
+ "dropbox_host.cc",
+ ],
+ },
+ },
+}
diff --git a/perfprofd/dropbox/dropbox.cc b/perfprofd/dropbox/dropbox.cc
new file mode 100644
index 00000000..2b1dc2ef
--- /dev/null
+++ b/perfprofd/dropbox/dropbox.cc
@@ -0,0 +1,129 @@
+/*
+ *
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dropbox.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android/os/DropBoxManager.h>
+#include <binder/Status.h>
+#include <utils/String8.h>
+
+#include "perfprofd_record.pb.h"
+
+#include "perfprofd_io.h"
+
+namespace android {
+namespace perfprofd {
+namespace dropbox {
+
+namespace {
+
+bool WriteDropboxFile(android::perfprofd::PerfprofdRecord* encodedProfile,
+ const std::string& temp_dir,
+ std::string* error_msg) {
+ android::base::unique_fd tmp_fd;
+ {
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "%s/dropboxtmp-XXXXXX", temp_dir.c_str());
+ tmp_fd.reset(mkstemp(path));
+ if (tmp_fd.get() == -1) {
+ *error_msg = android::base::StringPrintf("Could not create temp file %s: %s",
+ path,
+ strerror(errno));
+ return false;
+ }
+ if (unlink(path) != 0) {
+ PLOG(WARNING) << "Could not unlink binder temp file";
+ }
+ }
+
+ // Dropbox takes ownership of the fd, and if it is not readonly,
+ // a selinux violation will occur. Get a read-only version.
+ android::base::unique_fd read_only;
+ {
+ char fdpath[64];
+ snprintf(fdpath, arraysize(fdpath), "/proc/self/fd/%d", tmp_fd.get());
+ read_only.reset(open(fdpath, O_RDONLY | O_CLOEXEC));
+ if (read_only.get() < 0) {
+ *error_msg = android::base::StringPrintf("Could not create read-only fd: %s",
+ strerror(errno));
+ return false;
+ }
+ }
+
+ constexpr bool kCompress = true; // Ignore the config here. Dropbox will always end up
+ // compressing the data, might as well make the temp
+ // file smaller and help it out.
+ using DropBoxManager = android::os::DropBoxManager;
+ constexpr int kDropboxFlags = DropBoxManager::IS_GZIPPED;
+
+ if (!SerializeProtobuf(encodedProfile, std::move(tmp_fd), kCompress)) {
+ *error_msg = "Could not serialize to temp file";
+ return false;
+ }
+
+ sp<DropBoxManager> dropbox(new DropBoxManager());
+ android::binder::Status status = dropbox->addFile(String16("perfprofd"),
+ read_only.release(),
+ kDropboxFlags);
+ if (!status.isOk()) {
+ *error_msg = status.toString8();
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+bool SendToDropbox(android::perfprofd::PerfprofdRecord* profile,
+ const std::string& temp_directory,
+ std::string* error_msg) {
+ size_t size = profile->ByteSize();
+ if (size < 1024 * 1024) {
+ // For a small size, send as a byte buffer directly.
+ std::unique_ptr<uint8_t[]> data(new uint8_t[size]);
+ profile->SerializeWithCachedSizesToArray(data.get());
+
+ using DropBoxManager = android::os::DropBoxManager;
+ sp<DropBoxManager> dropbox(new DropBoxManager());
+ android::binder::Status status = dropbox->addData(String16("perfprofd"),
+ data.get(),
+ size,
+ 0);
+ if (!status.isOk()) {
+ *error_msg = status.toString8();
+ return false;
+ }
+ return true;
+ } else {
+ // For larger buffers, we need to go through the filesystem.
+ return WriteDropboxFile(profile, temp_directory, error_msg);
+ }
+}
+
+} // namespace dropbox
+} // namespace perfprofd
+} // namespace android
diff --git a/perfprofd/dropbox/dropbox.h b/perfprofd/dropbox/dropbox.h
new file mode 100644
index 00000000..b25d2cc2
--- /dev/null
+++ b/perfprofd/dropbox/dropbox.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_EXTRAS_PERFPROFD_DROPBOX_DROPBOX_H_
+#define SYSTEM_EXTRAS_PERFPROFD_DROPBOX_DROPBOX_H_
+
+#include <string>
+
+#include "perfprofd_record-fwd.h"
+
+namespace android {
+namespace perfprofd {
+namespace dropbox {
+
+bool SendToDropbox(android::perfprofd::PerfprofdRecord* profile,
+ const std::string& temp_directory,
+ std::string* error_msg);
+
+} // namespace dropbox
+} // namespace perfprofd
+} // namespace android
+
+#endif // SYSTEM_EXTRAS_PERFPROFD_DROPBOX_DROPBOX_H_
diff --git a/perfprofd/dropbox/dropbox_host.cc b/perfprofd/dropbox/dropbox_host.cc
new file mode 100644
index 00000000..5c08aa85
--- /dev/null
+++ b/perfprofd/dropbox/dropbox_host.cc
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dropbox.h"
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace perfprofd {
+namespace dropbox {
+
+bool SendToDropbox(android::perfprofd::PerfprofdRecord* profile,
+ const std::string& temp_directory ATTRIBUTE_UNUSED,
+ std::string* error_msg) {
+ *error_msg = "Dropbox not supported on host";
+ return false;
+}
+
+} // namespace dropbox
+} // namespace perfprofd
+} // namespace android
diff --git a/perfprofd/perfprofd_cmdline.cc b/perfprofd/perfprofd_cmdline.cc
new file mode 100644
index 00000000..fb9c2c17
--- /dev/null
+++ b/perfprofd/perfprofd_cmdline.cc
@@ -0,0 +1,255 @@
+/*
+ *
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfprofd_cmdline.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <set>
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+
+#include "perfprofd_record.pb.h"
+
+#include "configreader.h"
+#include "dropbox.h"
+#include "perfprofdcore.h"
+#include "perfprofd_io.h"
+
+//
+// Perf profiling daemon -- collects system-wide profiles using
+//
+// simpleperf record -a
+//
+// and encodes them so that they can be uploaded by a separate service.
+//
+
+//
+
+//
+// Output file from 'perf record'.
+//
+#define PERF_OUTPUT "perf.data"
+
+//
+// Path to the perf file to convert and exit? Empty value is the default, daemon mode.
+//
+static std::string perf_file_to_convert = "";
+
+//
+// SIGHUP handler. Sending SIGHUP to the daemon can be used to break it
+// out of a sleep() call so as to trigger a new collection (debugging)
+//
+static void sig_hup(int /* signum */)
+{
+ LOG(WARNING) << "SIGHUP received";
+}
+
+//
+// Parse command line args. Currently supported flags:
+// * "-c PATH" sets the path of the config file to PATH.
+// * "-x PATH" reads PATH as a perf data file and saves it as a file in
+// perf_profile.proto format. ".encoded" suffix is appended to PATH to form
+// the output file path.
+//
+static void parse_args(int argc, char** argv)
+{
+ int ac;
+
+ for (ac = 1; ac < argc; ++ac) {
+ if (!strcmp(argv[ac], "-c")) {
+ if (ac >= argc-1) {
+ LOG(ERROR) << "malformed command line: -c option requires argument)";
+ continue;
+ }
+ ConfigReader::setConfigFilePath(argv[ac+1]);
+ ++ac;
+ } else if (!strcmp(argv[ac], "-x")) {
+ if (ac >= argc-1) {
+ LOG(ERROR) << "malformed command line: -x option requires argument)";
+ continue;
+ }
+ perf_file_to_convert = argv[ac+1];
+ ++ac;
+ } else {
+ LOG(ERROR) << "malformed command line: unknown option or arg " << argv[ac] << ")";
+ continue;
+ }
+ }
+}
+
+//
+// Post-processes after profile is collected and converted to protobuf.
+// * GMS core stores processed file sequence numbers in
+// /data/data/com.google.android.gms/files/perfprofd_processed.txt
+// * Update /data/misc/perfprofd/perfprofd_produced.txt to remove the sequence
+// numbers that have been processed and append the current seq number
+// Returns true if the current_seq should increment.
+//
+static bool post_process(const Config& config, int current_seq)
+{
+ const std::string& dest_dir = config.destination_directory;
+ std::string processed_file_path =
+ config.config_directory + "/" + PROCESSED_FILENAME;
+ std::string produced_file_path = dest_dir + "/" + PRODUCED_FILENAME;
+
+
+ std::set<int> processed;
+ FILE *fp = fopen(processed_file_path.c_str(), "r");
+ if (fp != NULL) {
+ int seq;
+ while(fscanf(fp, "%d\n", &seq) > 0) {
+ if (remove(android::base::StringPrintf(
+ "%s/perf.data.encoded.%d", dest_dir.c_str(),seq).c_str()) == 0) {
+ processed.insert(seq);
+ }
+ }
+ fclose(fp);
+ }
+
+ std::set<int> produced;
+ fp = fopen(produced_file_path.c_str(), "r");
+ if (fp != NULL) {
+ int seq;
+ while(fscanf(fp, "%d\n", &seq) > 0) {
+ if (processed.find(seq) == processed.end()) {
+ produced.insert(seq);
+ }
+ }
+ fclose(fp);
+ }
+
+ uint32_t maxLive = config.max_unprocessed_profiles;
+ if (produced.size() >= maxLive) {
+ return false;
+ }
+
+ produced.insert(current_seq);
+ fp = fopen(produced_file_path.c_str(), "w");
+ if (fp == NULL) {
+ PLOG(WARNING) << "Cannot write " << produced_file_path;
+ return false;
+ }
+ for (std::set<int>::const_iterator iter = produced.begin();
+ iter != produced.end(); ++iter) {
+ fprintf(fp, "%d\n", *iter);
+ }
+ fclose(fp);
+ chmod(produced_file_path.c_str(),
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
+ return true;
+}
+
+//
+// Initialization
+//
+
+static void init(ConfigReader &config)
+{
+ if (!config.readFile()) {
+ LOG(ERROR) << "unable to open configuration file " << config.getConfigFilePath();
+ }
+
+ CommonInit(static_cast<uint32_t>(config.getUnsignedValue("use_fixed_seed")),
+ config.getStringValue("destination_directory").c_str());
+
+ signal(SIGHUP, sig_hup);
+}
+
+//
+// Main routine:
+// 1. parse cmd line args
+// 2. read config file
+// 3. loop: {
+// sleep for a while
+// perform a profile collection
+// }
+//
+int perfprofd_main(int argc, char** argv, Config* config)
+{
+ ConfigReader config_reader;
+
+ LOG(INFO) << "starting Android Wide Profiling daemon";
+
+ parse_args(argc, argv);
+ init(config_reader);
+ config_reader.FillConfig(config);
+
+ if (!perf_file_to_convert.empty()) {
+ std::string encoded_path = perf_file_to_convert + ".encoded";
+ encode_to_proto(perf_file_to_convert, encoded_path.c_str(), *config, 0, nullptr);
+ return 0;
+ }
+
+ // Early exit if we're not supposed to run on this build flavor
+ if (!IsDebugBuild() && config->only_debug_build) {
+ LOG(INFO) << "early exit due to inappropriate build type";
+ return 0;
+ }
+
+ auto config_fn = [config]() {
+ return config;
+ };
+ auto reread_config = [&config_reader, config]() {
+ // Reread config file -- the uploader may have rewritten it as a result
+ // of a gservices change
+ config_reader.readFile();
+ config_reader.FillConfig(config);
+ };
+ int seq = 0;
+ auto handler = [&seq](android::perfprofd::PerfprofdRecord* proto, Config* handler_config) {
+ if (proto == nullptr) {
+ return false;
+ }
+ if (handler_config->send_to_dropbox) {
+ std::string error_msg;
+ if (!android::perfprofd::dropbox::SendToDropbox(proto,
+ handler_config->destination_directory,
+ &error_msg)) {
+ LOG(ERROR) << "Failed dropbox submission: " << error_msg;
+ return false;
+ }
+ } else {
+ std::string data_file_path(handler_config->destination_directory);
+ data_file_path += "/";
+ data_file_path += PERF_OUTPUT;
+ std::string path = android::base::StringPrintf("%s.encoded.%d", data_file_path.c_str(), seq);
+ if (!android::perfprofd::SerializeProtobuf(proto, path.c_str(), handler_config->compress)) {
+ return false;
+ }
+ if (!post_process(*handler_config, seq)) {
+ return false;
+ }
+ }
+ seq++;
+ return true;
+ };
+ ProfilingLoop(config_fn, reread_config, handler);
+
+ LOG(INFO) << "finishing Android Wide Profiling daemon";
+ return 0;
+}
diff --git a/perfprofd/perfprofd_cmdline.h b/perfprofd/perfprofd_cmdline.h
new file mode 100644
index 00000000..5a6b766c
--- /dev/null
+++ b/perfprofd/perfprofd_cmdline.h
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_CMDLINE_H_
+#define SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_CMDLINE_H_
+
+// Semaphore file that indicates that the user is opting in
+#define SEMAPHORE_FILENAME "perf_profile_collection_enabled.txt"
+
+// File containing a list of sequence numbers corresponding to profiles
+// that have been processed/uploaded. Written by the GmsCore uploader,
+// within the GmsCore files directory.
+#define PROCESSED_FILENAME "perfprofd_processed.txt"
+
+// File containing a list of sequence numbers corresponding to profiles
+// that have been created by the perfprofd but not yet uploaded. Written
+// by perfprofd within the destination directory; consumed by GmsCore.
+#define PRODUCED_FILENAME "perfprofd_produced.txt"
+
+struct Config;
+
+// Main routine for perfprofd daemon
+int perfprofd_main(int argc, char **argv, Config* config);
+
+#endif // SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_CMDLINE_H_
diff --git a/perfprofd/perfprofdcore.cc b/perfprofd/perfprofdcore.cc
index 4fa666d3..a5b4b480 100644
--- a/perfprofd/perfprofdcore.cc
+++ b/perfprofd/perfprofdcore.cc
@@ -29,10 +29,7 @@
#include <time.h>
#include <unistd.h>
-#include <cctype>
-#include <map>
#include <memory>
-#include <set>
#include <sstream>
#include <string>
@@ -40,7 +37,6 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
#ifdef __BIONIC__
#include <android-base/properties.h>
@@ -48,7 +44,7 @@
#include "perfprofd_record.pb.h"
-#include "configreader.h"
+#include "config.h"
#include "cpuconfig.h"
#include "perf_data_converter.h"
#include "perfprofdcore.h"
@@ -97,6 +93,8 @@ typedef enum {
} CKPROFILE_RESULT;
+static bool common_initialized = false;
+
//
// Are we running in the emulator? If so, stub out profile collection
// Starts as uninitialized (-1), then set to 1 or 0 at init time.
@@ -105,14 +103,8 @@ static int running_in_emulator = -1;
//
// Is this a debug build ('userdebug' or 'eng')?
-// Starts as uninitialized (-1), then set to 1 or 0 at init time.
-//
-static int is_debug_build = -1;
-
-//
-// Path to the perf file to convert and exit? Empty value is the default, daemon mode.
//
-static std::string perf_file_to_convert = "";
+static bool is_debug_build = false;
//
// Random number generator seed (set at startup time).
@@ -120,51 +112,9 @@ static std::string perf_file_to_convert = "";
static unsigned short random_seed[3];
//
-// SIGHUP handler. Sending SIGHUP to the daemon can be used to break it
-// out of a sleep() call so as to trigger a new collection (debugging)
-//
-static void sig_hup(int /* signum */)
-{
- LOG(WARNING) << "SIGHUP received";
-}
-
-//
-// Parse command line args. Currently supported flags:
-// * "-c PATH" sets the path of the config file to PATH.
-// * "-x PATH" reads PATH as a perf data file and saves it as a file in
-// perf_profile.proto format. ".encoded" suffix is appended to PATH to form
-// the output file path.
-//
-static void parse_args(int argc, char** argv)
-{
- int ac;
-
- for (ac = 1; ac < argc; ++ac) {
- if (!strcmp(argv[ac], "-c")) {
- if (ac >= argc-1) {
- LOG(ERROR) << "malformed command line: -c option requires argument)";
- continue;
- }
- ConfigReader::setConfigFilePath(argv[ac+1]);
- ++ac;
- } else if (!strcmp(argv[ac], "-x")) {
- if (ac >= argc-1) {
- LOG(ERROR) << "malformed command line: -x option requires argument)";
- continue;
- }
- perf_file_to_convert = argv[ac+1];
- ++ac;
- } else {
- LOG(ERROR) << "malformed command line: unknown option or arg " << argv[ac] << ")";
- continue;
- }
- }
-}
-
-//
// Convert a CKPROFILE_RESULT to a string
//
-const char *ckprofile_result_to_string(CKPROFILE_RESULT result)
+static const char *ckprofile_result_to_string(CKPROFILE_RESULT result)
{
switch (result) {
case DO_COLLECT_PROFILE:
@@ -183,29 +133,6 @@ const char *ckprofile_result_to_string(CKPROFILE_RESULT result)
}
//
-// Convert a PROFILE_RESULT to a string
-//
-const char *profile_result_to_string(PROFILE_RESULT result)
-{
- switch(result) {
- case OK_PROFILE_COLLECTION:
- return "profile collection succeeded";
- case ERR_FORK_FAILED:
- return "fork() system call failed";
- case ERR_PERF_RECORD_FAILED:
- return "perf record returned bad exit status";
- case ERR_PERF_ENCODE_FAILED:
- return "failure encoding perf.data to protobuf";
- case ERR_OPEN_ENCODED_FILE_FAILED:
- return "failed to open encoded perf file";
- case ERR_WRITE_ENCODED_FILE_FAILED:
- return "write to encoded perf file failed";
- default:
- return "unknown";
- }
-}
-
-//
// Check to see whether we should perform a profile collection
//
static CKPROFILE_RESULT check_profiling_enabled(const Config& config)
@@ -387,9 +314,9 @@ bool get_charging()
return result;
}
-bool postprocess_proc_stat_contents(const std::string &pscontents,
- long unsigned *idleticks,
- long unsigned *remainingticks)
+static bool postprocess_proc_stat_contents(const std::string &pscontents,
+ long unsigned *idleticks,
+ long unsigned *remainingticks)
{
long unsigned usertime, nicetime, systime, idletime, iowaittime;
long unsigned irqtime, softirqtime;
@@ -663,68 +590,6 @@ static void cleanup_destination_dir(const std::string& dest_dir)
}
//
-// Post-processes after profile is collected and converted to protobuf.
-// * GMS core stores processed file sequence numbers in
-// /data/data/com.google.android.gms/files/perfprofd_processed.txt
-// * Update /data/misc/perfprofd/perfprofd_produced.txt to remove the sequence
-// numbers that have been processed and append the current seq number
-// Returns true if the current_seq should increment.
-//
-static bool post_process(const Config& config, int current_seq)
-{
- const std::string& dest_dir = config.destination_directory;
- std::string processed_file_path =
- config.config_directory + "/" + PROCESSED_FILENAME;
- std::string produced_file_path = dest_dir + "/" + PRODUCED_FILENAME;
-
-
- std::set<int> processed;
- FILE *fp = fopen(processed_file_path.c_str(), "r");
- if (fp != NULL) {
- int seq;
- while(fscanf(fp, "%d\n", &seq) > 0) {
- if (remove(android::base::StringPrintf(
- "%s/perf.data.encoded.%d", dest_dir.c_str(),seq).c_str()) == 0) {
- processed.insert(seq);
- }
- }
- fclose(fp);
- }
-
- std::set<int> produced;
- fp = fopen(produced_file_path.c_str(), "r");
- if (fp != NULL) {
- int seq;
- while(fscanf(fp, "%d\n", &seq) > 0) {
- if (processed.find(seq) == processed.end()) {
- produced.insert(seq);
- }
- }
- fclose(fp);
- }
-
- uint32_t maxLive = config.max_unprocessed_profiles;
- if (produced.size() >= maxLive) {
- return false;
- }
-
- produced.insert(current_seq);
- fp = fopen(produced_file_path.c_str(), "w");
- if (fp == NULL) {
- PLOG(WARNING) << "Cannot write " << produced_file_path;
- return false;
- }
- for (std::set<int>::const_iterator iter = produced.begin();
- iter != produced.end(); ++iter) {
- fprintf(fp, "%d\n", *iter);
- }
- fclose(fp);
- chmod(produced_file_path.c_str(),
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
- return true;
-}
-
-//
// Collect a perf profile. Steps for this operation are:
// - kick off 'perf record'
// - read perf.data, convert to protocol buf
@@ -852,7 +717,7 @@ static void set_seed(uint32_t use_fixed_seed)
random_seed[2] = (random_seed[0] ^ random_seed[1]);
}
-static void CommonInit(uint32_t use_fixed_seed, const char* dest_dir) {
+void CommonInit(uint32_t use_fixed_seed, const char* dest_dir) {
// Children of init inherit an artificially low OOM score -- this is not
// desirable for perfprofd (its OOM score should be on par with
// other user processes).
@@ -874,27 +739,13 @@ static void CommonInit(uint32_t use_fixed_seed, const char* dest_dir) {
running_in_emulator = false;
is_debug_build = true;
#endif
-}
-//
-// Initialization
-//
-static void init(const Config& config)
-{
- // TODO: Consider whether we want to clean things or just overwrite.
- CommonInit(config.use_fixed_seed, nullptr);
+ common_initialized = true;
}
-static void init(ConfigReader &config)
-{
- if (!config.readFile()) {
- LOG(ERROR) << "unable to open configuration file " << config.getConfigFilePath();
- }
-
- CommonInit(static_cast<uint32_t>(config.getUnsignedValue("use_fixed_seed")),
- config.getStringValue("destination_directory").c_str());
-
- signal(SIGHUP, sig_hup);
+bool IsDebugBuild() {
+ CHECK(common_initialized);
+ return is_debug_build;
}
template <typename ConfigFn, typename UpdateFn>
@@ -952,7 +803,7 @@ static void ProfilingLoopImpl(ConfigFn config, UpdateFn update, HandlerFn handle
}
void ProfilingLoop(Config& config, HandlerFn handler) {
- init(config);
+ CommonInit(config.use_fixed_seed, nullptr);
auto config_fn = [&config]() {
return &config;;
@@ -962,67 +813,8 @@ void ProfilingLoop(Config& config, HandlerFn handler) {
ProfilingLoopImpl(config_fn, do_nothing, handler);
}
-//
-// Main routine:
-// 1. parse cmd line args
-// 2. read config file
-// 3. loop: {
-// sleep for a while
-// perform a profile collection
-// }
-//
-int perfprofd_main(int argc, char** argv, Config* config)
-{
- ConfigReader config_reader;
-
- LOG(INFO) << "starting Android Wide Profiling daemon";
-
- parse_args(argc, argv);
- init(config_reader);
- config_reader.FillConfig(config);
-
- if (!perf_file_to_convert.empty()) {
- std::string encoded_path = perf_file_to_convert + ".encoded";
- encode_to_proto(perf_file_to_convert, encoded_path.c_str(), *config, 0, nullptr);
- return 0;
- }
-
- // Early exit if we're not supposed to run on this build flavor
- if (is_debug_build != 1 && config->only_debug_build) {
- LOG(INFO) << "early exit due to inappropriate build type";
- return 0;
- }
-
- auto config_fn = [config]() {
- return config;
- };
- auto reread_config = [&config_reader, config]() {
- // Reread config file -- the uploader may have rewritten it as a result
- // of a gservices change
- config_reader.readFile();
- config_reader.FillConfig(config);
- };
- int seq = 0;
- auto handler = [&seq](android::perfprofd::PerfprofdRecord* proto, Config* handler_config) {
- if (proto == nullptr) {
- return false;
- }
- std::string data_file_path(handler_config->destination_directory);
- data_file_path += "/";
- data_file_path += PERF_OUTPUT;
- std::string path = android::base::StringPrintf("%s.encoded.%d", data_file_path.c_str(), seq);
- if (!android::perfprofd::SerializeProtobuf(proto, path.c_str(), handler_config->compress)) {
- return false;
- }
-
- if (!post_process(*handler_config, seq)) {
- return false;
- }
- seq++;
- return true;
- };
- ProfilingLoopImpl(config_fn, reread_config, handler);
-
- LOG(INFO) << "finishing Android Wide Profiling daemon";
- return 0;
+void ProfilingLoop(std::function<Config*()> config_fn,
+ std::function<void()> update_fn,
+ HandlerFn handler) {
+ ProfilingLoopImpl(config_fn, update_fn, handler);
}
diff --git a/perfprofd/perfprofdcore.h b/perfprofd/perfprofdcore.h
index 73a9c567..2adf114d 100644
--- a/perfprofd/perfprofdcore.h
+++ b/perfprofd/perfprofdcore.h
@@ -29,21 +29,7 @@ namespace perfprofd {
struct Symbolizer;
}
-// Semaphore file that indicates that the user is opting in
-#define SEMAPHORE_FILENAME "perf_profile_collection_enabled.txt"
-
-// File containing a list of sequence numbers corresponding to profiles
-// that have been processed/uploaded. Written by the GmsCore uploader,
-// within the GmsCore files directory.
-#define PROCESSED_FILENAME "perfprofd_processed.txt"
-
-// File containing a list of sequence numbers corresponding to profiles
-// that have been created by the perfprofd but not yet uploaded. Written
-// by perfprofd within the destination directory; consumed by GmsCore.
-#define PRODUCED_FILENAME "perfprofd_produced.txt"
-
-// Main routine for perfprofd daemon
-extern int perfprofd_main(int argc, char **argv, Config* config);
+void CommonInit(uint32_t use_fixed_seed, const char* dest_dir);
//
// This enumeration holds the results of what happened when on an
@@ -86,6 +72,9 @@ using HandlerFn = std::function<bool(android::perfprofd::PerfprofdRecord* proto,
Config* config)>;
void ProfilingLoop(Config& config, HandlerFn handler);
+void ProfilingLoop(std::function<Config*()> config_fn,
+ std::function<void()> update_fn,
+ HandlerFn handler);
//
// Exposed for unit testing
@@ -95,4 +84,6 @@ extern bool get_booting();
extern bool get_charging();
extern bool get_camera_active();
+bool IsDebugBuild();
+
#endif
diff --git a/perfprofd/perfprofdmain.cc b/perfprofd/perfprofdmain.cc
index 403e0253..0f9f53e9 100644
--- a/perfprofd/perfprofdmain.cc
+++ b/perfprofd/perfprofdmain.cc
@@ -21,6 +21,7 @@
#include "config.h"
#include "perfprofd_binder.h"
+#include "perfprofd_cmdline.h"
#include "perfprofdcore.h"
extern int perfprofd_main(int argc, char** argv, Config* config);
diff --git a/perfprofd/tests/Android.bp b/perfprofd/tests/Android.bp
index 9fa0d730..f601aaf5 100644
--- a/perfprofd/tests/Android.bp
+++ b/perfprofd/tests/Android.bp
@@ -48,6 +48,11 @@ cc_test {
required: [
"simpleperf",
],
+ shared_libs: [
+ "libbinder",
+ "libservices",
+ "libutils",
+ ],
},
},
diff --git a/perfprofd/tests/perfprofd_test.cc b/perfprofd/tests/perfprofd_test.cc
index 61eb09d2..79f8ea64 100644
--- a/perfprofd/tests/perfprofd_test.cc
+++ b/perfprofd/tests/perfprofd_test.cc
@@ -43,6 +43,7 @@
#include "configreader.h"
#include "map_utils.h"
#include "perfprofdcore.h"
+#include "perfprofd_cmdline.h"
#include "quipper_helper.h"
#include "symbolizer.h"