summaryrefslogtreecommitdiff
path: root/profcollectd
diff options
context:
space:
mode:
authorYi Kong <yikong@google.com>2020-02-19 15:14:42 +0800
committerYi Kong <yikong@google.com>2020-06-23 03:37:57 +0000
commit83e3567d6a7dae7612d386a74ddba5de85ee6351 (patch)
tree988909fc3e6f2ffb92373a4e4d1d771dbd21900d /profcollectd
parent4d5330155d5e873d81e3764107c17a7228d99c0e (diff)
downloadextras-83e3567d6a7dae7612d386a74ddba5de85ee6351.tar.gz
profcollectd: initial import
A daemon to collect, process, and upload sampling traces to aid platform AutoFDO optimisation. Bug: 79161490 Change-Id: Icf9927c56c3d4c6ea7562be4706c0d2f309db341
Diffstat (limited to 'profcollectd')
l---------profcollectd/.clang-format1
-rw-r--r--profcollectd/Android.bp60
-rw-r--r--profcollectd/MODULE_LICENSE_APACHE20
-rw-r--r--profcollectd/NOTICE190
-rw-r--r--profcollectd/OWNERS3
-rw-r--r--profcollectd/binder/android/os/IProfCollectd.aidl26
-rw-r--r--profcollectd/libprofcollectd/Android.bp46
-rw-r--r--profcollectd/libprofcollectd/binder_service.cpp71
-rw-r--r--profcollectd/libprofcollectd/binder_service.h45
-rw-r--r--profcollectd/libprofcollectd/compress.cpp49
-rw-r--r--profcollectd/libprofcollectd/compress.h27
-rw-r--r--profcollectd/libprofcollectd/hwtrace_provider.h48
-rw-r--r--profcollectd/libprofcollectd/include/libprofcollectd.h33
-rw-r--r--profcollectd/libprofcollectd/interface.cpp86
-rw-r--r--profcollectd/libprofcollectd/scheduler.cpp216
-rw-r--r--profcollectd/libprofcollectd/scheduler.h65
-rw-r--r--profcollectd/libprofcollectd/simpleperf_etm_provider.cpp96
-rw-r--r--profcollectd/profcollectctl.cpp71
-rw-r--r--profcollectd/profcollectd.cpp47
-rw-r--r--profcollectd/profcollectd.rc11
20 files changed, 1191 insertions, 0 deletions
diff --git a/profcollectd/.clang-format b/profcollectd/.clang-format
new file mode 120000
index 00000000..f7e9891f
--- /dev/null
+++ b/profcollectd/.clang-format
@@ -0,0 +1 @@
+../../../system/core/.clang-format-2 \ No newline at end of file
diff --git a/profcollectd/Android.bp b/profcollectd/Android.bp
new file mode 100644
index 00000000..38282274
--- /dev/null
+++ b/profcollectd/Android.bp
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_defaults {
+ name: "libprofcollectd_defaults",
+
+ // We are only doing this for C++20. Can be removed after it becomes default.
+ cpp_std: "experimental",
+
+ tidy: true,
+ tidy_checks: [
+ "-google-runtime-int",
+ "-google-explicit-constructor",
+ "-bugprone-unhandled-self-assignment",
+ "-bugprone-macro-parentheses",
+ ],
+}
+
+cc_binary {
+ name: "profcollectctl",
+
+ defaults: ["libprofcollectd_defaults"],
+
+ srcs: ["profcollectctl.cpp"],
+
+ shared_libs: ["libprofcollectd"],
+}
+
+cc_binary {
+ name: "profcollectd",
+
+ defaults: ["libprofcollectd_defaults"],
+
+ srcs: ["profcollectd.cpp"],
+
+ shared_libs: ["libprofcollectd"],
+
+ init_rc: ["profcollectd.rc"],
+}
+
+filegroup {
+ name: "profcollectd_aidl",
+ srcs: [
+ "binder/android/os/IProfCollectd.aidl",
+ ],
+ path: "binder",
+}
diff --git a/profcollectd/MODULE_LICENSE_APACHE2 b/profcollectd/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/profcollectd/MODULE_LICENSE_APACHE2
diff --git a/profcollectd/NOTICE b/profcollectd/NOTICE
new file mode 100644
index 00000000..f3e7764f
--- /dev/null
+++ b/profcollectd/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2020, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/profcollectd/OWNERS b/profcollectd/OWNERS
new file mode 100644
index 00000000..b380e395
--- /dev/null
+++ b/profcollectd/OWNERS
@@ -0,0 +1,3 @@
+srhines@google.com
+yabinc@google.com
+yikong@google.com
diff --git a/profcollectd/binder/android/os/IProfCollectd.aidl b/profcollectd/binder/android/os/IProfCollectd.aidl
new file mode 100644
index 00000000..03f6b19b
--- /dev/null
+++ b/profcollectd/binder/android/os/IProfCollectd.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IProfCollectd {
+ void ReadConfig();
+ void ScheduleCollection();
+ void TerminateCollection();
+ void TraceOnce();
+ void ProcessProfile();
+}
diff --git a/profcollectd/libprofcollectd/Android.bp b/profcollectd/libprofcollectd/Android.bp
new file mode 100644
index 00000000..7b1b2f31
--- /dev/null
+++ b/profcollectd/libprofcollectd/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_library {
+ name: "libprofcollectd",
+
+ defaults: ["libprofcollectd_defaults"],
+
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libjsoncpp",
+ "liblog",
+ "libsimpleperf_profcollect",
+ "libutils",
+ "libziparchive",
+ ],
+
+ static_libs: [
+ "libc++fs",
+ ],
+
+ srcs: [
+ "binder_service.cpp",
+ "compress.cpp",
+ "interface.cpp",
+ "scheduler.cpp",
+ "simpleperf_etm_provider.cpp",
+ ":profcollectd_aidl",
+ ],
+
+ export_include_dirs: ["include"],
+}
diff --git a/profcollectd/libprofcollectd/binder_service.cpp b/profcollectd/libprofcollectd/binder_service.cpp
new file mode 100644
index 00000000..0eb9caaa
--- /dev/null
+++ b/profcollectd/libprofcollectd/binder_service.cpp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#define LOG_TAG "profcollectd_binder"
+
+#include "binder_service.h"
+
+#include <android-base/logging.h>
+
+#include "hwtrace_provider.h"
+#include "scheduler.h"
+
+namespace android {
+namespace profcollectd {
+
+using ::android::binder::Status;
+using ::android::os::IProfCollectd;
+
+namespace {
+
+Status HandleIfError(const std::function<OptError()>& action) {
+ auto errmsg = action();
+ if (errmsg) {
+ LOG(ERROR) << errmsg.value();
+ return Status::fromExceptionCode(1, errmsg.value().c_str());
+ }
+ return Status::ok();
+}
+
+} // namespace
+
+ProfcollectdBinder::ProfcollectdBinder() {
+ ProfcollectdBinder::Scheduler = std::make_unique<ProfcollectdScheduler>();
+ LOG(INFO) << "Binder service started";
+}
+
+Status ProfcollectdBinder::ReadConfig() {
+ return HandleIfError([=]() { return Scheduler->ReadConfig(); });
+}
+
+Status ProfcollectdBinder::ScheduleCollection() {
+ return HandleIfError([=]() { return Scheduler->ScheduleCollection(); });
+}
+
+Status ProfcollectdBinder::TerminateCollection() {
+ return HandleIfError([=]() { return Scheduler->TerminateCollection(); });
+}
+
+Status ProfcollectdBinder::TraceOnce() {
+ return HandleIfError([=]() { return Scheduler->TraceOnce(); });
+}
+
+Status ProfcollectdBinder::ProcessProfile() {
+ return HandleIfError([=]() { return Scheduler->ProcessProfile(); });
+}
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/binder_service.h b/profcollectd/libprofcollectd/binder_service.h
new file mode 100644
index 00000000..83197666
--- /dev/null
+++ b/profcollectd/libprofcollectd/binder_service.h
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+#include <binder/BinderService.h>
+#include <binder/Status.h>
+
+#include "android/os/BnProfCollectd.h"
+#include "scheduler.h"
+
+namespace android {
+namespace profcollectd {
+
+class ProfcollectdBinder : public BinderService<ProfcollectdBinder>, public os::BnProfCollectd {
+ public:
+ explicit ProfcollectdBinder();
+
+ static constexpr const char* getServiceName() { return "profcollectd"; }
+
+ binder::Status ReadConfig() override;
+ binder::Status ScheduleCollection() override;
+ binder::Status TerminateCollection() override;
+ binder::Status TraceOnce() override;
+ binder::Status ProcessProfile() override;
+
+ protected:
+ inline static std::unique_ptr<ProfcollectdScheduler> Scheduler;
+};
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/compress.cpp b/profcollectd/libprofcollectd/compress.cpp
new file mode 100644
index 00000000..6a2b2e8e
--- /dev/null
+++ b/profcollectd/libprofcollectd/compress.cpp
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2020 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 "compress.h"
+
+#include <ziparchive/zip_writer.h>
+#include <cstdlib>
+#include <fstream>
+#include <iostream>
+
+namespace android {
+namespace profcollectd {
+
+bool CompressFiles(const std::filesystem::path& output,
+ std::vector<std::filesystem::path>& inputFiles) {
+ FILE* outputFile = std::fopen(output.c_str(), "wb");
+ ZipWriter writer(outputFile);
+
+ for (const auto& f : inputFiles) {
+ // read profile into memory.
+ std::ifstream ifs(f, std::ios::in | std::ios::binary);
+ std::vector<char> buf((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+
+ // append to zip file
+ writer.StartEntry(f.filename().string(), ZipWriter::kCompress | ZipWriter::kAlign32);
+ writer.WriteBytes(buf.data(), buf.size());
+ writer.FinishEntry();
+ }
+
+ auto ret = writer.Finish();
+ std::fclose(outputFile);
+ return ret == 0;
+}
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/compress.h b/profcollectd/libprofcollectd/compress.h
new file mode 100644
index 00000000..f99deca1
--- /dev/null
+++ b/profcollectd/libprofcollectd/compress.h
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+#include <filesystem>
+
+namespace android {
+namespace profcollectd {
+
+bool CompressFiles(const std::filesystem::path& output, std::vector<std::filesystem::path>& files);
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/hwtrace_provider.h b/profcollectd/libprofcollectd/hwtrace_provider.h
new file mode 100644
index 00000000..59329dd0
--- /dev/null
+++ b/profcollectd/libprofcollectd/hwtrace_provider.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+#include <chrono>
+#include <filesystem>
+#include <functional>
+
+namespace android {
+namespace profcollectd {
+
+class HwtraceProvider {
+ public:
+ virtual ~HwtraceProvider() = default;
+
+ /**
+ * Trace for the given length of time.
+ *
+ * @param period Length of time to trace in seconds.
+ * @return True if successful.
+ */
+ virtual bool Trace(const std::filesystem::path& outputPath,
+ std::chrono::duration<float> samplingPeriod) = 0;
+
+ /**
+ * Process the hardware trace to generate simpleperf intermediate profile.
+ */
+ virtual bool Process(const std::filesystem::path& inputPath,
+ const std::filesystem::path& outputPath,
+ const std::string& binaryFilter) = 0;
+};
+
+} // namespace profcollectd
+} // namespace android \ No newline at end of file
diff --git a/profcollectd/libprofcollectd/include/libprofcollectd.h b/profcollectd/libprofcollectd/include/libprofcollectd.h
new file mode 100644
index 00000000..1beebb61
--- /dev/null
+++ b/profcollectd/libprofcollectd/include/libprofcollectd.h
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+namespace android {
+namespace profcollectd {
+
+// Daemon side operations.
+void InitService(bool start);
+
+// Client side operations.
+void ScheduleCollection();
+void TerminateCollection();
+void TraceOnce();
+void Process();
+void ReadConfig();
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/interface.cpp b/profcollectd/libprofcollectd/interface.cpp
new file mode 100644
index 00000000..f7985761
--- /dev/null
+++ b/profcollectd/libprofcollectd/interface.cpp
@@ -0,0 +1,86 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#define LOG_TAG "profcollectd"
+
+#include "libprofcollectd.h"
+
+#include <android-base/logging.h>
+
+#include <iostream>
+
+#include "binder_service.h"
+
+namespace android {
+namespace profcollectd {
+
+using ::android::os::IProfCollectd;
+
+namespace {
+
+sp<IProfCollectd> GetIProfcollectdService() {
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IBinder> binder =
+ defaultServiceManager()->getService(String16(ProfcollectdBinder::getServiceName()));
+ if (!binder) {
+ std::cerr << "Cannot connect to the daemon, is it running?" << std::endl;
+ exit(EXIT_FAILURE);
+ }
+
+ return interface_cast<IProfCollectd>(binder);
+}
+
+} // namespace
+
+void InitService(bool start) {
+ if (defaultServiceManager()->checkService(String16(ProfcollectdBinder::getServiceName()))) {
+ ALOGE("Another instance of profcollectd is already running");
+ exit(EXIT_FAILURE);
+ }
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm(defaultServiceManager());
+ auto svc = sp<ProfcollectdBinder>(new ProfcollectdBinder());
+ sm->addService(String16(ProfcollectdBinder::getServiceName()), svc);
+ if (start) {
+ svc->ScheduleCollection();
+ }
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
+
+void ScheduleCollection() {
+ GetIProfcollectdService()->ScheduleCollection();
+}
+
+void TerminateCollection() {
+ GetIProfcollectdService()->TerminateCollection();
+}
+
+void TraceOnce() {
+ GetIProfcollectdService()->TraceOnce();
+}
+
+void Process() {
+ GetIProfcollectdService()->ProcessProfile();
+}
+
+void ReadConfig() {
+ GetIProfcollectdService()->ReadConfig();
+}
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/scheduler.cpp b/profcollectd/libprofcollectd/scheduler.cpp
new file mode 100644
index 00000000..38bf19a4
--- /dev/null
+++ b/profcollectd/libprofcollectd/scheduler.cpp
@@ -0,0 +1,216 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#define LOG_TAG "profcollectd_scheduler"
+
+#include "scheduler.h"
+
+#include <fstream>
+#include <variant>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include "compress.h"
+#include "hwtrace_provider.h"
+#include "json/json.h"
+#include "json/writer.h"
+
+// Default option values.
+using config_t = std::pair<const char*, std::variant<const int, const char*>>;
+static constexpr const config_t CONFIG_BUILD_FINGERPRINT = {"Fingerprint", "unknown"};
+static constexpr const config_t CONFIG_COLLECTION_INTERVAL_SEC = {"CollectionInterval", 600};
+static constexpr const config_t CONFIG_SAMPLING_PERIOD_MS = {"SamplingPeriod", 500};
+static constexpr const config_t CONFIG_TRACE_OUTDIR = {"TraceDir", "/data/misc/profcollectd/trace"};
+static constexpr const config_t CONFIG_PROFILE_OUTDIR = {"ProfileDir",
+ "/data/misc/profcollectd/output"};
+static constexpr const config_t CONFIG_BINARY_FILTER = {"BinaryFilter", ""};
+
+namespace android {
+namespace profcollectd {
+
+namespace fs = std::filesystem;
+using ::android::base::GetIntProperty;
+using ::android::base::GetProperty;
+
+// Hwtrace provider registry
+extern std::unique_ptr<HwtraceProvider> REGISTER_SIMPLEPERF_ETM_PROVIDER();
+
+namespace {
+
+void ClearDir(const fs::path& path) {
+ if (fs::exists(path)) {
+ for (const auto& entry : fs::directory_iterator(path)) {
+ fs::remove_all(entry);
+ }
+ }
+}
+
+bool ClearOnConfigChange(const ProfcollectdScheduler::Config& config) {
+ const fs::path configFile = config.profileOutputDir / "config.json";
+ ProfcollectdScheduler::Config oldConfig{};
+
+ // Read old config, if exists.
+ if (fs::exists(configFile)) {
+ std::ifstream ifs(configFile);
+ ifs >> oldConfig;
+ }
+
+ if (oldConfig != config) {
+ LOG(INFO) << "Clearing profiles due to config change.";
+ ClearDir(config.traceOutputDir);
+ ClearDir(config.profileOutputDir);
+
+ // Write new config.
+ std::ofstream ofs(configFile);
+ ofs << config;
+ return true;
+ }
+ return false;
+}
+
+void PeriodicCollectionWorker(std::future<void> terminationSignal, ProfcollectdScheduler& scheduler,
+ std::chrono::seconds& interval) {
+ do {
+ scheduler.TraceOnce();
+ } while ((terminationSignal.wait_for(interval)) == std::future_status::timeout);
+}
+
+} // namespace
+
+ProfcollectdScheduler::ProfcollectdScheduler() {
+ ReadConfig();
+
+ // Load a registered hardware trace provider.
+ if ((hwtracer = REGISTER_SIMPLEPERF_ETM_PROVIDER())) {
+ LOG(INFO) << "ETM provider registered.";
+ return;
+ } else {
+ LOG(ERROR) << "No hardware trace provider found for this architecture.";
+ exit(EXIT_FAILURE);
+ }
+}
+
+OptError ProfcollectdScheduler::ReadConfig() {
+ if (workerThread != nullptr) {
+ static std::string errmsg = "Terminate the collection before refreshing config.";
+ return errmsg;
+ }
+
+ const std::lock_guard<std::mutex> lock(mu);
+
+ config.buildFingerprint = GetProperty("ro.build.fingerprint", "unknown");
+ config.collectionInterval = std::chrono::seconds(
+ GetIntProperty("profcollectd.collection_interval",
+ std::get<const int>(CONFIG_COLLECTION_INTERVAL_SEC.second)));
+ config.samplingPeriod = std::chrono::milliseconds(GetIntProperty(
+ "profcollectd.sampling_period_ms", std::get<const int>(CONFIG_SAMPLING_PERIOD_MS.second)));
+ config.traceOutputDir = GetProperty("profcollectd.trace_output_dir",
+ std::get<const char*>(CONFIG_TRACE_OUTDIR.second));
+ config.profileOutputDir =
+ GetProperty("profcollectd.output_dir", std::get<const char*>(CONFIG_PROFILE_OUTDIR.second));
+ config.binaryFilter =
+ GetProperty("profcollectd.binary_filter", std::get<const char*>(CONFIG_BINARY_FILTER.second));
+ ClearOnConfigChange(config);
+
+ return std::nullopt;
+}
+
+OptError ProfcollectdScheduler::ScheduleCollection() {
+ if (workerThread != nullptr) {
+ static std::string errmsg = "Collection is already scheduled.";
+ return errmsg;
+ }
+
+ workerThread =
+ std::make_unique<std::thread>(PeriodicCollectionWorker, terminate.get_future(),
+ std::ref(*this), std::ref(config.collectionInterval));
+ return std::nullopt;
+}
+
+OptError ProfcollectdScheduler::TerminateCollection() {
+ if (workerThread == nullptr) {
+ static std::string errmsg = "Collection is not scheduled.";
+ return errmsg;
+ }
+
+ terminate.set_value();
+ workerThread->join();
+ workerThread = nullptr;
+ terminate = std::promise<void>(); // Reset promise.
+ return std::nullopt;
+}
+
+OptError ProfcollectdScheduler::TraceOnce() {
+ const std::lock_guard<std::mutex> lock(mu);
+ bool success = hwtracer->Trace(config.traceOutputDir, config.samplingPeriod);
+ if (!success) {
+ static std::string errmsg = "Trace failed";
+ return errmsg;
+ }
+ return std::nullopt;
+}
+
+OptError ProfcollectdScheduler::ProcessProfile() {
+ const std::lock_guard<std::mutex> lock(mu);
+ hwtracer->Process(config.traceOutputDir, config.profileOutputDir, config.binaryFilter);
+ std::vector<fs::path> profiles;
+ profiles.insert(profiles.begin(), fs::directory_iterator(config.profileOutputDir),
+ fs::directory_iterator());
+ bool success = CompressFiles("/sdcard/profile.zip", profiles);
+ if (!success) {
+ static std::string errmsg = "Compress files failed";
+ return errmsg;
+ }
+ return std::nullopt;
+}
+
+std::ostream& operator<<(std::ostream& os, const ProfcollectdScheduler::Config& config) {
+ Json::Value root;
+ const auto writer = std::make_unique<Json::StyledStreamWriter>();
+ root[CONFIG_BUILD_FINGERPRINT.first] = config.buildFingerprint;
+ root[CONFIG_COLLECTION_INTERVAL_SEC.first] = config.collectionInterval.count();
+ root[CONFIG_SAMPLING_PERIOD_MS.first] = config.samplingPeriod.count();
+ root[CONFIG_TRACE_OUTDIR.first] = config.traceOutputDir.c_str();
+ root[CONFIG_PROFILE_OUTDIR.first] = config.profileOutputDir.c_str();
+ root[CONFIG_BINARY_FILTER.first] = config.binaryFilter.c_str();
+ writer->write(os, root);
+ return os;
+}
+
+std::istream& operator>>(std::istream& is, ProfcollectdScheduler::Config& config) {
+ Json::Value root;
+ const auto reader = std::make_unique<Json::Reader>();
+ bool success = reader->parse(is, root);
+ if (!success) {
+ return is;
+ }
+
+ config.buildFingerprint = root[CONFIG_BUILD_FINGERPRINT.first].asString();
+ config.collectionInterval =
+ std::chrono::seconds(root[CONFIG_COLLECTION_INTERVAL_SEC.first].asInt64());
+ config.samplingPeriod =
+ std::chrono::duration<float>(root[CONFIG_SAMPLING_PERIOD_MS.first].asFloat());
+ config.traceOutputDir = root[CONFIG_TRACE_OUTDIR.first].asString();
+ config.profileOutputDir = root[CONFIG_PROFILE_OUTDIR.first].asString();
+ config.binaryFilter = root[CONFIG_BINARY_FILTER.first].asString();
+
+ return is;
+}
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/libprofcollectd/scheduler.h b/profcollectd/libprofcollectd/scheduler.h
new file mode 100644
index 00000000..3325abab
--- /dev/null
+++ b/profcollectd/libprofcollectd/scheduler.h
@@ -0,0 +1,65 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+#include <compare>
+#include <future>
+#include <mutex>
+#include <optional>
+#include <thread>
+
+#include "hwtrace_provider.h"
+
+using OptError = std::optional<std::string>;
+
+namespace android {
+namespace profcollectd {
+
+class ProfcollectdScheduler {
+ public:
+ struct Config {
+ std::string buildFingerprint;
+ std::chrono::seconds collectionInterval;
+ std::chrono::duration<float> samplingPeriod;
+ std::filesystem::path traceOutputDir;
+ std::filesystem::path profileOutputDir;
+ std::string binaryFilter;
+
+ auto operator<=>(const Config&) const = default;
+ friend std::ostream& operator<<(std::ostream& os, const Config& config);
+ friend std::istream& operator>>(std::istream& is, Config& config);
+ };
+
+ explicit ProfcollectdScheduler();
+
+ // Methods below returns optional error message on failure, otherwise returns std::nullopt.
+ OptError ReadConfig();
+ OptError ScheduleCollection();
+ OptError TerminateCollection();
+ OptError TraceOnce();
+ OptError ProcessProfile();
+
+ private:
+ Config config;
+ std::promise<void> terminate;
+ std::unique_ptr<HwtraceProvider> hwtracer;
+ std::unique_ptr<std::thread> workerThread;
+ std::mutex mu;
+};
+
+} // namespace profcollectd
+} // namespace android \ No newline at end of file
diff --git a/profcollectd/libprofcollectd/simpleperf_etm_provider.cpp b/profcollectd/libprofcollectd/simpleperf_etm_provider.cpp
new file mode 100644
index 00000000..8882ccd5
--- /dev/null
+++ b/profcollectd/libprofcollectd/simpleperf_etm_provider.cpp
@@ -0,0 +1,96 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#define LOG_TAG "profcolelctd_simpleperf_etm"
+
+#include "hwtrace_provider.h"
+
+#include <android-base/logging.h>
+#include <simpleperf_profcollect.h>
+
+#include <cstdlib>
+#include <filesystem>
+#include <sstream>
+#include <string>
+#include <thread>
+
+static constexpr const char* ETM_TRACEFILE_EXTENSION = ".etmtrace";
+static constexpr const char* OUTPUT_FILE_EXTENSION = ".data";
+
+namespace {
+
+std::string GetTimestamp() {
+ auto now = std::time(nullptr);
+ char timestr[32];
+ std::strftime(timestr, sizeof(timestr), "%Y%m%d-%H%M%S", std::localtime(&now));
+ return timestr;
+}
+
+} // namespace
+
+namespace android {
+namespace profcollectd {
+
+namespace fs = std::filesystem;
+
+class SimpleperfETMProvider : public HwtraceProvider {
+ public:
+ static bool IsSupported();
+ bool Trace(const fs::path& outputPath, std::chrono::duration<float> samplingPeriod) override;
+ bool Process(const fs::path& inputPath, const fs::path& outputPath,
+ const std::string& binaryFilter) override;
+};
+
+bool SimpleperfETMProvider::IsSupported() {
+ return simpleperf::etm::HasSupport();
+}
+
+bool SimpleperfETMProvider::Trace(const fs::path& outputPath,
+ std::chrono::duration<float> samplingPeriod) {
+ const std::string timestamp = GetTimestamp();
+ auto outputFile = outputPath / (timestamp + ETM_TRACEFILE_EXTENSION);
+ return simpleperf::etm::Record(outputFile, samplingPeriod);
+}
+
+bool SimpleperfETMProvider::Process(const fs::path& inputPath, const fs::path& outputPath,
+ const std::string& binaryFilter) {
+ for (const auto& entry : fs::directory_iterator(inputPath)) {
+ const fs::path& traceFile = entry.path();
+ if (traceFile.extension() != ETM_TRACEFILE_EXTENSION) {
+ continue;
+ }
+
+ const fs::path binaryOutput =
+ outputPath / traceFile.filename().replace_extension(OUTPUT_FILE_EXTENSION);
+
+ bool success = simpleperf::etm::Inject(traceFile, binaryOutput, binaryFilter);
+ if (success) {
+ fs::remove(traceFile);
+ }
+ }
+
+ return true;
+}
+
+std::unique_ptr<HwtraceProvider> REGISTER_SIMPLEPERF_ETM_PROVIDER() {
+ if (SimpleperfETMProvider::IsSupported()) {
+ return std::make_unique<SimpleperfETMProvider>();
+ }
+ return nullptr;
+}
+
+} // namespace profcollectd
+} // namespace android
diff --git a/profcollectd/profcollectctl.cpp b/profcollectd/profcollectctl.cpp
new file mode 100644
index 00000000..897d04e2
--- /dev/null
+++ b/profcollectd/profcollectctl.cpp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2020 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 <stdlib.h>
+
+#include <iostream>
+
+#include "libprofcollectd.h"
+
+namespace profcollectd = android::profcollectd;
+
+namespace {
+
+void PrintHelp(const std::string& reason = "") {
+ std::cout << reason;
+ std::cout << R"(
+usage: profcollectctl [command]
+command:
+ start Schedule periodic collection.
+ stop Terminate periodic collection.
+ once Request an one-off trace.
+ process Convert traces to perf profiles.
+ reconfig Refresh configuration.
+ help Print this message.
+)";
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ PrintHelp("Invalid arguments");
+ exit(EXIT_FAILURE);
+ }
+
+ std::string command(argv[1]);
+ if (command == "start") {
+ std::cout << "Scheduling profile collection\n";
+ profcollectd::ScheduleCollection();
+ } else if (command == "stop") {
+ std::cout << "Terminating profile collection\n";
+ profcollectd::TerminateCollection();
+ } else if (command == "once") {
+ std::cout << "Trace once\n";
+ profcollectd::TraceOnce();
+ } else if (command == "process") {
+ std::cout << "Processing traces\n";
+ profcollectd::Process();
+ } else if (command == "reconfig") {
+ std::cout << "Refreshing configuration\n";
+ profcollectd::ReadConfig();
+ } else if (command == "help") {
+ PrintHelp();
+ } else {
+ PrintHelp("Unknown command: " + command);
+ exit(EXIT_FAILURE);
+ }
+}
diff --git a/profcollectd/profcollectd.cpp b/profcollectd/profcollectd.cpp
new file mode 100644
index 00000000..884bf420
--- /dev/null
+++ b/profcollectd/profcollectd.cpp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2020 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 <stdlib.h>
+
+#include <iostream>
+
+#include "libprofcollectd.h"
+
+namespace {
+
+void print_help() {
+ std::cout << R"(
+usage: profcollectd [command]
+ boot Start daemon and schedule profile collection after a short delay.
+ run Start daemon but do not schedule profile collection.
+)";
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ print_help();
+ exit(EXIT_SUCCESS);
+ } else if (std::string(argv[1]) == "boot") {
+ android::profcollectd::InitService(/* start = */ true);
+ } else if (std::string(argv[1]) == "run") {
+ android::profcollectd::InitService(/* start = */ false);
+ } else {
+ print_help();
+ exit(EXIT_FAILURE);
+ }
+}
diff --git a/profcollectd/profcollectd.rc b/profcollectd/profcollectd.rc
new file mode 100644
index 00000000..26379240
--- /dev/null
+++ b/profcollectd/profcollectd.rc
@@ -0,0 +1,11 @@
+service profcollectd /system/bin/profcollectd boot
+ class late_start
+ user root
+ group root wakelock
+ writepid /dev/cpuset/system-background/tasks
+
+on post-fs-data
+ # Create directory for profcollectd.
+ mkdir /data/misc/profcollectd 0770 root root
+ mkdir /data/misc/profcollectd/trace 0770 root root
+ mkdir /data/misc/profcollectd/output 0770 root root