summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto-perf/Android.bp35
-rw-r--r--crypto-perf/NOTICE190
-rw-r--r--crypto-perf/crypto.cpp165
-rw-r--r--profcollectd/libprofcollectd/config.rs26
-rw-r--r--profcollectd/libprofcollectd/report.rs3
-rw-r--r--profcollectd/libprofcollectd/scheduler.rs6
-rw-r--r--simpleperf/BranchListFile_test.cpp1
-rw-r--r--simpleperf/CallChainJoiner_test.cpp9
-rw-r--r--simpleperf/ETMConstants.h1
-rw-r--r--simpleperf/ETMRecorder.cpp1
-rw-r--r--simpleperf/IOEventLoop_test.cpp10
-rw-r--r--simpleperf/JITDebugReader_test.cpp2
-rw-r--r--simpleperf/MapRecordReader_test.cpp4
-rw-r--r--simpleperf/OfflineUnwinder_test.cpp3
-rw-r--r--simpleperf/ProbeEvents_test.cpp1
-rw-r--r--simpleperf/RecordFilter_test.cpp19
-rw-r--r--simpleperf/RecordReadThread.cpp12
-rw-r--r--simpleperf/RecordReadThread.h1
-rw-r--r--simpleperf/RecordReadThread_test.cpp15
-rw-r--r--simpleperf/RegEx_test.cpp2
-rw-r--r--simpleperf/cmd_api_test.cpp4
-rw-r--r--simpleperf/cmd_boot_record_test.cpp1
-rw-r--r--simpleperf/cmd_debug_unwind_test.cpp12
-rw-r--r--simpleperf/cmd_dumprecord_test.cpp8
-rw-r--r--simpleperf/cmd_inject_test.cpp13
-rw-r--r--simpleperf/cmd_kmem_test.cpp7
-rw-r--r--simpleperf/cmd_list.cpp4
-rw-r--r--simpleperf/cmd_list_test.cpp6
-rw-r--r--simpleperf/cmd_merge_test.cpp2
-rw-r--r--simpleperf/cmd_monitor_test.cpp11
-rw-r--r--simpleperf/cmd_record.cpp31
-rw-r--r--simpleperf/cmd_record_impl.h2
-rw-r--r--simpleperf/cmd_record_test.cpp115
-rw-r--r--simpleperf/cmd_report.cpp7
-rw-r--r--simpleperf/cmd_report_sample_test.cpp24
-rw-r--r--simpleperf/cmd_report_test.cpp74
-rw-r--r--simpleperf/cmd_stat_test.cpp48
-rw-r--r--simpleperf/cmd_trace_sched_test.cpp2
-rw-r--r--simpleperf/command_test.cpp5
-rw-r--r--simpleperf/doc/collect_etm_data_for_autofdo.md80
-rw-r--r--simpleperf/doc/scripts_reference.md3
-rw-r--r--simpleperf/dso.cpp8
-rw-r--r--simpleperf/dso_test.cpp24
-rw-r--r--simpleperf/environment.cpp13
-rw-r--r--simpleperf/environment_test.cpp11
-rw-r--r--simpleperf/event_selection_set.cpp70
-rw-r--r--simpleperf/event_selection_set.h6
-rw-r--r--simpleperf/event_selection_set_test.cpp3
-rw-r--r--simpleperf/event_type.cpp6
-rw-r--r--simpleperf/event_type.h1
-rw-r--r--simpleperf/kallsyms_test.cpp5
-rw-r--r--simpleperf/perf_regs_test.cpp1
-rw-r--r--simpleperf/read_apk_test.cpp3
-rw-r--r--simpleperf/read_dex_file_test.cpp1
-rw-r--r--simpleperf/read_elf_test.cpp16
-rw-r--r--simpleperf/read_symbol_map_test.cpp2
-rw-r--r--simpleperf/record_file_test.cpp8
-rw-r--r--simpleperf/record_lib_test.cpp5
-rw-r--r--simpleperf/record_test.cpp11
-rw-r--r--simpleperf/report_utils_test.cpp17
-rw-r--r--simpleperf/sample_tree_test.cpp9
-rw-r--r--simpleperf/scripts/report_html.js30
-rwxr-xr-xsimpleperf/scripts/report_html.py10
-rw-r--r--simpleperf/scripts/simpleperf_utils.py1
-rw-r--r--simpleperf/test_util.cpp22
-rw-r--r--simpleperf/test_util.h2
-rw-r--r--simpleperf/thread_tree_test.cpp7
-rw-r--r--simpleperf/tracing_test.cpp2
-rw-r--r--simpleperf/utils_test.cpp7
-rw-r--r--simpleperf/workload_test.cpp4
-rwxr-xr-xtools/check_elf_alignment.sh90
71 files changed, 866 insertions, 494 deletions
diff --git a/crypto-perf/Android.bp b/crypto-perf/Android.bp
deleted file mode 100644
index 8f575ca9..00000000
--- a/crypto-perf/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-package {
- default_applicable_licenses: ["system_extras_crypto-perf_license"],
-}
-
-// Added automatically by a large-scale-change
-// See: http://go/android-license-faq
-license {
- name: "system_extras_crypto-perf_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- ],
- license_text: [
- "NOTICE",
- ],
-}
-
-cc_binary {
- name: "crypto",
-
- cflags: [
- "-O0",
- "-march=armv8-a+crypto",
- "-Wall",
- "-Werror",
- ],
- srcs: ["crypto.cpp"],
-
- enabled: false,
- arch: {
- arm64: {
- enabled: true,
- },
- },
-}
diff --git a/crypto-perf/NOTICE b/crypto-perf/NOTICE
deleted file mode 100644
index c77f135e..00000000
--- a/crypto-perf/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2012, 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/crypto-perf/crypto.cpp b/crypto-perf/crypto.cpp
deleted file mode 100644
index a7228324..00000000
--- a/crypto-perf/crypto.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-#include <ctype.h>
-#include <sched.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <unistd.h>
-#define USEC_PER_SEC 1000000ULL
-#define MAX_COUNT 1000000000ULL
-#define NUM_INSTS_GARBAGE 18
-
-// Contains information about benchmark options.
-typedef struct {
- int cpu_to_lock;
- int locked_freq;
-} command_data_t;
-
-void usage() {
- printf("--------------------------------------------------------------------------------\n");
- printf("Usage:");
- printf(" crypto [--cpu_to_lock CPU] [--locked_freq FREQ_IN_KHZ]\n\n");
- printf("!!!!!!Lock the desired core to a desired frequency before invoking this benchmark.\n");
- printf("Hint: Set scaling_max_freq=scaling_min_freq=FREQ_IN_KHZ. FREQ_IN_KHZ "
- "can be obtained from scaling_available_freq\n");
- printf("--------------------------------------------------------------------------------\n");
-}
-
-int processOptions(int argc, char** argv, command_data_t* cmd_data) {
- // Initialize the command_flags.
- cmd_data->cpu_to_lock = 0;
- cmd_data->locked_freq = 1;
- for (int i = 1; i < argc; i++) {
- if (argv[i][0] == '-') {
- int* save_value = NULL;
- if (strcmp(argv[i], "--cpu_to_lock") == 0) {
- save_value = &cmd_data->cpu_to_lock;
- } else if (strcmp(argv[i], "--locked_freq") == 0) {
- save_value = &cmd_data->locked_freq;
- } else {
- printf("Unknown option %s\n", argv[i]);
- return -1;
- }
- if (save_value) {
- // Checking both characters without a strlen() call should be
- // safe since as long as the argument exists, one character will
- // be present (\0). And if the first character is '-', then
- // there will always be a second character (\0 again).
- if (i == argc - 1 || (argv[i + 1][0] == '-' && !isdigit(argv[i + 1][1]))) {
- printf("The option %s requires one argument.\n", argv[i]);
- return -1;
- }
- *save_value = (int)strtol(argv[++i], NULL, 0);
- }
- }
- }
- return 0;
-}
-/* Performs encryption on garbage values. In Cortex-A57 r0p1 and later
- * revisions, pairs of dependent AESE/AESMC and AESD/AESIMC instructions are
- * higher performance when adjacent, and in the described order below. */
-void garbage_encrypt() {
- __asm__ __volatile__(
- "aese v0.16b, v4.16b ;"
- "aesmc v0.16b, v0.16b ;"
- "aese v1.16b, v4.16b ;"
- "aesmc v1.16b, v1.16b ;"
- "aese v2.16b, v4.16b ;"
- "aesmc v2.16b, v2.16b ;"
- "aese v0.16b, v5.16b ;"
- "aesmc v0.16b, v0.16b ;"
- "aese v1.16b, v5.16b ;"
- "aesmc v1.16b, v1.16b ;"
- "aese v2.16b, v5.16b ;"
- "aesmc v2.16b, v2.16b ;"
- "aese v0.16b, v6.16b ;"
- "aesmc v0.16b, v0.16b ;"
- "aese v1.16b, v6.16b ;"
- "aesmc v1.16b, v1.16b ;"
- "aese v2.16b, v6.16b ;"
- "aesmc v2.16b, v2.16b ;");
-}
-
-void garbage_decrypt() {
- __asm__ __volatile__(
- "aesd v0.16b, v4.16b ;"
- "aesimc v0.16b, v0.16b ;"
- "aesd v1.16b, v4.16b ;"
- "aesimc v1.16b, v1.16b ;"
- "aesd v2.16b, v4.16b ;"
- "aesimc v2.16b, v2.16b ;"
- "aesd v0.16b, v5.16b ;"
- "aesimc v0.16b, v0.16b ;"
- "aesd v1.16b, v5.16b ;"
- "aesimc v1.16b, v1.16b ;"
- "aesd v2.16b, v5.16b ;"
- "aesimc v2.16b, v2.16b ;"
- "aesd v0.16b, v6.16b ;"
- "aesimc v0.16b, v0.16b ;"
- "aesd v1.16b, v6.16b ;"
- "aesimc v1.16b, v1.16b ;"
- "aesd v2.16b, v6.16b ;"
- "aesimc v2.16b, v2.16b ;");
-}
-
-int main(int argc, char** argv) {
- usage();
- command_data_t cmd_data;
-
- if (processOptions(argc, argv, &cmd_data) == -1) {
- usage();
- return -1;
- }
- unsigned long long count = 0;
- struct timeval begin_time, end_time, elapsed_time;
- cpu_set_t cpuset;
- CPU_ZERO(&cpuset);
- CPU_SET(cmd_data.cpu_to_lock, &cpuset);
- if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
- perror("sched_setaffinity failed");
- return 1;
- }
- gettimeofday(&begin_time, NULL);
- while (count < MAX_COUNT) {
- garbage_encrypt();
- count++;
- }
- gettimeofday(&end_time, NULL);
- timersub(&end_time, &begin_time, &elapsed_time);
- fprintf(stderr, "encrypt: %llu us\n",
- elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec);
- fprintf(stderr, "encrypt instructions: %llu\n", MAX_COUNT * NUM_INSTS_GARBAGE);
- fprintf(stderr, "encrypt instructions per second: %f\n",
- (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
- (elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec));
- if (cmd_data.locked_freq != 0) {
- fprintf(stderr, "encrypt instructions per cycle: %f\n",
- (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
- ((elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec) * 1000 *
- cmd_data.locked_freq));
- }
- printf("--------------------------------------------------------------------------------\n");
-
- count = 0;
- gettimeofday(&begin_time, NULL);
- while (count < MAX_COUNT) {
- garbage_decrypt();
- count++;
- }
- gettimeofday(&end_time, NULL);
- timersub(&end_time, &begin_time, &elapsed_time);
- fprintf(stderr, "decrypt: %llu us\n",
- elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec);
- fprintf(stderr, "decrypt instructions: %llu\n", MAX_COUNT * NUM_INSTS_GARBAGE);
- fprintf(stderr, "decrypt instructions per second: %f\n",
- (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
- (elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec));
- if (cmd_data.locked_freq != 0) {
- fprintf(stderr, "decrypt instructions per cycle: %f\n",
- (float)(MAX_COUNT * NUM_INSTS_GARBAGE * USEC_PER_SEC) /
- ((elapsed_time.tv_sec * USEC_PER_SEC + elapsed_time.tv_usec) * 1000 *
- cmd_data.locked_freq));
- }
- return 0;
-}
diff --git a/profcollectd/libprofcollectd/config.rs b/profcollectd/libprofcollectd/config.rs
index 87242489..cbc5b7cd 100644
--- a/profcollectd/libprofcollectd/config.rs
+++ b/profcollectd/libprofcollectd/config.rs
@@ -27,7 +27,7 @@ use std::path::Path;
use std::str::FromStr;
use std::time::Duration;
-const PROFCOLLECT_CONFIG_NAMESPACE: &str = "profcollect_native_boot";
+const PROFCOLLECT_CONFIG_NAMESPACE: &str = "aconfig_flags.profcollect_native_boot";
const PROFCOLLECT_NODE_ID_PROPERTY: &str = "persist.profcollectd.node_id";
const DEFAULT_BINARY_FILTER: &str =
@@ -57,8 +57,6 @@ pub struct Config {
pub build_fingerprint: String,
/// Interval between collections.
pub collection_interval: Duration,
- /// Length of time each collection lasts for.
- pub sampling_period: Duration,
/// An optional filter to limit which binaries to or not to profile.
pub binary_filter: String,
/// Maximum size of the trace directory.
@@ -75,7 +73,6 @@ impl Config {
"collection_interval",
600,
)?),
- sampling_period: Duration::from_millis(get_device_config("sampling_period", 500)?),
binary_filter: get_device_config("binary_filter", DEFAULT_BINARY_FILTER.to_string())?,
max_trace_limit: get_device_config(
"max_trace_limit",
@@ -85,9 +82,9 @@ impl Config {
}
}
-impl ToString for Config {
- fn to_string(&self) -> String {
- serde_json::to_string(self).expect("Failed to deserialise configuration.")
+impl std::fmt::Display for Config {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", serde_json::to_string(self).expect("Failed to deserialise configuration."))
}
}
@@ -123,6 +120,13 @@ where
Ok(T::from_str(&config)?)
}
+pub fn get_sampling_period() -> Duration {
+ let default_period = 500;
+ Duration::from_millis(
+ get_device_config("sampling_period", default_period).unwrap_or(default_period),
+ )
+}
+
fn get_property<T>(key: &str, default_value: T) -> Result<T>
where
T: FromStr + ToString,
@@ -162,3 +166,11 @@ pub fn clear_data() -> Result<()> {
remove_files(&REPORT_OUTPUT_DIR)?;
Ok(())
}
+pub fn clear_processed_files() -> Result<()> {
+ read_dir(&PROFILE_OUTPUT_DIR as &Path)?
+ .filter_map(|e| e.ok())
+ .map(|e| e.path())
+ .filter(|e| e.is_file() && e != (&CONFIG_FILE as &Path))
+ .try_for_each(remove_file)?;
+ Ok(())
+}
diff --git a/profcollectd/libprofcollectd/report.rs b/profcollectd/libprofcollectd/report.rs
index e0f2ec84..60410c1a 100644
--- a/profcollectd/libprofcollectd/report.rs
+++ b/profcollectd/libprofcollectd/report.rs
@@ -29,7 +29,7 @@ use zip::write::FileOptions;
use zip::CompressionMethod::Deflated;
use zip::ZipWriter;
-use crate::config::Config;
+use crate::config::{clear_processed_files, Config};
pub const NO_USAGE_SETTING: i32 = -1;
@@ -80,6 +80,7 @@ pub fn pack_report(
zip.write_all(usage_setting.to_string().as_bytes())?;
}
zip.finish()?;
+ clear_processed_files()?;
Ok(report_filename)
}
diff --git a/profcollectd/libprofcollectd/scheduler.rs b/profcollectd/libprofcollectd/scheduler.rs
index 5558f581..8695f57c 100644
--- a/profcollectd/libprofcollectd/scheduler.rs
+++ b/profcollectd/libprofcollectd/scheduler.rs
@@ -25,7 +25,7 @@ use std::sync::Mutex;
use std::thread;
use std::time::{Duration, Instant};
-use crate::config::{Config, LOG_FILE, PROFILE_OUTPUT_DIR, TRACE_OUTPUT_DIR};
+use crate::config::{get_sampling_period, Config, LOG_FILE, PROFILE_OUTPUT_DIR, TRACE_OUTPUT_DIR};
use crate::trace_provider::{self, TraceProvider};
use anyhow::{anyhow, ensure, Context, Result};
@@ -73,7 +73,7 @@ impl Scheduler {
trace_provider.lock().unwrap().trace(
&TRACE_OUTPUT_DIR,
"periodic",
- &config.sampling_period,
+ &get_sampling_period(),
&config.binary_filter,
);
}
@@ -100,7 +100,7 @@ impl Scheduler {
trace_provider.lock().unwrap().trace(
&TRACE_OUTPUT_DIR,
tag,
- &config.sampling_period,
+ &get_sampling_period(),
&config.binary_filter,
);
}
diff --git a/simpleperf/BranchListFile_test.cpp b/simpleperf/BranchListFile_test.cpp
index 759b0218..d7f9a6a5 100644
--- a/simpleperf/BranchListFile_test.cpp
+++ b/simpleperf/BranchListFile_test.cpp
@@ -20,6 +20,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(BranchListFile, etm_branch_to_proto_string) {
std::vector<bool> branch;
for (size_t i = 0; i < 100; i++) {
diff --git a/simpleperf/CallChainJoiner_test.cpp b/simpleperf/CallChainJoiner_test.cpp
index 90460e03..4b0fa29f 100644
--- a/simpleperf/CallChainJoiner_test.cpp
+++ b/simpleperf/CallChainJoiner_test.cpp
@@ -33,6 +33,7 @@ static bool JoinCallChain(LRUCache& cache, uint32_t tid, const std::vector<uint6
return tmp_ip == expected_output_ip && tmp_sp == expected_output_sp;
}
+// @CddTest = 6.1/C-0-2
TEST(LRUCache, different_nodes) {
LRUCache cache(sizeof(CacheNode) * 2, 1);
ASSERT_EQ(cache.Stat().max_node_count, 2u);
@@ -65,6 +66,7 @@ TEST(LRUCache, different_nodes) {
ASSERT_NE(cache.FindNode(1, ip[0], sp2[0]), nullptr);
}
+// @CddTest = 6.1/C-0-2
TEST(LRUCache, extend_chains) {
// matched_node_count_to_extend_callchain = 1
// c -> b
@@ -93,6 +95,7 @@ TEST(LRUCache, extend_chains) {
ASSERT_EQ(cache3.Stat().used_node_count, 4u);
}
+// @CddTest = 6.1/C-0-2
TEST(LRUCache, avoid_ip_sp_loop) {
LRUCache cache(sizeof(CacheNode) * 2, 1);
std::vector<uint64_t> ip = {0xa, 0xb};
@@ -104,6 +107,7 @@ TEST(LRUCache, avoid_ip_sp_loop) {
ASSERT_EQ(cache.Stat().recycled_node_count, 0u);
}
+// @CddTest = 6.1/C-0-2
TEST(LRUCache, one_chain) {
LRUCache cache(sizeof(CacheNode) * 4, 1);
ASSERT_EQ(cache.Stat().max_node_count, 4u);
@@ -125,6 +129,7 @@ TEST(LRUCache, one_chain) {
ASSERT_EQ(cache.Stat().recycled_node_count, 0u);
}
+// @CddTest = 6.1/C-0-2
TEST(LRUCache, many_chains) {
LRUCache cache(sizeof(CacheNode) * 12, 1);
// 4 -> 3 -> 2 -> 1
@@ -149,6 +154,7 @@ TEST(LRUCache, many_chains) {
ASSERT_EQ(cache.FindNode(0, 0xa, 0xa), nullptr);
}
+// @CddTest = 6.1/C-0-2
class CallChainJoinerTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -164,6 +170,7 @@ class CallChainJoinerTest : public ::testing::Test {
std::unique_ptr<ScopedTempFiles> scoped_temp_files_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainJoinerTest, smoke) {
CallChainJoiner joiner(sizeof(CacheNode) * 1024, 1, true);
for (pid_t pid = 0; pid < 10; ++pid) {
@@ -230,6 +237,7 @@ TEST_F(CallChainJoinerTest, smoke) {
ASSERT_EQ(joiner.GetStat().after_join_max_chain_length, 5u);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainJoinerTest, no_original_chains) {
CallChainJoiner joiner(sizeof(CacheNode) * 1024, 1, false);
ASSERT_TRUE(joiner.AddCallChain(0, 0, CallChainJoiner::ORIGINAL_OFFLINE, {1}, {1}));
@@ -249,6 +257,7 @@ TEST_F(CallChainJoinerTest, no_original_chains) {
joiner.DumpStat();
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainJoinerTest, no_chains) {
CallChainJoiner joiner(sizeof(CacheNode) * 1024, 1, false);
ASSERT_TRUE(joiner.JoinCallChains());
diff --git a/simpleperf/ETMConstants.h b/simpleperf/ETMConstants.h
index 78e9cc26..003d88ab 100644
--- a/simpleperf/ETMConstants.h
+++ b/simpleperf/ETMConstants.h
@@ -24,6 +24,7 @@ static constexpr int ETM_OPT_CTXTID = 14;
static constexpr int ETM_OPT_CTXTID2 = 15;
static constexpr int ETM_OPT_TS = 28;
// For etm_config_reg:
+static constexpr int ETM4_CFG_BIT_CCI = 4;
static constexpr int ETM4_CFG_BIT_CTXTID = 6;
static constexpr int ETM4_CFG_BIT_VMID = 7;
static constexpr int ETM4_CFG_BIT_TS = 11;
diff --git a/simpleperf/ETMRecorder.cpp b/simpleperf/ETMRecorder.cpp
index cde1eb2b..a722df5c 100644
--- a/simpleperf/ETMRecorder.cpp
+++ b/simpleperf/ETMRecorder.cpp
@@ -229,6 +229,7 @@ void ETMRecorder::BuildEtmConfig() {
}
if (cycles_supported) {
etm_event_config_ |= 1ULL << ETM_OPT_CYCACC;
+ etm_config_reg_ |= 1U << ETM4_CFG_BIT_CCI;
if (cycle_threshold_) {
cc_threshold_config_ |= cycle_threshold_;
diff --git a/simpleperf/IOEventLoop_test.cpp b/simpleperf/IOEventLoop_test.cpp
index 74a45281..fbbc0fc8 100644
--- a/simpleperf/IOEventLoop_test.cpp
+++ b/simpleperf/IOEventLoop_test.cpp
@@ -26,6 +26,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, read) {
int fd[2];
ASSERT_EQ(0, pipe(fd));
@@ -65,6 +66,7 @@ TEST(IOEventLoop, read) {
close(fd[1]);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, write) {
int fd[2];
ASSERT_EQ(0, pipe(fd));
@@ -101,6 +103,7 @@ TEST(IOEventLoop, write) {
ASSERT_EQ(100, count);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, signal) {
IOEventLoop loop;
int count = 0;
@@ -147,10 +150,12 @@ void TestPeriodicEvents(int period_in_us, int iterations) {
ASSERT_LT(time_used, max_time_in_sec);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, periodic) {
TestPeriodicEvents(1000, 100);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, one_time_event) {
int duration_in_us = 1000;
timeval tv = {};
@@ -179,6 +184,7 @@ TEST(IOEventLoop, one_time_event) {
ASSERT_LT(time_used, max_time_in_sec);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, read_and_del_event) {
int fd[2];
ASSERT_EQ(0, pipe(fd));
@@ -204,6 +210,7 @@ TEST(IOEventLoop, read_and_del_event) {
close(fd[1]);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, disable_enable_event) {
int fd[2];
ASSERT_EQ(0, pipe(fd));
@@ -241,6 +248,7 @@ TEST(IOEventLoop, disable_enable_event) {
close(fd[1]);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, disable_enable_periodic_event) {
timeval tv;
tv.tv_sec = 0;
@@ -267,11 +275,13 @@ TEST(IOEventLoop, disable_enable_periodic_event) {
ASSERT_EQ(2u, periodic_count);
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, exit_before_loop) {
IOEventLoop loop;
ASSERT_TRUE(loop.ExitLoop());
}
+// @CddTest = 6.1/C-0-2
TEST(IOEventLoop, priority) {
int low_priority_fd[2];
ASSERT_EQ(0, pipe(low_priority_fd));
diff --git a/simpleperf/JITDebugReader_test.cpp b/simpleperf/JITDebugReader_test.cpp
index d46236a6..4aaad813 100644
--- a/simpleperf/JITDebugReader_test.cpp
+++ b/simpleperf/JITDebugReader_test.cpp
@@ -32,6 +32,7 @@
using namespace simpleperf;
using namespace simpleperf::JITDebugReader_impl;
+// @CddTest = 6.1/C-0-2
TEST(TempSymFile, smoke) {
TemporaryFile tmpfile;
std::unique_ptr<TempSymFile> symfile = TempSymFile::Create(tmpfile.path, false);
@@ -51,6 +52,7 @@ TEST(TempSymFile, smoke) {
ASSERT_EQ(strncmp(test_data.c_str(), buf, test_data.size()), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(JITDebugReader, read_dex_file_in_memory) {
// 1. Create dex file in memory. Use mmap instead of malloc, to avoid the pointer from
// being modified by memory tag (or pointer authentication?) on ARM64.
diff --git a/simpleperf/MapRecordReader_test.cpp b/simpleperf/MapRecordReader_test.cpp
index 669b31fb..d194cb56 100644
--- a/simpleperf/MapRecordReader_test.cpp
+++ b/simpleperf/MapRecordReader_test.cpp
@@ -26,6 +26,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
class MapRecordReaderTest : public ::testing::Test {
protected:
bool CreateMapRecordReader() {
@@ -54,12 +55,14 @@ class MapRecordReaderTest : public ::testing::Test {
size_t comm_record_count_ = 0;
};
+// @CddTest = 6.1/C-0-2
TEST_F(MapRecordReaderTest, ReadKernelMaps) {
ASSERT_TRUE(CreateMapRecordReader());
ASSERT_TRUE(reader_->ReadKernelMaps());
ASSERT_GT(map_record_count_, 0);
}
+// @CddTest = 6.1/C-0-2
TEST_F(MapRecordReaderTest, ReadProcessMaps) {
ASSERT_TRUE(CreateMapRecordReader());
ASSERT_TRUE(reader_->ReadProcessMaps(getpid(), 0));
@@ -67,6 +70,7 @@ TEST_F(MapRecordReaderTest, ReadProcessMaps) {
ASSERT_GT(comm_record_count_, 0);
}
+// @CddTest = 6.1/C-0-2
TEST_F(MapRecordReaderTest, MapRecordThread) {
#ifdef __ANDROID__
std::string tmpdir = "/data/local/tmp";
diff --git a/simpleperf/OfflineUnwinder_test.cpp b/simpleperf/OfflineUnwinder_test.cpp
index 7f9d9aab..c13e229c 100644
--- a/simpleperf/OfflineUnwinder_test.cpp
+++ b/simpleperf/OfflineUnwinder_test.cpp
@@ -44,6 +44,7 @@ bool CheckUnwindMaps(UnwindMaps& maps, const MapSet& map_set) {
return true;
}
+// @CddTest = 6.1/C-0-2
TEST(OfflineUnwinder, UnwindMaps) {
// 1. Create fake map entries.
std::unique_ptr<Dso> fake_dso = Dso::CreateDso(DSO_UNKNOWN_FILE, "unknown");
@@ -90,6 +91,7 @@ TEST(OfflineUnwinder, UnwindMaps) {
ASSERT_TRUE(CheckUnwindMaps(maps, map_set));
}
+// @CddTest = 6.1/C-0-2
TEST(OfflineUnwinder, CollectMetaInfo) {
std::unordered_map<std::string, std::string> info_map;
OfflineUnwinder::CollectMetaInfo(&info_map);
@@ -100,6 +102,7 @@ TEST(OfflineUnwinder, CollectMetaInfo) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(OfflineUnwinder, ARM64PackMask) {
std::unordered_map<std::string, std::string> info_map;
info_map[OfflineUnwinder::META_KEY_ARM64_PAC_MASK] = "0xff00000000";
diff --git a/simpleperf/ProbeEvents_test.cpp b/simpleperf/ProbeEvents_test.cpp
index be135386..630c5761 100644
--- a/simpleperf/ProbeEvents_test.cpp
+++ b/simpleperf/ProbeEvents_test.cpp
@@ -23,6 +23,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(probe_events, ParseKprobeEventName) {
ProbeEvent event;
ASSERT_TRUE(ProbeEvents::ParseKprobeEventName("p:myprobe do_sys_open", &event));
diff --git a/simpleperf/RecordFilter_test.cpp b/simpleperf/RecordFilter_test.cpp
index 3bbda4c8..1d5d1a06 100644
--- a/simpleperf/RecordFilter_test.cpp
+++ b/simpleperf/RecordFilter_test.cpp
@@ -30,6 +30,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
class RecordFilterTest : public ::testing::Test {
public:
RecordFilterTest() : filter(thread_tree) {}
@@ -58,10 +59,12 @@ class RecordFilterTest : public ::testing::Test {
std::unique_ptr<SampleRecord> record;
};
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, no_filter) {
ASSERT_TRUE(filter.Check(GetRecord(0, 0)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, cpu) {
filter.AddCpus({1});
SampleRecord& r = GetRecord(0, 0);
@@ -71,18 +74,21 @@ TEST_F(RecordFilterTest, cpu) {
ASSERT_FALSE(filter.Check(r));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, exclude_pid) {
filter.AddPids({1}, true);
ASSERT_FALSE(filter.Check(GetRecord(1, 1)));
ASSERT_TRUE(filter.Check(GetRecord(2, 2)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, exclude_tid) {
filter.AddTids({1}, true);
ASSERT_FALSE(filter.Check(GetRecord(1, 1)));
ASSERT_TRUE(filter.Check(GetRecord(1, 2)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, exclude_process_name_regex) {
ASSERT_TRUE(filter.AddProcessNameRegex("processA", true));
thread_tree.SetThreadName(1, 1, "processA1");
@@ -91,6 +97,7 @@ TEST_F(RecordFilterTest, exclude_process_name_regex) {
ASSERT_TRUE(filter.Check(GetRecord(2, 2)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, exclude_thread_name_regex) {
ASSERT_TRUE(filter.AddThreadNameRegex("threadA", true));
thread_tree.SetThreadName(1, 1, "processA_threadA");
@@ -100,6 +107,7 @@ TEST_F(RecordFilterTest, exclude_thread_name_regex) {
}
#if defined(__linux__)
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, exclude_uid) {
pid_t pid = getpid();
std::optional<uint32_t> uid = GetProcessUid(pid);
@@ -112,18 +120,21 @@ TEST_F(RecordFilterTest, exclude_uid) {
}
#endif // defined(__linux__)
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, include_pid) {
filter.AddPids({1}, false);
ASSERT_TRUE(filter.Check(GetRecord(1, 1)));
ASSERT_FALSE(filter.Check(GetRecord(2, 2)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, include_tid) {
filter.AddTids({1}, false);
ASSERT_TRUE(filter.Check(GetRecord(1, 1)));
ASSERT_FALSE(filter.Check(GetRecord(1, 2)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, include_process_name_regex) {
ASSERT_TRUE(filter.AddProcessNameRegex("processA", false));
thread_tree.SetThreadName(1, 1, "processA1");
@@ -132,6 +143,7 @@ TEST_F(RecordFilterTest, include_process_name_regex) {
ASSERT_FALSE(filter.Check(GetRecord(2, 2)));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, include_thread_name_regex) {
ASSERT_TRUE(filter.AddThreadNameRegex("threadA", false));
thread_tree.SetThreadName(1, 1, "processA_threadA");
@@ -141,6 +153,7 @@ TEST_F(RecordFilterTest, include_thread_name_regex) {
}
#if defined(__linux__)
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, include_uid) {
pid_t pid = getpid();
std::optional<uint32_t> uid = GetProcessUid(pid);
@@ -152,6 +165,7 @@ TEST_F(RecordFilterTest, include_uid) {
}
#endif // defined(__linux__)
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, global_time_filter) {
ASSERT_TRUE(
SetFilterData("GLOBAL_BEGIN 1000\n"
@@ -179,6 +193,7 @@ TEST_F(RecordFilterTest, global_time_filter) {
ASSERT_FALSE(filter.Check(r));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, process_time_filter) {
ASSERT_TRUE(
SetFilterData("PROCESS_BEGIN 1 1000\n"
@@ -202,6 +217,7 @@ TEST_F(RecordFilterTest, process_time_filter) {
ASSERT_FALSE(filter.Check(r));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, thread_time_filter) {
ASSERT_TRUE(
SetFilterData("THREAD_BEGIN 1 1000\n"
@@ -225,6 +241,7 @@ TEST_F(RecordFilterTest, thread_time_filter) {
ASSERT_FALSE(filter.Check(r));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, clock_in_time_filter) {
// If there is no filter data, any clock is fine.
ASSERT_TRUE(filter.CheckClock("monotonic"));
@@ -239,6 +256,7 @@ TEST_F(RecordFilterTest, clock_in_time_filter) {
ASSERT_FALSE(filter.CheckClock("monotonic"));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, error_in_time_filter) {
// no timestamp error
ASSERT_FALSE(SetFilterData("GLOBAL_BEGIN"));
@@ -290,6 +308,7 @@ class ParseRecordFilterCommand : public Command {
} // namespace
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFilterTest, parse_options) {
ParseRecordFilterCommand filter_cmd(filter);
diff --git a/simpleperf/RecordReadThread.cpp b/simpleperf/RecordReadThread.cpp
index 2ab61278..2d034bc1 100644
--- a/simpleperf/RecordReadThread.cpp
+++ b/simpleperf/RecordReadThread.cpp
@@ -408,6 +408,7 @@ bool RecordReadThread::HandleAddEventFds(IOEventLoop& loop,
success = false;
break;
}
+ has_etm_events_ = true;
}
cpu_map[fd->Cpu()] = fd;
} else {
@@ -620,6 +621,9 @@ void RecordReadThread::PushRecordToRecordBuffer(KernelRecordReader* kernel_recor
}
void RecordReadThread::ReadAuxDataFromKernelBuffer(bool* has_data) {
+ if (!has_etm_events_) {
+ return;
+ }
for (auto& reader : kernel_record_readers_) {
EventFd* event_fd = reader.GetEventFd();
if (event_fd->HasAuxBuffer()) {
@@ -659,6 +663,14 @@ void RecordReadThread::ReadAuxDataFromKernelBuffer(bool* has_data) {
}
bool RecordReadThread::SendDataNotificationToMainThread() {
+ if (has_etm_events_) {
+ // For ETM recording, the default buffer size is large enough to hold ETM data for several
+ // seconds. To reduce impact of processing ETM data (especially when --decode-etm is used),
+ // delay processing ETM data until the buffer is half full.
+ if (record_buffer_.GetFreeSize() >= record_buffer_.size() / 2) {
+ return true;
+ }
+ }
if (!has_data_notification_.load(std::memory_order_relaxed)) {
has_data_notification_ = true;
char unused = 0;
diff --git a/simpleperf/RecordReadThread.h b/simpleperf/RecordReadThread.h
index c104b083..893f8234 100644
--- a/simpleperf/RecordReadThread.h
+++ b/simpleperf/RecordReadThread.h
@@ -211,6 +211,7 @@ class RecordReadThread {
std::unique_ptr<std::thread> read_thread_;
std::vector<KernelRecordReader> kernel_record_readers_;
pid_t exclude_pid_ = -1;
+ bool has_etm_events_ = false;
std::unordered_set<EventFd*> event_fds_disabled_by_kernel_;
diff --git a/simpleperf/RecordReadThread_test.cpp b/simpleperf/RecordReadThread_test.cpp
index e597e443..2ff9a460 100644
--- a/simpleperf/RecordReadThread_test.cpp
+++ b/simpleperf/RecordReadThread_test.cpp
@@ -32,6 +32,7 @@ using ::testing::Truly;
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
class RecordBufferTest : public ::testing::Test {
protected:
void PushRecord(uint32_t type, size_t size) {
@@ -57,6 +58,7 @@ class RecordBufferTest : public ::testing::Test {
std::unique_ptr<RecordBuffer> buffer_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(RecordBufferTest, fifo) {
for (size_t loop = 0; loop < 10; ++loop) {
buffer_.reset(new RecordBuffer(sizeof(perf_event_header) * 10));
@@ -73,6 +75,7 @@ TEST_F(RecordBufferTest, fifo) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(RecordParser, smoke) {
std::unique_ptr<RecordFileReader> reader =
RecordFileReader::CreateInstance(GetTestData(PERF_DATA_NO_UNWIND));
@@ -113,6 +116,7 @@ TEST(RecordParser, smoke) {
}));
}
+// @CddTest = 6.1/C-0-2
TEST(RecordParser, GetStackSizePos_with_PerfSampleReadType) {
const EventType* type = FindEventTypeByName("cpu-clock");
ASSERT_TRUE(type != nullptr);
@@ -190,6 +194,7 @@ static inline std::function<bool(size_t&)> SetArg(size_t value) {
};
}
+// @CddTest = 6.1/C-0-2
TEST(KernelRecordReader, smoke) {
// 1. Create fake records.
perf_event_attr attr = CreateFakeEventAttr();
@@ -229,6 +234,7 @@ TEST(KernelRecordReader, smoke) {
ASSERT_FALSE(reader.MoveToNextRecord(parser));
}
+// @CddTest = 6.1/C-0-2
class RecordReadThreadTest : public ::testing::Test {
protected:
std::vector<EventFd*> CreateFakeEventFds(const perf_event_attr& attr, size_t event_fd_count) {
@@ -270,6 +276,7 @@ class RecordReadThreadTest : public ::testing::Test {
std::vector<std::unique_ptr<MockEventFd>> event_fds_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, handle_cmds) {
perf_event_attr attr = CreateFakeEventAttr();
records_ = CreateFakeRecords(attr, 2, 0, 0);
@@ -291,6 +298,7 @@ TEST_F(RecordReadThreadTest, handle_cmds) {
ASSERT_TRUE(thread.StopReadThread());
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, read_records) {
perf_event_attr attr = CreateFakeEventAttr();
RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
@@ -323,6 +331,7 @@ TEST_F(RecordReadThreadTest, read_records) {
}
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, process_sample_record) {
perf_event_attr attr = CreateFakeEventAttr();
attr.sample_type |= PERF_SAMPLE_STACK_USER;
@@ -377,6 +386,7 @@ TEST_F(RecordReadThreadTest, process_sample_record) {
// Test that the data notification exists until the RecordBuffer is empty. So we can read all
// records even if reading one record at a time.
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, has_data_notification_until_buffer_empty) {
perf_event_attr attr = CreateFakeEventAttr();
RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
@@ -403,6 +413,7 @@ TEST_F(RecordReadThreadTest, has_data_notification_until_buffer_empty) {
ASSERT_TRUE(thread.RemoveEventFds(event_fds));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, no_truncated_samples) {
perf_event_attr attr = CreateFakeEventAttr();
attr.sample_type |= PERF_SAMPLE_STACK_USER;
@@ -426,6 +437,7 @@ TEST_F(RecordReadThreadTest, no_truncated_samples) {
ASSERT_EQ(thread.GetStat().userspace_truncated_stack_samples, 0u);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, exclude_perf) {
perf_event_attr attr = CreateFakeEventAttr();
attr.sample_type |= PERF_SAMPLE_STACK_USER;
@@ -475,6 +487,7 @@ struct FakeAuxData {
: buf1(buf1_size, c), buf2(buf2_size, c), pad(pad_size, 0), lost(lost) {}
};
+// @CddTest = 6.1/C-0-2
TEST_F(RecordReadThreadTest, read_aux_data) {
ScopedEventTypes scoped_types("cs-etm,0,0");
const EventType* type = FindEventTypeByName("cs-etm");
@@ -569,4 +582,4 @@ TEST_F(RecordReadThreadTest, read_aux_data) {
}
ASSERT_EQ(aux_data_size, thread.GetStat().aux_data_size);
ASSERT_EQ(lost_aux_data_size, thread.GetStat().lost_aux_data_size);
-} \ No newline at end of file
+}
diff --git a/simpleperf/RegEx_test.cpp b/simpleperf/RegEx_test.cpp
index cbb25ae0..978772c4 100644
--- a/simpleperf/RegEx_test.cpp
+++ b/simpleperf/RegEx_test.cpp
@@ -20,6 +20,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(RegEx, smoke) {
auto re = RegEx::Create("b+");
ASSERT_EQ(re->GetPattern(), "b+");
@@ -42,6 +43,7 @@ TEST(RegEx, smoke) {
ASSERT_EQ(re->Replace("ababb", "c").value(), "acac");
}
+// @CddTest = 6.1/C-0-2
TEST(RegEx, invalid_pattern) {
ASSERT_TRUE(RegEx::Create("?hello") == nullptr);
}
diff --git a/simpleperf/cmd_api_test.cpp b/simpleperf/cmd_api_test.cpp
index 41a2a165..d1fb044a 100644
--- a/simpleperf/cmd_api_test.cpp
+++ b/simpleperf/cmd_api_test.cpp
@@ -90,6 +90,7 @@ static void RecordApp(const std::string& package_name, const std::string& apk_pa
#endif // defined(__ANDROID__)
+// @CddTest = 6.1/C-0-2
TEST(cmd_api, java_app) {
#if defined(__ANDROID__)
RecordApp("simpleperf.demo.java_api", GetTestData("java_api.apk"));
@@ -98,10 +99,11 @@ TEST(cmd_api, java_app) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_api, native_app) {
#if defined(__ANDROID__)
RecordApp("simpleperf.demo.cpp_api", GetTestData("cpp_api.apk"));
#else
GTEST_LOG_(INFO) << "This test tests recording apps on Android.";
#endif
-} \ No newline at end of file
+}
diff --git a/simpleperf/cmd_boot_record_test.cpp b/simpleperf/cmd_boot_record_test.cpp
index 25b2aff0..73266ce2 100644
--- a/simpleperf/cmd_boot_record_test.cpp
+++ b/simpleperf/cmd_boot_record_test.cpp
@@ -28,6 +28,7 @@ static std::unique_ptr<Command> BootRecordCmd() {
return CreateCommandInstance("boot-record");
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_boot_record, smoke) {
TEST_REQUIRE_ROOT();
ASSERT_TRUE(BootRecordCmd()->Run({"--enable", "-a -g --duration 1"}));
diff --git a/simpleperf/cmd_debug_unwind_test.cpp b/simpleperf/cmd_debug_unwind_test.cpp
index d0bbfe8f..2bf14a59 100644
--- a/simpleperf/cmd_debug_unwind_test.cpp
+++ b/simpleperf/cmd_debug_unwind_test.cpp
@@ -35,6 +35,7 @@ static std::unique_ptr<Command> DebugUnwindCmd() {
return CreateCommandInstance("debug-unwind");
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, unwind_sample_option) {
std::string input_data = GetTestData(PERF_DATA_NO_UNWIND);
CaptureStdout capture;
@@ -44,6 +45,7 @@ TEST(cmd_debug_unwind, unwind_sample_option) {
ASSERT_NE(capture.Finish().find("sample_time: 1516379654300997"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, sample_time_option) {
std::string input_data = GetTestData(PERF_DATA_NO_UNWIND);
CaptureStdout capture;
@@ -58,6 +60,7 @@ TEST(cmd_debug_unwind, sample_time_option) {
ASSERT_NE(output.find("sample_time: 1516379655959122"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, output_option) {
std::string input_data = GetTestData(PERF_DATA_NO_UNWIND);
TemporaryFile tmpfile;
@@ -69,6 +72,7 @@ TEST(cmd_debug_unwind, output_option) {
ASSERT_NE(output.find("sample_time: 1516379654300997"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, symfs_option) {
std::string input_data = GetTestData(NATIVELIB_IN_APK_PERF_DATA);
CaptureStdout capture;
@@ -80,6 +84,7 @@ TEST(cmd_debug_unwind, symfs_option) {
std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, unwind_with_ip_zero_in_callchain) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
@@ -88,6 +93,7 @@ TEST(cmd_debug_unwind, unwind_with_ip_zero_in_callchain) {
ASSERT_NE(capture.Finish().find("sample_time: 152526249937103"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, unwind_embedded_lib_in_apk) {
// Check if we can unwind through a native library embedded in an apk. In the profiling data
// file, there is a sample with ip address pointing to
@@ -107,6 +113,7 @@ TEST(cmd_debug_unwind, unwind_embedded_lib_in_apk) {
ASSERT_NE(output.find("dso_2: /bionic/lib64/libc.so"), std::string::npos) << output;
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, unwind_sample_in_unwinding_debug_info_file) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
@@ -116,6 +123,7 @@ TEST(cmd_debug_unwind, unwind_sample_in_unwinding_debug_info_file) {
ASSERT_NE(output.find("symbol_5: android.os.Handler.post"), std::string::npos) << output;
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, skip_sample_print_option) {
std::string input_data = GetTestData(PERF_DATA_NO_UNWIND);
CaptureStdout capture;
@@ -128,6 +136,7 @@ TEST(cmd_debug_unwind, skip_sample_print_option) {
ASSERT_NE(output.find("unwinding_sample_count: 8"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, generate_test_file) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -143,6 +152,7 @@ TEST(cmd_debug_unwind, generate_test_file) {
ASSERT_NE(output.find("symbol_2: android.os.Handler.enqueueMessage"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, generate_test_file_with_build_id) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -157,6 +167,7 @@ TEST(cmd_debug_unwind, generate_test_file_with_build_id) {
ASSERT_STREQ(build_ids[0].filename, "/apex/com.android.runtime/lib64/bionic/libc.so");
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, generate_report) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -169,6 +180,7 @@ TEST(cmd_debug_unwind, generate_report) {
ASSERT_NE(output.find("symbol_2: android.os.Handler.enqueueMessage"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_debug_unwind, unwind_sample_for_small_map_range) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
diff --git a/simpleperf/cmd_dumprecord_test.cpp b/simpleperf/cmd_dumprecord_test.cpp
index e6cc5e23..ffdcbc2d 100644
--- a/simpleperf/cmd_dumprecord_test.cpp
+++ b/simpleperf/cmd_dumprecord_test.cpp
@@ -26,22 +26,27 @@ static std::unique_ptr<Command> DumpCmd() {
return CreateCommandInstance("dump");
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, record_file_option) {
ASSERT_TRUE(DumpCmd()->Run({GetTestData("perf.data")}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, input_option) {
ASSERT_TRUE(DumpCmd()->Run({"-i", GetTestData("perf.data")}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, dump_data_generated_by_linux_perf) {
ASSERT_TRUE(DumpCmd()->Run({GetTestData(PERF_DATA_GENERATED_BY_LINUX_PERF)}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, dump_callchain_records) {
ASSERT_TRUE(DumpCmd()->Run({GetTestData(PERF_DATA_WITH_CALLCHAIN_RECORD)}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, dump_callchain_of_sample_records) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
@@ -51,6 +56,7 @@ TEST(cmd_dump, dump_callchain_of_sample_records) {
ASSERT_NE(data.find("__ioctl (/system/lib64/libc.so[+70b6c])"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, dump_tracepoint_fields_of_sample_records) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
@@ -66,6 +72,7 @@ TEST(cmd_dump, dump_tracepoint_fields_of_sample_records) {
std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, etm_data) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
@@ -78,6 +85,7 @@ TEST(cmd_dump, etm_data) {
ASSERT_NE(data.find("OCSD_GEN_TRC_ELEM_INSTR_RANGE"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_dump, dump_arm_regs_recorded_in_arm64) {
ASSERT_TRUE(DumpCmd()->Run({GetTestData("perf_with_arm_regs.data")}));
}
diff --git a/simpleperf/cmd_inject_test.cpp b/simpleperf/cmd_inject_test.cpp
index 9bb1efba..b6e6456c 100644
--- a/simpleperf/cmd_inject_test.cpp
+++ b/simpleperf/cmd_inject_test.cpp
@@ -59,6 +59,7 @@ static void CheckMatchingExpectedData(const std::string& name, std::string& data
ASSERT_EQ(data, expected_data);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, smoke) {
std::string data;
ASSERT_TRUE(RunInjectCmd({}, &data));
@@ -67,6 +68,7 @@ TEST(cmd_inject, smoke) {
CheckMatchingExpectedData("perf_inject.data", data);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, binary_option) {
// Test that data for etm_test_loop is generated when selected by --binary.
std::string data;
@@ -86,10 +88,12 @@ TEST(cmd_inject, binary_option) {
ASSERT_EQ(data.find("etm_test_loop"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, exclude_perf_option) {
ASSERT_TRUE(RunInjectCmd({"--exclude-perf"}, nullptr));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, output_option) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -100,6 +104,7 @@ TEST(cmd_inject, output_option) {
CheckMatchingExpectedData("perf_inject.data", autofdo_data);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, skip_empty_output_file) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -110,6 +115,7 @@ TEST(cmd_inject, skip_empty_output_file) {
tmpfile.DoNotRemove();
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, inject_kernel_data) {
const std::string recording_file =
GetTestData(std::string("etm") + OS_PATH_SEPARATOR + "perf_kernel.data");
@@ -132,6 +138,7 @@ TEST(cmd_inject, inject_kernel_data) {
ASSERT_EQ(output, autofdo_output);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, unformatted_trace) {
std::string data;
std::string perf_with_unformatted_trace =
@@ -142,6 +149,7 @@ TEST(cmd_inject, unformatted_trace) {
CheckMatchingExpectedData("perf_inject.data", data);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, multiple_input_files) {
std::string data;
std::string perf_data = GetTestData(PERF_DATA_ETM_TEST_LOOP);
@@ -165,6 +173,7 @@ TEST(cmd_inject, multiple_input_files) {
ASSERT_NE(data.find("106c->1074:200"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, merge_branch_list_files) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -178,6 +187,7 @@ TEST(cmd_inject, merge_branch_list_files) {
ASSERT_NE(autofdo_data.find("106c->1074:200"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, report_warning_when_overflow) {
CapturedStderr capture;
std::vector<std::unique_ptr<TemporaryFile>> branch_list_files;
@@ -217,6 +227,7 @@ TEST(cmd_inject, report_warning_when_overflow) {
ASSERT_NE(autofdo_data.find("106c->1074:18446744073709551615"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, accept_missing_aux_data) {
// Recorded with "-e cs-etm:u --user-buffer-size 64k sleep 1".
std::string perf_data = GetTestData("etm/perf_with_missing_aux_data.data");
@@ -225,6 +236,7 @@ TEST(cmd_inject, accept_missing_aux_data) {
ASSERT_TRUE(RunInjectCmd({"--output", "branch-list", "-i", perf_data, "-o", tmpfile.path}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, read_lbr_data) {
// Convert perf.data to AutoFDO text format.
std::string perf_data_path = GetTestData("lbr/perf_lbr.data");
@@ -264,6 +276,7 @@ TEST(cmd_inject, read_lbr_data) {
ASSERT_NE(data.find("194d->1940:706"), data.npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_inject, inject_small_binary) {
// etm_test_loop_small, a binary compiled with
// "-Wl,-z,noseparate-code", where the file is smaller than its text
diff --git a/simpleperf/cmd_kmem_test.cpp b/simpleperf/cmd_kmem_test.cpp
index b34f6148..7c66be41 100644
--- a/simpleperf/cmd_kmem_test.cpp
+++ b/simpleperf/cmd_kmem_test.cpp
@@ -85,15 +85,18 @@ static bool RunKmemRecordCmd(std::vector<std::string> v, const char* output_file
return KmemCmd()->Run(v);
}
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, record_slab) {
TEST_IN_ROOT(ASSERT_TRUE(RunKmemRecordCmd({"--slab"})));
}
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, record_fp_callchain_sampling) {
TEST_IN_ROOT(ASSERT_TRUE(RunKmemRecordCmd({"--slab", "-g"})));
TEST_IN_ROOT(ASSERT_TRUE(RunKmemRecordCmd({"--slab", "--call-graph", "fp"})));
}
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, record_and_report) {
TemporaryFile tmp_file;
TEST_IN_ROOT({
@@ -104,6 +107,7 @@ TEST(kmem_cmd, record_and_report) {
});
}
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, record_and_report_callgraph) {
TemporaryFile tmp_file;
TEST_IN_ROOT({
@@ -116,6 +120,7 @@ TEST(kmem_cmd, record_and_report_callgraph) {
#endif
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, report) {
ReportResult result;
KmemReportFile(PERF_DATA_WITH_KMEM_SLAB_CALLGRAPH_RECORD, {}, &result);
@@ -124,6 +129,7 @@ TEST(kmem_cmd, report) {
ASSERT_NE(result.content.find("__alloc_skb"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, report_all_sort_options) {
ReportResult result;
KmemReportFile(
@@ -134,6 +140,7 @@ TEST(kmem_cmd, report_all_sort_options) {
ASSERT_NE(result.content.find("GfpFlags"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(kmem_cmd, report_callgraph) {
ReportResult result;
KmemReportFile(PERF_DATA_WITH_KMEM_SLAB_CALLGRAPH_RECORD, {"-g"}, &result);
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp
index 963259d1..926b7f7e 100644
--- a/simpleperf/cmd_list.cpp
+++ b/simpleperf/cmd_list.cpp
@@ -246,8 +246,8 @@ static void PrintRawEventTypes(const std::string& type_desc) {
}
static bool IsEventTypeSupported(const EventType& event_type) {
- // Because PMU events are provided by kernel, we assume it's supported.
- if (event_type.IsPmuEvent()) {
+ // PMU and tracepoint events are provided by kernel. So we assume they're supported.
+ if (event_type.IsPmuEvent() || event_type.IsTracepointEvent()) {
return true;
}
perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
diff --git a/simpleperf/cmd_list_test.cpp b/simpleperf/cmd_list_test.cpp
index e2f804da..940f7595 100644
--- a/simpleperf/cmd_list_test.cpp
+++ b/simpleperf/cmd_list_test.cpp
@@ -21,6 +21,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
class ListCommandTest : public ::testing::Test {
protected:
virtual void SetUp() {
@@ -31,22 +32,27 @@ class ListCommandTest : public ::testing::Test {
std::unique_ptr<Command> list_cmd;
};
+// @CddTest = 6.1/C-0-2
TEST_F(ListCommandTest, no_options) {
ASSERT_TRUE(list_cmd->Run({}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ListCommandTest, one_option) {
ASSERT_TRUE(list_cmd->Run({"sw"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ListCommandTest, multiple_options) {
ASSERT_TRUE(list_cmd->Run({"hw", "tracepoint"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ListCommandTest, show_features_option) {
ASSERT_TRUE(list_cmd->Run({"--show-features"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ListCommandTest, pmu_option) {
ASSERT_TRUE(list_cmd->Run({"pmu"}));
}
diff --git a/simpleperf/cmd_merge_test.cpp b/simpleperf/cmd_merge_test.cpp
index 482d0893..1a60c507 100644
--- a/simpleperf/cmd_merge_test.cpp
+++ b/simpleperf/cmd_merge_test.cpp
@@ -46,6 +46,7 @@ static std::string GetReport(const std::string& record_file) {
return data;
}
+// @CddTest = 6.1/C-0-2
TEST(merge_cmd, input_output_options) {
// missing arguments
ASSERT_FALSE(MergeCmd()->Run({}));
@@ -63,6 +64,7 @@ TEST(merge_cmd, input_output_options) {
ASSERT_TRUE(MergeCmd()->Run({"-i", input_file, "-i", input_file, "-o", tmpfile.path}));
}
+// @CddTest = 6.1/C-0-2
TEST(merge_cmd, merge_two_files) {
std::string input_file1 = GetTestData("perf_merge1.data");
std::string input_file2 = GetTestData("perf_merge2.data");
diff --git a/simpleperf/cmd_monitor_test.cpp b/simpleperf/cmd_monitor_test.cpp
index 963a9808..8264c966 100644
--- a/simpleperf/cmd_monitor_test.cpp
+++ b/simpleperf/cmd_monitor_test.cpp
@@ -59,15 +59,18 @@ static ::testing::AssertionResult RunMonitorCmd(std::vector<std::string> v, std:
return (result ? ::testing::AssertionSuccess() : ::testing::AssertionFailure());
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, no_options) {
std::string output;
ASSERT_FALSE(RunMonitorCmd({}, output));
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, no_event) {
ASSERT_FALSE(MonitorCmd()->Run({"-a", "--duration", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, global) {
TEST_REQUIRE_ROOT();
std::string output;
@@ -75,6 +78,7 @@ TEST(monitor_cmd, global) {
ASSERT_GT(output.size(), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, no_perf) {
TEST_REQUIRE_ROOT();
std::string output;
@@ -82,6 +86,7 @@ TEST(monitor_cmd, no_perf) {
ASSERT_GT(output.size(), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, with_callchain) {
TEST_REQUIRE_ROOT();
std::string output;
@@ -89,6 +94,7 @@ TEST(monitor_cmd, with_callchain) {
ASSERT_GT(output.size(), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, with_callchain_fp) {
TEST_REQUIRE_ROOT();
std::string output;
@@ -96,6 +102,7 @@ TEST(monitor_cmd, with_callchain_fp) {
ASSERT_GT(output.size(), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, with_callchain_dwarf) {
TEST_REQUIRE_ROOT();
std::string output;
@@ -103,18 +110,21 @@ TEST(monitor_cmd, with_callchain_dwarf) {
ASSERT_GT(output.size(), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, frequency) {
TEST_REQUIRE_ROOT();
std::string output;
ASSERT_TRUE(RunMonitorCmd({"-a", "-f", "1"}, output));
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, count) {
TEST_REQUIRE_ROOT();
std::string output;
ASSERT_TRUE(RunMonitorCmd({"-a", "-c", "10000000"}, output));
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, cpu_percent) {
TEST_REQUIRE_ROOT();
std::string output;
@@ -124,6 +134,7 @@ TEST(monitor_cmd, cpu_percent) {
ASSERT_FALSE(RunMonitorCmd({"-a", "--cpu-percent", "101"}, output));
}
+// @CddTest = 6.1/C-0-2
TEST(monitor_cmd, record_filter_options) {
TEST_REQUIRE_ROOT();
std::string output;
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 40582045..cb9ad884 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -22,6 +22,7 @@
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
+#include <chrono>
#include <filesystem>
#include <optional>
#include <set>
@@ -111,8 +112,8 @@ static constexpr size_t DEFAULT_CALL_CHAIN_JOINER_CACHE_SIZE = 8 * kMegabyte;
static constexpr size_t kDefaultAuxBufferSize = 4 * kMegabyte;
// On Pixel 3, it takes about 1ms to enable ETM, and 16-40ms to disable ETM and copy 4M ETM data.
-// So make default period to 100ms.
-static constexpr double kDefaultEtmDataFlushPeriodInSec = 0.1;
+// So make default interval to 100ms.
+static constexpr uint32_t kDefaultEtmDataFlushIntervalInMs = 100;
struct TimeStat {
uint64_t prepare_recording_time = 0;
@@ -316,6 +317,8 @@ RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING
"--record-timestamp Generate timestamp packets in ETM stream.\n"
"--record-cycles Generate cycle count packets in ETM stream.\n"
"--cycle-threshold <threshold> Set cycle count counter threshold for ETM cycle count packets.\n"
+"--etm-flush-interval <interval> Set the interval between ETM data flushes from the ETR buffer\n"
+" to the perf event buffer (in milliseconds). Default is 100 ms.\n"
"\n"
"Other options:\n"
"--exit-with-parent Stop recording when the thread starting simpleperf dies.\n"
@@ -480,6 +483,7 @@ RECORD_FILTER_OPTION_HELP_MSG_FOR_RECORDING
std::unique_ptr<ETMBranchListGenerator> etm_branch_list_generator_;
std::unique_ptr<RegEx> binary_name_regex_;
+ std::chrono::milliseconds etm_flush_interval_{kDefaultEtmDataFlushIntervalInMs};
};
std::string RecordCommand::LongHelpString() const {
@@ -631,7 +635,7 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
} else {
need_to_check_targets = true;
}
- if (delay_in_ms_ != 0) {
+ if (delay_in_ms_ != 0 || event_selection_set_.HasAuxTrace()) {
event_selection_set_.SetEnableCondition(false, false);
}
@@ -755,6 +759,12 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
}
}
if (event_selection_set_.HasAuxTrace()) {
+ // ETM events can only be enabled successfully after MmapEventFiles().
+ if (delay_in_ms_ == 0 && !event_selection_set_.IsEnabledOnExec()) {
+ if (!event_selection_set_.EnableETMEvents()) {
+ return false;
+ }
+ }
// ETM data is dumped to kernel buffer only when there is no thread traced by ETM. It happens
// either when all monitored threads are scheduled off cpu, or when all etm perf events are
// disabled.
@@ -762,10 +772,9 @@ bool RecordCommand::PrepareRecording(Workload* workload) {
// makes less than expected data, especially in system wide recording. So add a periodic event
// to flush etm data by temporarily disable all perf events.
auto etm_flush = [this]() {
- return event_selection_set_.SetEnableEvents(false) &&
- event_selection_set_.SetEnableEvents(true);
+ return event_selection_set_.DisableETMEvents() && event_selection_set_.EnableETMEvents();
};
- if (!loop->AddPeriodicEvent(SecondToTimeval(kDefaultEtmDataFlushPeriodInSec), etm_flush)) {
+ if (!loop->AddPeriodicEvent(SecondToTimeval(etm_flush_interval_.count() / 1000.0), etm_flush)) {
return false;
}
@@ -800,6 +809,12 @@ bool RecordCommand::DoRecording(Workload* workload) {
return false;
}
time_stat_.stop_recording_time = GetSystemClock();
+ if (event_selection_set_.HasAuxTrace()) {
+ // Disable ETM events to flush the last ETM data.
+ if (!event_selection_set_.DisableETMEvents()) {
+ return false;
+ }
+ }
if (!event_selection_set_.SyncKernelBuffer()) {
return false;
}
@@ -1041,6 +1056,10 @@ bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
if (options.PullBoolValue("--decode-etm")) {
etm_branch_list_generator_ = ETMBranchListGenerator::Create(system_wide_collection_);
}
+ uint32_t interval = 0;
+ if (options.PullUintValue("--etm-flush-interval", &interval) && interval != 0) {
+ etm_flush_interval_ = std::chrono::milliseconds(interval);
+ }
if (options.PullBoolValue("--record-timestamp")) {
ETMRecorder& recorder = ETMRecorder::GetInstance();
diff --git a/simpleperf/cmd_record_impl.h b/simpleperf/cmd_record_impl.h
index 29f44809..e8561636 100644
--- a/simpleperf/cmd_record_impl.h
+++ b/simpleperf/cmd_record_impl.h
@@ -51,6 +51,8 @@ inline const OptionFormatMap& GetRecordCmdOptionFormats() {
{"--cycle-threshold", {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--decode-etm", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--delay", {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
+ {"--etm-flush-interval",
+ {OptionValueType::UINT, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--record-timestamp", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--record-cycles", {OptionValueType::NONE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
{"--duration", {OptionValueType::DOUBLE, OptionType::SINGLE, AppRunnerType::ALLOWED}},
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 345a128b..898d8756 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -85,10 +85,12 @@ static bool RunRecordCmd(std::vector<std::string> v, const char* output_file = n
return RecordCmd()->Run(v);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, no_options) {
ASSERT_TRUE(RunRecordCmd({}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, system_wide_option) {
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a"})));
}
@@ -115,16 +117,19 @@ static void CheckEventType(const std::string& record_file, const std::string& ev
FAIL();
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, sample_period_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-c", "100000"}, tmpfile.path));
CheckEventType(tmpfile.path, GetDefaultEvent(), 100000u, 0);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, event_option) {
ASSERT_TRUE(RunRecordCmd({"-e", "cpu-clock"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, freq_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-f", "99"}, tmpfile.path));
@@ -134,6 +139,7 @@ TEST(record_cmd, freq_option) {
ASSERT_FALSE(RunRecordCmd({"-f", std::to_string(UINT_MAX)}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, multiple_freq_or_sample_period_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-f", "99", "-e", "task-clock", "-c", "1000000", "-e", "cpu-clock"},
@@ -142,11 +148,13 @@ TEST(record_cmd, multiple_freq_or_sample_period_option) {
CheckEventType(tmpfile.path, "cpu-clock", 1000000u, 0u);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, output_file_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "-e", GetDefaultEvent(), "sleep", SLEEP_SEC}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, dump_kernel_mmap) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
@@ -167,6 +175,7 @@ TEST(record_cmd, dump_kernel_mmap) {
ASSERT_TRUE(have_kernel_mmap);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, dump_build_id_feature) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
@@ -177,10 +186,12 @@ TEST(record_cmd, dump_build_id_feature) {
ASSERT_GT(reader->FeatureSectionDescriptors().size(), 0u);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, tracepoint_event) {
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a", "-e", "sched:sched_switch"})));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, rN_event) {
TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
@@ -211,6 +222,7 @@ TEST(record_cmd, rN_event) {
ASSERT_EQ(event_number, attrs[0].attr.config);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, branch_sampling) {
TEST_REQUIRE_HW_COUNTER();
if (IsBranchSamplingSupported()) {
@@ -225,14 +237,17 @@ TEST(record_cmd, branch_sampling) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, event_modifier) {
ASSERT_TRUE(RunRecordCmd({"-e", GetDefaultEvent() + std::string(":u")}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, fp_callchain_sampling) {
ASSERT_TRUE(RunRecordCmd({"--call-graph", "fp"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, fp_callchain_sampling_warning_on_arm) {
if (GetTargetArch() != ARCH_ARM) {
GTEST_LOG_(INFO) << "This test does nothing as it only tests on arm arch.";
@@ -245,10 +260,12 @@ TEST(record_cmd, fp_callchain_sampling_warning_on_arm) {
testing::ExitedWithCode(0), "doesn't work well on arm");
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, system_wide_fp_callchain_sampling) {
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a", "--call-graph", "fp"})));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, dwarf_callchain_sampling) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
@@ -270,12 +287,14 @@ TEST(record_cmd, dwarf_callchain_sampling) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, system_wide_dwarf_callchain_sampling) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
TEST_IN_ROOT(RunRecordCmd({"-a", "--call-graph", "dwarf"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, no_unwind_option) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
@@ -283,6 +302,7 @@ TEST(record_cmd, no_unwind_option) {
ASSERT_FALSE(RunRecordCmd({"--no-unwind"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, post_unwind_option) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
@@ -294,6 +314,7 @@ TEST(record_cmd, post_unwind_option) {
ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf", "--post-unwind=no"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, existing_processes) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
@@ -302,6 +323,7 @@ TEST(record_cmd, existing_processes) {
ASSERT_TRUE(RunRecordCmd({"-p", pid_list}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, existing_threads) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
@@ -311,17 +333,20 @@ TEST(record_cmd, existing_threads) {
ASSERT_TRUE(RunRecordCmd({"-t", tid_list}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, no_monitored_threads) {
TemporaryFile tmpfile;
ASSERT_FALSE(RecordCmd()->Run({"-o", tmpfile.path}));
ASSERT_FALSE(RecordCmd()->Run({"-o", tmpfile.path, ""}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, more_than_one_event_types) {
ASSERT_TRUE(RunRecordCmd({"-e", "task-clock,cpu-clock"}));
ASSERT_TRUE(RunRecordCmd({"-e", "task-clock", "-e", "cpu-clock"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, mmap_page_option) {
ASSERT_TRUE(RunRecordCmd({"-m", "1"}));
ASSERT_FALSE(RunRecordCmd({"-m", "0"}));
@@ -345,6 +370,7 @@ static void CheckKernelSymbol(const std::string& path, bool need_kallsyms, bool*
*success = true;
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, kernel_symbol) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols"}, tmpfile.path));
@@ -390,6 +416,7 @@ static bool CheckDumpedSymbols(const std::string& path, bool allow_dumped_symbol
return true;
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, no_dump_symbols) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
@@ -408,6 +435,7 @@ TEST(record_cmd, no_dump_symbols) {
ASSERT_TRUE(CheckDumpedSymbols(tmpfile.path, false));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, dump_kernel_symbols) {
TEST_REQUIRE_ROOT();
TemporaryFile tmpfile;
@@ -423,6 +451,7 @@ TEST(record_cmd, dump_kernel_symbols) {
ASSERT_TRUE(has_kernel_symbols);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, group_option) {
ASSERT_TRUE(RunRecordCmd({"--group", "task-clock,cpu-clock", "-m", "16"}));
ASSERT_TRUE(
@@ -430,10 +459,12 @@ TEST(record_cmd, group_option) {
"--group", "task-clock:k,cpu-clock:k", "-m", "16"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, symfs_option) {
ASSERT_TRUE(RunRecordCmd({"--symfs", "/"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, duration_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"--duration", "1.2", "-p", std::to_string(getpid()), "-o",
@@ -442,6 +473,7 @@ TEST(record_cmd, duration_option) {
{"--duration", "1", "-o", tmpfile.path, "-e", GetDefaultEvent(), "sleep", "2"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, support_modifier_for_clock_events) {
for (const std::string& e : {"cpu-clock", "task-clock"}) {
for (const std::string& m : {"u", "k"}) {
@@ -450,6 +482,7 @@ TEST(record_cmd, support_modifier_for_clock_events) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, handle_SIGHUP) {
TemporaryFile tmpfile;
int pipefd[2];
@@ -470,6 +503,7 @@ TEST(record_cmd, handle_SIGHUP) {
ASSERT_STREQ(data, "STARTED");
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, stop_when_no_more_targets) {
TemporaryFile tmpfile;
std::atomic<int> tid(0);
@@ -484,6 +518,7 @@ TEST(record_cmd, stop_when_no_more_targets) {
{"-o", tmpfile.path, "-t", std::to_string(tid), "--in-app", "-e", GetDefaultEvent()}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, donot_stop_when_having_targets) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(1, &workloads);
@@ -496,6 +531,7 @@ TEST(record_cmd, donot_stop_when_having_targets) {
ASSERT_GT(end_time_in_ns - start_time_in_ns, static_cast<uint64_t>(2e9));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, start_profiling_fd_option) {
int pipefd[2];
ASSERT_EQ(0, pipe(pipefd));
@@ -514,6 +550,7 @@ TEST(record_cmd, start_profiling_fd_option) {
ASSERT_EQ("STARTED", s);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_meta_info_feature) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
@@ -530,6 +567,7 @@ TEST(record_cmd, record_meta_info_feature) {
}
// See http://b/63135835.
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, cpu_clock_for_a_long_time) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(1, &workloads);
@@ -539,6 +577,7 @@ TEST(record_cmd, cpu_clock_for_a_long_time) {
RecordCmd()->Run({"-e", "cpu-clock", "-o", tmpfile.path, "-p", pid, "--duration", "3"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, dump_regs_for_tracepoint_events) {
TEST_REQUIRE_HOST_ROOT();
TEST_REQUIRE_TRACEPOINT_EVENTS();
@@ -549,6 +588,7 @@ TEST(record_cmd, dump_regs_for_tracepoint_events) {
ASSERT_TRUE(IsDumpingRegsForTracepointEventsSupported());
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, trace_offcpu_option) {
// On linux host, we need root privilege to read tracepoint events.
TEST_REQUIRE_HOST_ROOT();
@@ -574,10 +614,12 @@ TEST(record_cmd, trace_offcpu_option) {
ASSERT_FALSE(RunRecordCmd({"--trace-offcpu", "-e", "cpu-clock,task-clock"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, exit_with_parent_option) {
ASSERT_TRUE(RunRecordCmd({"--exit-with-parent"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, use_cmd_exit_code_option) {
TemporaryFile tmpfile;
int exit_code;
@@ -590,6 +632,7 @@ TEST(record_cmd, use_cmd_exit_code_option) {
ASSERT_NE(exit_code, 0);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, clockid_option) {
if (!IsSettingClockIdSupported()) {
ASSERT_FALSE(RunRecordCmd({"--clockid", "monotonic"}));
@@ -603,6 +646,7 @@ TEST(record_cmd, clockid_option) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, generate_samples_by_hw_counters) {
TEST_REQUIRE_HW_COUNTER();
std::vector<std::string> events = {"cpu-cycles", "instructions"};
@@ -622,16 +666,19 @@ TEST(record_cmd, generate_samples_by_hw_counters) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, callchain_joiner_options) {
ASSERT_TRUE(RunRecordCmd({"--no-callchain-joiner"}));
ASSERT_TRUE(RunRecordCmd({"--callchain-joiner-min-matching-nodes", "2"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, dashdash) {
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "-e", GetDefaultEvent(), "--", "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, size_limit_option) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(1, &workloads);
@@ -646,6 +693,7 @@ TEST(record_cmd, size_limit_option) {
ASSERT_FALSE(RunRecordCmd({"--size-limit", "0"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, support_mmap2) {
// mmap2 is supported in kernel >= 3.16. If not supported, please cherry pick below kernel
// patches:
@@ -654,6 +702,7 @@ TEST(record_cmd, support_mmap2) {
ASSERT_TRUE(IsMmap2Supported());
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, kernel_bug_making_zero_dyn_size) {
// Test a kernel bug that makes zero dyn_size in kernel < 3.13. If it fails, please cherry pick
// below kernel patch: 0a196848ca365e perf: Fix arch_perf_out_copy_user default
@@ -680,6 +729,7 @@ TEST(record_cmd, kernel_bug_making_zero_dyn_size) {
ASSERT_TRUE(has_sample);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, kernel_bug_making_zero_dyn_size_for_kernel_samples) {
// Test a kernel bug that makes zero dyn_size for syscalls of 32-bit applications in 64-bit
// kernels. If it fails, please cherry pick below kernel patch:
@@ -709,6 +759,7 @@ TEST(record_cmd, kernel_bug_making_zero_dyn_size_for_kernel_samples) {
ASSERT_TRUE(has_sample);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, cpu_percent_option) {
ASSERT_TRUE(RunRecordCmd({"--cpu-percent", "50"}));
ASSERT_FALSE(RunRecordCmd({"--cpu-percent", "0"}));
@@ -741,6 +792,11 @@ class RecordingAppHelper {
};
ProcessSymbolsInPerfDataFile(GetDataPath(), callback);
if (!success) {
+ if (IsInEmulator() && !HasSample()) {
+ // In emulator, the monitored app may not have a chance to run.
+ GTEST_LOG_(INFO) << "No samples are recorded. Skip checking symbols.";
+ return true;
+ }
DumpData();
}
return success;
@@ -751,6 +807,24 @@ class RecordingAppHelper {
std::string GetDataPath() const { return perf_data_file_.path; }
private:
+ bool HasSample() {
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(GetDataPath());
+ if (!reader) {
+ return false;
+ }
+ bool has_sample = false;
+ auto process_record = [&](std::unique_ptr<Record> r) {
+ if (r->type() == PERF_RECORD_SAMPLE) {
+ has_sample = true;
+ }
+ return true;
+ };
+ if (!reader->ReadDataSection(process_record)) {
+ return false;
+ }
+ return has_sample;
+ }
+
AppHelper app_helper_;
TemporaryFile perf_data_file_;
};
@@ -790,6 +864,7 @@ static void TestRecordingApps(const std::string& app_name, const std::string& ap
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, app_option_for_debuggable_app) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
TEST_REQUIRE_APPS();
@@ -799,6 +874,7 @@ TEST(record_cmd, app_option_for_debuggable_app) {
TestRecordingApps("com.android.simpleperf.debuggable", "debuggable");
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, app_option_for_profileable_app) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
TEST_REQUIRE_APPS();
@@ -828,6 +904,7 @@ static void RecordJavaApp(RecordingAppHelper& helper) {
}
#endif // defined(__ANDROID__)
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_java_app) {
#if defined(__ANDROID__)
OMIT_TEST_ON_NON_NATIVE_ABIS();
@@ -858,6 +935,7 @@ TEST(record_cmd, record_java_app) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_native_app) {
#if defined(__ANDROID__)
// In case of non-native ABI guest symbols are never directly executed, thus
@@ -893,6 +971,7 @@ TEST(record_cmd, record_native_app) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, check_trampoline_after_art_jni_methods) {
// Test if art jni methods are called by art_jni_trampoline.
#if defined(__ANDROID__)
@@ -959,10 +1038,12 @@ TEST(record_cmd, check_trampoline_after_art_jni_methods) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, no_cut_samples_option) {
ASSERT_TRUE(RunRecordCmd({"--no-cut-samples"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, cs_etm_event) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
@@ -997,6 +1078,7 @@ TEST(record_cmd, cs_etm_event) {
ASSERT_TRUE(has_aux);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, cs_etm_system_wide) {
TEST_REQUIRE_ROOT();
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
@@ -1006,6 +1088,7 @@ TEST(record_cmd, cs_etm_system_wide) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "-a"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, aux_buffer_size_option) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
@@ -1018,6 +1101,7 @@ TEST(record_cmd, aux_buffer_size_option) {
ASSERT_FALSE(RunRecordCmd({"-e", "cs-etm", "--aux-buffer-size", "12k"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, addr_filter_option) {
TEST_REQUIRE_HW_COUNTER();
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
@@ -1078,6 +1162,7 @@ TEST(record_cmd, addr_filter_option) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--addr-filter", filter}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, decode_etm_option) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
@@ -1087,6 +1172,7 @@ TEST(record_cmd, decode_etm_option) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--decode-etm", "--exclude-perf"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_timestamp) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
@@ -1095,6 +1181,7 @@ TEST(record_cmd, record_timestamp) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--record-timestamp"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_cycles) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
@@ -1103,15 +1190,16 @@ TEST(record_cmd, record_cycles) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--record-cycles"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, cycle_threshold) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
return;
}
- ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--record-cycles",
- "--cycle-threshold", "8"}));
+ ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--record-cycles", "--cycle-threshold", "8"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, binary_option) {
if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
@@ -1120,6 +1208,16 @@ TEST(record_cmd, binary_option) {
ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--decode-etm", "--binary", ".*"}));
}
+// @CddTest = 6.1/C-0-2
+TEST(record_cmd, etm_flush_interval_option) {
+ if (!ETMRecorder::GetInstance().CheckEtmSupport().ok()) {
+ GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
+ return;
+ }
+ ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--etm-flush-interval", "10"}));
+}
+
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, pmu_event_option) {
TEST_REQUIRE_PMU_COUNTER();
TEST_REQUIRE_HW_COUNTER();
@@ -1135,6 +1233,7 @@ TEST(record_cmd, pmu_event_option) {
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-e", event_string})));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, exclude_perf_option) {
ASSERT_TRUE(RunRecordCmd({"--exclude-perf"}));
if (IsRoot()) {
@@ -1155,6 +1254,7 @@ TEST(record_cmd, exclude_perf_option) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, tp_filter_option) {
TEST_REQUIRE_HOST_ROOT();
TEST_REQUIRE_TRACEPOINT_EVENTS();
@@ -1175,6 +1275,7 @@ TEST(record_cmd, tp_filter_option) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, ParseAddrFilterOption) {
auto option_to_str = [](const std::string& option) {
auto filters = ParseAddrFilterOption(option);
@@ -1207,6 +1308,7 @@ TEST(record_cmd, ParseAddrFilterOption) {
ASSERT_EQ(option_to_str("start 0x12345678,stop 0x1234567a"), "start 0x12345678,stop 0x1234567a");
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, kprobe_option) {
TEST_REQUIRE_ROOT();
EventSelectionSet event_selection_set(false);
@@ -1221,6 +1323,7 @@ TEST(record_cmd, kprobe_option) {
ASSERT_TRUE(RunRecordCmd({"--group", "kprobes:do_sys_openat2"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_filter_options) {
ASSERT_TRUE(
RunRecordCmd({"--exclude-pid", "1,2", "--exclude-tid", "3,4", "--exclude-process-name",
@@ -1230,6 +1333,7 @@ TEST(record_cmd, record_filter_options) {
"processB", "--include-thread-name", "threadB", "--include-uid", "5,6"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, keep_failed_unwinding_result_option) {
OMIT_TEST_ON_NON_NATIVE_ABIS();
std::vector<std::unique_ptr<Workload>> workloads;
@@ -1239,6 +1343,7 @@ TEST(record_cmd, keep_failed_unwinding_result_option) {
{"-p", pid, "-g", "--keep-failed-unwinding-result", "--keep-failed-unwinding-debug-info"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, kernel_address_warning) {
TEST_REQUIRE_NON_ROOT();
const std::string warning_msg = "Access to kernel symbol addresses is restricted.";
@@ -1263,6 +1368,7 @@ TEST(record_cmd, kernel_address_warning) {
ASSERT_EQ(output.find(warning_msg, pos + warning_msg.size()), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, add_meta_info_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"--add-meta-info", "key1=value1", "--add-meta-info", "key2=value2"},
@@ -1284,6 +1390,7 @@ TEST(record_cmd, add_meta_info_option) {
ASSERT_FALSE(RunRecordCmd({"--add-meta-info", "=value1"}, tmpfile.path));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, device_meta_info) {
#if defined(__ANDROID__)
TemporaryFile tmpfile;
@@ -1303,6 +1410,7 @@ TEST(record_cmd, device_meta_info) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, add_counter_option) {
TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
@@ -1324,10 +1432,12 @@ TEST(record_cmd, add_counter_option) {
ASSERT_TRUE(has_sample);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, user_buffer_size_option) {
ASSERT_TRUE(RunRecordCmd({"--user-buffer-size", "256M"}));
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, record_process_name) {
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"-e", GetDefaultEvent(), "-o", tmpfile.path, "sleep", SLEEP_SEC}));
@@ -1346,6 +1456,7 @@ TEST(record_cmd, record_process_name) {
ASSERT_TRUE(has_comm);
}
+// @CddTest = 6.1/C-0-2
TEST(record_cmd, delay_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run(
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index 524174e4..f2fb527f 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -449,6 +449,7 @@ class ReportCommand : public Command {
" The default sort keys are:\n"
" comm,pid,tid,dso,symbol\n"
"--symfs <dir> Look for files with symbols relative to this directory.\n"
+"--symdir <dir> Look for files with symbols in a directory recursively.\n"
"--vmlinux <file> Parse kernel symbols from <file>.\n"
"\n"
"Sample filter options:\n"
@@ -585,6 +586,7 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
{"--sort", {OptionValueType::STRING, OptionType::SINGLE}},
{"--symbols", {OptionValueType::STRING, OptionType::MULTIPLE}},
{"--symfs", {OptionValueType::STRING, OptionType::SINGLE}},
+ {"--symdir", {OptionValueType::STRING, OptionType::SINGLE}},
{"--vmlinux", {OptionValueType::STRING, OptionType::SINGLE}},
};
OptionFormatMap record_filter_options = GetRecordFilterOptionFormats(false);
@@ -692,6 +694,11 @@ bool ReportCommand::ParseOptions(const std::vector<std::string>& args) {
return false;
}
}
+ if (auto value = options.PullValue("--symdir"); value) {
+ if (!Dso::AddSymbolDir(*value->str_value)) {
+ return false;
+ }
+ }
if (auto value = options.PullValue("--vmlinux"); value) {
Dso::SetVmlinux(*value->str_value);
}
diff --git a/simpleperf/cmd_report_sample_test.cpp b/simpleperf/cmd_report_sample_test.cpp
index d71dce2f..b544f7b5 100644
--- a/simpleperf/cmd_report_sample_test.cpp
+++ b/simpleperf/cmd_report_sample_test.cpp
@@ -29,16 +29,19 @@ static std::unique_ptr<Command> ReportSampleCmd() {
return CreateCommandInstance("report-sample");
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, text) {
ASSERT_TRUE(ReportSampleCmd()->Run({"-i", GetTestData(PERF_DATA_WITH_SYMBOLS)}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, output_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(
ReportSampleCmd()->Run({"-i", GetTestData(PERF_DATA_WITH_SYMBOLS), "-o", tmpfile.path}));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, show_callchain_option) {
TemporaryFile tmpfile;
ASSERT_TRUE(ReportSampleCmd()->Run(
@@ -58,6 +61,7 @@ static void GetProtobufReport(const std::string& test_data_file, std::string* pr
ASSERT_TRUE(android::base::ReadFileToString(tmpfile2.path, protobuf_report));
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, protobuf_option) {
std::string data;
GetProtobufReport(PERF_DATA_WITH_SYMBOLS, &data);
@@ -66,6 +70,7 @@ TEST(cmd_report_sample, protobuf_option) {
ASSERT_NE(data.find("file:"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, no_skipped_file_id) {
std::string data;
GetProtobufReport(PERF_DATA_WITH_WRONG_IP_IN_CALLCHAIN, &data);
@@ -73,12 +78,14 @@ TEST(cmd_report_sample, no_skipped_file_id) {
ASSERT_EQ(data.find("unknown"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, sample_has_event_count) {
std::string data;
GetProtobufReport(PERF_DATA_WITH_SYMBOLS, &data);
ASSERT_NE(data.find("event_count:"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, has_thread_record) {
std::string data;
GetProtobufReport(PERF_DATA_WITH_SYMBOLS, &data);
@@ -86,6 +93,7 @@ TEST(cmd_report_sample, has_thread_record) {
ASSERT_NE(data.find("thread_name: t2"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, trace_offcpu) {
std::string data;
GetProtobufReport("perf_with_trace_offcpu_v2.data", &data);
@@ -101,6 +109,7 @@ TEST(cmd_report_sample, trace_offcpu) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, have_clear_callchain_end_in_protobuf_output) {
std::string data;
GetProtobufReport("perf_with_trace_offcpu_v2.data", &data, {"--show-callchain"});
@@ -108,6 +117,7 @@ TEST(cmd_report_sample, have_clear_callchain_end_in_protobuf_output) {
ASSERT_EQ(data.find("_start_main"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, app_device_info_in_meta_info) {
std::string data;
GetProtobufReport("perf_with_meta_info.data", &data);
@@ -117,6 +127,7 @@ TEST(cmd_report_sample, app_device_info_in_meta_info) {
ASSERT_NE(data.find("android_build_type: userdebug"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, remove_unknown_kernel_symbols) {
std::string data;
// Test --remove-unknown-kernel-symbols on perf.data with kernel_symbols_available=false.
@@ -148,6 +159,7 @@ TEST(cmd_report_sample, remove_unknown_kernel_symbols) {
ASSERT_NE(data.find("path: /system/lib64/libc.so"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, show_art_frames_option) {
std::string data;
GetProtobufReport(PERF_DATA_WITH_INTERPRETER_FRAMES, &data, {"--show-callchain"});
@@ -157,6 +169,7 @@ TEST(cmd_report_sample, show_art_frames_option) {
ASSERT_NE(data.find("artMterpAsmInstructionStart"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, show_execution_type_option) {
std::string data;
GetProtobufReport("perf_display_bitmaps.data", &data,
@@ -174,6 +187,7 @@ TEST(cmd_report_sample, show_execution_type_option) {
ASSERT_NE(data.find("execution_type: art_method"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, show_symbols_before_and_after_demangle) {
std::string data;
GetProtobufReport(PERF_DATA_WITH_INTERPRETER_FRAMES, &data, {"--show-callchain"});
@@ -183,6 +197,7 @@ TEST(cmd_report_sample, show_symbols_before_and_after_demangle) {
std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, symdir_option) {
std::string data;
GetProtobufReport(PERF_DATA_FOR_BUILD_ID_CHECK, &data);
@@ -192,6 +207,7 @@ TEST(cmd_report_sample, symdir_option) {
ASSERT_NE(data.find("symbol: main"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, show_art_jni_methods) {
std::string data;
GetProtobufReport("perf_display_bitmaps.data", &data, {"--show-callchain"});
@@ -200,6 +216,7 @@ TEST(cmd_report_sample, show_art_jni_methods) {
ASSERT_EQ(data.find("art_jni_trampoline"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, show_unwinding_result) {
std::string data;
GetProtobufReport("perf_with_failed_unwinding_debug_info.data", &data,
@@ -207,6 +224,7 @@ TEST(cmd_report_sample, show_unwinding_result) {
ASSERT_NE(data.find("error_code: ERROR_INVALID_MAP"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, proguard_mapping_file_option) {
std::string data;
// Symbols aren't de-obfuscated without proguard mapping file.
@@ -226,6 +244,7 @@ TEST(cmd_report_sample, proguard_mapping_file_option) {
std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, exclude_include_pid_options) {
std::string data;
GetProtobufReport("perf_display_bitmaps.data", &data, {"--exclude-pid", "31850"});
@@ -235,6 +254,7 @@ TEST(cmd_report_sample, exclude_include_pid_options) {
ASSERT_NE(data.find("thread_id: 31850"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, exclude_include_tid_options) {
std::string data;
GetProtobufReport("perf_display_bitmaps.data", &data, {"--exclude-tid", "31881"});
@@ -244,6 +264,7 @@ TEST(cmd_report_sample, exclude_include_tid_options) {
ASSERT_NE(data.find("thread_id: 31881"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, exclude_include_process_name_options) {
std::string data;
GetProtobufReport("perf_display_bitmaps.data", &data,
@@ -255,6 +276,7 @@ TEST(cmd_report_sample, exclude_include_process_name_options) {
ASSERT_NE(data.find("thread_id: 31881"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, exclude_include_thread_name_options) {
std::string data;
GetProtobufReport("perf_display_bitmaps.data", &data,
@@ -266,6 +288,7 @@ TEST(cmd_report_sample, exclude_include_thread_name_options) {
ASSERT_NE(data.find("thread_id: 31850"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, filter_file_option) {
std::string filter_data =
"GLOBAL_BEGIN 684943449406175\n"
@@ -278,6 +301,7 @@ TEST(cmd_report_sample, filter_file_option) {
ASSERT_EQ(data.find("thread_id: 31850"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(cmd_report_sample, remove_gaps_option) {
auto get_sample_count = [](const std::string& s) {
size_t count = 0;
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index 6dfbae5c..9170beb2 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -37,19 +37,27 @@ static std::unique_ptr<Command> ReportCmd() {
return CreateCommandInstance("report");
}
+// @CddTest = 6.1/C-0-2
class ReportCommandTest : public ::testing::Test {
protected:
void Report(const std::string& perf_data,
- const std::vector<std::string>& add_args = std::vector<std::string>()) {
- ReportRaw(GetTestData(perf_data), add_args);
+ const std::vector<std::string>& add_args = std::vector<std::string>(),
+ bool with_symfs = true) {
+ ReportRaw(GetTestData(perf_data), add_args, with_symfs);
}
void ReportRaw(const std::string& perf_data,
- const std::vector<std::string>& add_args = std::vector<std::string>()) {
+ const std::vector<std::string>& add_args = std::vector<std::string>(),
+ bool with_symfs = true) {
success = false;
TemporaryFile tmp_file;
- std::vector<std::string> args = {"-i", perf_data, "--symfs", GetTestDataDir(),
- "-o", tmp_file.path};
+ std::vector<std::string> args = {"-i", perf_data, "-o", tmp_file.path};
+
+ if (with_symfs) {
+ args.emplace_back("--symfs");
+ args.emplace_back(GetTestDataDir());
+ }
+
args.insert(args.end(), add_args.begin(), add_args.end());
ASSERT_TRUE(ReportCmd()->Run(args));
ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
@@ -83,18 +91,21 @@ class ReportCommandTest : public ::testing::Test {
bool success;
};
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, no_option) {
Report(PERF_DATA);
ASSERT_TRUE(success);
ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_symbol_from_elf_file_with_mini_debug_info) {
Report(PERF_DATA_WITH_MINI_DEBUG_INFO);
ASSERT_TRUE(success);
ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, sort_option_pid) {
Report(PERF_DATA, {"--sort", "pid"});
ASSERT_TRUE(success);
@@ -105,6 +116,7 @@ TEST_F(ReportCommandTest, sort_option_pid) {
ASSERT_LT(line_index + 2, lines.size());
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, sort_option_more_than_one) {
Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
ASSERT_TRUE(success);
@@ -120,6 +132,7 @@ TEST_F(ReportCommandTest, sort_option_more_than_one) {
ASSERT_EQ(lines[line_index].find("Tid"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, children_option) {
Report(CALLGRAPH_FP_PERF_DATA, {"--children", "--sort", "symbol"});
ASSERT_TRUE(success);
@@ -164,6 +177,7 @@ static bool CheckCallerMode(std::vector<std::string>& lines) {
return found;
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, callgraph_option) {
Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
ASSERT_TRUE(success);
@@ -201,6 +215,7 @@ static bool AllItemsWithString(std::vector<std::string>& lines,
return true;
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, pid_filter_option) {
Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "pid"});
ASSERT_TRUE(success);
@@ -221,6 +236,7 @@ TEST_F(ReportCommandTest, pid_filter_option) {
ASSERT_NE(content.find("17445"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, wrong_pid_filter_option) {
ASSERT_EXIT(
{
@@ -230,6 +246,7 @@ TEST_F(ReportCommandTest, wrong_pid_filter_option) {
testing::ExitedWithCode(1), "invalid pid: bogus");
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, tid_filter_option) {
Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "tid"});
ASSERT_TRUE(success);
@@ -243,6 +260,7 @@ TEST_F(ReportCommandTest, tid_filter_option) {
ASSERT_TRUE(AllItemsWithString(lines, {"17441", "17445"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, wrong_tid_filter_option) {
ASSERT_EXIT(
{
@@ -252,6 +270,7 @@ TEST_F(ReportCommandTest, wrong_tid_filter_option) {
testing::ExitedWithCode(1), "Invalid tid 'bogus'");
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, comm_filter_option) {
Report(PERF_DATA, {"--sort", "comm"});
ASSERT_TRUE(success);
@@ -265,6 +284,7 @@ TEST_F(ReportCommandTest, comm_filter_option) {
ASSERT_TRUE(AllItemsWithString(lines, {"t1", "t2"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, dso_filter_option) {
Report(PERF_DATA, {"--sort", "dso"});
ASSERT_TRUE(success);
@@ -278,6 +298,7 @@ TEST_F(ReportCommandTest, dso_filter_option) {
ASSERT_TRUE(AllItemsWithString(lines, {"/t1", "/t2"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, symbol_filter_option) {
Report(PERF_DATA_WITH_SYMBOLS, {"--sort", "symbol"});
ASSERT_TRUE(success);
@@ -291,6 +312,7 @@ TEST_F(ReportCommandTest, symbol_filter_option) {
ASSERT_TRUE(AllItemsWithString(lines, {"main", "func2(int, int)"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, dso_symbol_filter_with_children_option) {
// dso and symbol filter should filter different layers of the callchain separately.
Report("perf_display_bitmaps.data", {"--dsos", "/apex/com.android.runtime/lib64/libart.so",
@@ -305,6 +327,7 @@ TEST_F(ReportCommandTest, dso_symbol_filter_with_children_option) {
ASSERT_NE(content.find("51500000 2500000 MterpInvokeVirtual"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, use_branch_address) {
Report(BRANCH_PERF_DATA, {"-b", "--sort", "symbol_from,symbol_to"});
std::set<std::pair<std::string, std::string>> hit_set;
@@ -326,6 +349,7 @@ TEST_F(ReportCommandTest, use_branch_address) {
hit_set.end());
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
Report(NATIVELIB_IN_APK_PERF_DATA);
ASSERT_TRUE(success);
@@ -333,6 +357,7 @@ TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
ASSERT_NE(content.find("Func2"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_more_than_one_event_types) {
Report(PERF_DATA_WITH_TWO_EVENT_TYPES);
ASSERT_TRUE(success);
@@ -343,12 +368,14 @@ TEST_F(ReportCommandTest, report_more_than_one_event_types) {
ASSERT_NE(pos = content.find("Samples:", pos), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_kernel_symbol) {
Report(PERF_DATA_WITH_KERNEL_SYMBOL);
ASSERT_TRUE(success);
ASSERT_NE(content.find("perf_event_aux"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_dumped_symbols) {
Report(PERF_DATA_WITH_SYMBOLS);
ASSERT_TRUE(success);
@@ -358,6 +385,7 @@ TEST_F(ReportCommandTest, report_dumped_symbols) {
ASSERT_NE(content.find("memcpy"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_dumped_symbols_with_symfs_dir) {
// Check if we can report symbols when they appear both in perf.data and symfs dir.
Report(PERF_DATA_WITH_SYMBOLS, {"--symfs", GetTestDataDir()});
@@ -365,17 +393,28 @@ TEST_F(ReportCommandTest, report_dumped_symbols_with_symfs_dir) {
ASSERT_NE(content.find("main"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
+TEST_F(ReportCommandTest, report_dumped_symbols_with_symdir) {
+ // Check if we can report symbols by specifying symdir.
+ Report(PERF_DATA, {"--symdir", GetTestDataDir()}, false);
+ ASSERT_TRUE(success);
+ ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
+}
+
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_without_symfs_dir) {
TemporaryFile tmpfile;
ASSERT_TRUE(ReportCmd()->Run({"-i", GetTestData(PERF_DATA), "-o", tmpfile.path}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_sort_vaddr_in_file) {
Report(PERF_DATA, {"--sort", "vaddr_in_file"});
ASSERT_TRUE(success);
ASSERT_NE(content.find("VaddrInFile"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, check_build_id) {
Report(PERF_DATA_FOR_BUILD_ID_CHECK, {"--symfs", GetTestData(CORRECT_SYMFS_FOR_BUILD_ID_CHECK)});
ASSERT_TRUE(success);
@@ -395,6 +434,7 @@ TEST_F(ReportCommandTest, check_build_id) {
testing::ExitedWithCode(0), "failed to read symbols from /elf_for_build_id_check");
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, no_show_ip_option) {
Report(PERF_DATA);
ASSERT_TRUE(success);
@@ -404,6 +444,7 @@ TEST_F(ReportCommandTest, no_show_ip_option) {
ASSERT_NE(content.find("unknown"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, read_elf_file_warning) {
ASSERT_EXIT(
{
@@ -419,11 +460,13 @@ TEST_F(ReportCommandTest, read_elf_file_warning) {
testing::ExitedWithCode(0), "failed to read symbols from /elf: File not found");
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_data_generated_by_linux_perf) {
Report(PERF_DATA_GENERATED_BY_LINUX_PERF);
ASSERT_TRUE(success);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, max_stack_and_percent_limit_option) {
Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g"});
ASSERT_TRUE(success);
@@ -444,6 +487,7 @@ TEST_F(ReportCommandTest, max_stack_and_percent_limit_option) {
ASSERT_NE(content.find("89.03"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, percent_limit_option) {
Report(PERF_DATA);
ASSERT_TRUE(success);
@@ -455,16 +499,19 @@ TEST_F(ReportCommandTest, percent_limit_option) {
ASSERT_EQ(content.find("3.23%"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, kallsyms_option) {
Report(PERF_DATA, {"--kallsyms", GetTestData("kallsyms")});
ASSERT_TRUE(success);
ASSERT_NE(content.find("FakeKernelSymbol"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, invalid_perf_data) {
ASSERT_FALSE(ReportCmd()->Run({"-i", GetTestData(INVALID_PERF_DATA)}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, raw_period_option) {
Report(PERF_DATA, {"--raw-period"});
ASSERT_TRUE(success);
@@ -472,6 +519,7 @@ TEST_F(ReportCommandTest, raw_period_option) {
ASSERT_EQ(content.find('%'), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, full_callgraph_option) {
Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
ASSERT_TRUE(success);
@@ -481,6 +529,7 @@ TEST_F(ReportCommandTest, full_callgraph_option) {
ASSERT_EQ(content.find("skipped in brief callgraph mode"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_offcpu_time) {
Report(PERF_DATA_WITH_TRACE_OFFCPU, {"--children"});
ASSERT_TRUE(success);
@@ -496,11 +545,13 @@ TEST_F(ReportCommandTest, report_offcpu_time) {
ASSERT_TRUE(found);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_big_trace_data) {
Report(PERF_DATA_WITH_BIG_TRACE_DATA);
ASSERT_TRUE(success);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, csv_option) {
Report(PERF_DATA, {"--csv"});
ASSERT_TRUE(success);
@@ -511,6 +562,7 @@ TEST_F(ReportCommandTest, csv_option) {
ASSERT_NE(content.find("AccEventCount,SelfEventCount,EventName"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, csv_separator_option) {
Report(PERF_DATA, {"--csv", "--csv-separator", ";"});
ASSERT_TRUE(success);
@@ -518,6 +570,7 @@ TEST_F(ReportCommandTest, csv_separator_option) {
ASSERT_NE(content.find(";cpu-cycles"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, dso_path_for_jit_cache) {
Report("perf_with_jit_symbol.data", {"--sort", "dso"});
ASSERT_TRUE(success);
@@ -529,12 +582,14 @@ TEST_F(ReportCommandTest, dso_path_for_jit_cache) {
ASSERT_NE(content.find("[JIT app cache]"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, generic_jit_symbols) {
Report("perf_with_generic_git_symbols.data", {"--sort", "symbol"});
ASSERT_TRUE(success);
ASSERT_NE(std::string::npos, content.find("generic_jit_symbol_one"));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, cpu_option) {
Report("perf.data");
ASSERT_TRUE(success);
@@ -551,6 +606,7 @@ TEST_F(ReportCommandTest, cpu_option) {
ASSERT_FALSE(ReportCmd()->Run({"-i", GetTestData("perf.data"), "--cpu", "-2"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, print_event_count_option) {
// Report record file not recorded with --add-counter.
Report("perf.data", {"--print-event-count"});
@@ -583,6 +639,7 @@ TEST_F(ReportCommandTest, print_event_count_option) {
->Search(content));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, exclude_include_pid_options) {
Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "pid", "--exclude-pid", "17441"});
ASSERT_TRUE(success);
@@ -592,6 +649,7 @@ TEST_F(ReportCommandTest, exclude_include_pid_options) {
ASSERT_TRUE(AllItemsWithString(lines, {"17441"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, exclude_include_tid_options) {
Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS,
{"--sort", "tid", "--exclude-tid", "17441,17443,17444"});
@@ -603,6 +661,7 @@ TEST_F(ReportCommandTest, exclude_include_tid_options) {
ASSERT_TRUE(AllItemsWithString(lines, {"17441", "17443", "17444"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, exclude_include_process_name_options) {
Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "comm", "--exclude-process-name", "t1"});
ASSERT_TRUE(success);
@@ -612,6 +671,7 @@ TEST_F(ReportCommandTest, exclude_include_process_name_options) {
ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, exclude_include_thread_name_options) {
Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "comm", "--exclude-thread-name", "t1"});
ASSERT_TRUE(success);
@@ -621,6 +681,7 @@ TEST_F(ReportCommandTest, exclude_include_thread_name_options) {
ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, filter_file_option) {
std::string filter_data =
"GLOBAL_BEGIN 684943449406175\n"
@@ -645,6 +706,7 @@ static std::unique_ptr<Command> RecordCmd() {
return CreateCommandInstance("record");
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, dwarf_callgraph) {
TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
@@ -658,6 +720,7 @@ TEST_F(ReportCommandTest, dwarf_callgraph) {
ASSERT_TRUE(success);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, report_dwarf_callgraph_of_nativelib_in_apk) {
Report(NATIVELIB_IN_APK_PERF_DATA, {"-g"});
ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
@@ -666,6 +729,7 @@ TEST_F(ReportCommandTest, report_dwarf_callgraph_of_nativelib_in_apk) {
ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ReportCommandTest, exclude_kernel_callchain) {
TEST_REQUIRE_HW_COUNTER();
TEST_REQUIRE_HOST_ROOT();
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 86c7ae8c..c47ad729 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -36,26 +36,32 @@ static std::unique_ptr<Command> StatCmd() {
return CreateCommandInstance("stat");
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, no_options) {
ASSERT_TRUE(StatCmd()->Run({"sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, event_option) {
ASSERT_TRUE(StatCmd()->Run({"-e", "cpu-clock,task-clock", "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, system_wide_option) {
TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "sleep", "1"})));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, verbose_option) {
ASSERT_TRUE(StatCmd()->Run({"--verbose", "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, tracepoint_event) {
TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", "1"})));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, rN_event) {
TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
@@ -79,6 +85,7 @@ TEST(stat_cmd, rN_event) {
ASSERT_TRUE(StatCmd()->Run({"-e", event_name, "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, pmu_event) {
TEST_REQUIRE_PMU_COUNTER();
TEST_REQUIRE_HW_COUNTER();
@@ -96,6 +103,7 @@ TEST(stat_cmd, pmu_event) {
TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "-e", event_string, "sleep", "1"})));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, event_modifier) {
TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(StatCmd()->Run({"-e", "cpu-cycles:u,cpu-cycles:k", "sleep", "1"}));
@@ -121,6 +129,7 @@ void CreateProcesses(size_t count, std::vector<std::unique_ptr<Workload>>* workl
}
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, existing_processes) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
@@ -129,6 +138,7 @@ TEST(stat_cmd, existing_processes) {
ASSERT_TRUE(StatCmd()->Run({"-p", pid_list, "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, existing_threads) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
@@ -138,11 +148,13 @@ TEST(stat_cmd, existing_threads) {
ASSERT_TRUE(StatCmd()->Run({"-t", tid_list, "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, no_monitored_threads) {
ASSERT_FALSE(StatCmd()->Run({}));
ASSERT_FALSE(StatCmd()->Run({""}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, group_option) {
TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(StatCmd()->Run({"--group", "cpu-clock,page-faults", "sleep", "1"}));
@@ -151,6 +163,7 @@ TEST(stat_cmd, group_option) {
"cpu-cycles:k,instructions:k", "sleep", "1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, auto_generated_summary) {
TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmp_file;
@@ -167,11 +180,13 @@ TEST(stat_cmd, auto_generated_summary) {
ASSERT_NE(s.npos, s.find("instructions", pos));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, duration_option) {
ASSERT_TRUE(StatCmd()->Run({"--duration", "1.2", "-p", std::to_string(getpid()), "--in-app"}));
ASSERT_TRUE(StatCmd()->Run({"--duration", "1", "sleep", "2"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, interval_option) {
TemporaryFile tmp_file;
ASSERT_TRUE(StatCmd()->Run(
@@ -188,16 +203,19 @@ TEST(stat_cmd, interval_option) {
ASSERT_EQ(count, 2UL);
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, interval_option_in_system_wide) {
TEST_IN_ROOT(ASSERT_TRUE(StatCmd()->Run({"-a", "--interval", "100", "--duration", "0.3"})));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, interval_only_values_option) {
ASSERT_TRUE(StatCmd()->Run({"--interval", "500", "--interval-only-values", "sleep", "2"}));
TEST_IN_ROOT(ASSERT_TRUE(
StatCmd()->Run({"-a", "--interval", "100", "--interval-only-values", "--duration", "0.3"})));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, no_modifier_for_clock_events) {
for (const std::string& e : {"cpu-clock", "task-clock"}) {
for (const std::string& m : {"u", "k"}) {
@@ -207,6 +225,7 @@ TEST(stat_cmd, no_modifier_for_clock_events) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, handle_SIGHUP) {
std::thread thread([]() {
sleep(1);
@@ -216,6 +235,7 @@ TEST(stat_cmd, handle_SIGHUP) {
ASSERT_TRUE(StatCmd()->Run({"sleep", "1000000"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, stop_when_no_more_targets) {
std::atomic<int> tid(0);
std::thread thread([&]() {
@@ -228,6 +248,7 @@ TEST(stat_cmd, stop_when_no_more_targets) {
ASSERT_TRUE(StatCmd()->Run({"-t", std::to_string(tid), "--in-app"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, sample_rate_should_be_zero) {
TEST_REQUIRE_HW_COUNTER();
EventSelectionSet set(true);
@@ -244,6 +265,7 @@ TEST(stat_cmd, sample_rate_should_be_zero) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, calculating_cpu_frequency) {
TEST_REQUIRE_HW_COUNTER();
CaptureStdout capture;
@@ -269,6 +291,7 @@ TEST(stat_cmd, calculating_cpu_frequency) {
ASSERT_NEAR(cpu_frequency, calculated_frequency, 1e-3);
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, set_comm_in_another_thread) {
// Test a kernel bug which was fixed in 3.15. If kernel panic happens, please cherry pick kernel
// patch: e041e328c4b41e perf: Fix perf_event_comm() vs. exec() assumption
@@ -321,6 +344,7 @@ static void TestStatingApps(const std::string& app_name) {
ASSERT_TRUE(StatCmd()->Run({"--app", app_name, "--duration", "3"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, app_option_for_debuggable_app) {
TEST_REQUIRE_APPS();
SetRunInAppToolForTesting(true, false);
@@ -329,12 +353,14 @@ TEST(stat_cmd, app_option_for_debuggable_app) {
TestStatingApps("com.android.simpleperf.debuggable");
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, app_option_for_profileable_app) {
TEST_REQUIRE_APPS();
SetRunInAppToolForTesting(false, true);
TestStatingApps("com.android.simpleperf.profileable");
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, use_devfreq_counters_option) {
#if defined(__ANDROID__)
TEST_IN_ROOT(StatCmd()->Run({"--use-devfreq-counters", "sleep", "0.1"}));
@@ -343,21 +369,25 @@ TEST(stat_cmd, use_devfreq_counters_option) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, per_thread_option) {
ASSERT_TRUE(StatCmd()->Run({"--per-thread", "sleep", "0.1"}));
TEST_IN_ROOT(StatCmd()->Run({"--per-thread", "-a", "--duration", "0.1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, per_core_option) {
ASSERT_TRUE(StatCmd()->Run({"--per-core", "sleep", "0.1"}));
TEST_IN_ROOT(StatCmd()->Run({"--per-core", "-a", "--duration", "0.1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, sort_option) {
ASSERT_TRUE(
StatCmd()->Run({"--per-thread", "--per-core", "--sort", "cpu,count", "sleep", "0.1"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, counter_sum) {
PerfCounter counter;
counter.value = 1;
@@ -382,10 +412,12 @@ TEST(stat_cmd, counter_sum) {
ASSERT_EQ(counter.time_running, 6);
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, print_hw_counter_option) {
ASSERT_TRUE(StatCmd()->Run({"--print-hw-counter"}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, record_different_counters_for_different_cpus) {
std::vector<int> online_cpus = GetOnlineCpus();
ASSERT_FALSE(online_cpus.empty());
@@ -412,6 +444,7 @@ TEST(stat_cmd, record_different_counters_for_different_cpus) {
ASSERT_TRUE(has_task_clock) << output;
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, kprobe_option) {
TEST_REQUIRE_ROOT();
EventSelectionSet event_selection_set(false);
@@ -427,6 +460,7 @@ TEST(stat_cmd, kprobe_option) {
ASSERT_TRUE(StatCmd()->Run({"--group", "kprobes:do_sys_openat2", "-a", "--duration", SLEEP_SEC}));
}
+// @CddTest = 6.1/C-0-2
TEST(stat_cmd, tp_filter_option) {
TEST_REQUIRE_HOST_ROOT();
TEST_REQUIRE_TRACEPOINT_EVENTS();
@@ -434,6 +468,7 @@ TEST(stat_cmd, tp_filter_option) {
{"-e", "sched:sched_switch", "--tp-filter", "prev_comm != sleep", "sleep", SLEEP_SEC}));
}
+// @CddTest = 6.1/C-0-2
class StatCmdSummaryBuilderTest : public ::testing::Test {
protected:
struct CounterArg {
@@ -485,6 +520,7 @@ class StatCmdSummaryBuilderTest : public ::testing::Test {
std::vector<std::string> sort_keys_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, multiple_events) {
AddCounter({.event_id = 0, .value = 1, .time_enabled = 1, .time_running = 1});
AddCounter({.event_id = 1, .value = 2, .time_enabled = 2, .time_running = 2});
@@ -498,6 +534,7 @@ TEST_F(StatCmdSummaryBuilderTest, multiple_events) {
ASSERT_NEAR(summaries[1].scale, 1.0, 1e-5);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, default_aggregate) {
AddCounter({.tid = 0, .cpu = 0, .value = 1, .time_enabled = 1, .time_running = 1});
AddCounter({.tid = 0, .cpu = 1, .value = 1, .time_enabled = 1, .time_running = 1});
@@ -509,6 +546,7 @@ TEST_F(StatCmdSummaryBuilderTest, default_aggregate) {
ASSERT_NEAR(summaries[0].scale, 1.25, 1e-5);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, per_thread_aggregate) {
AddCounter({.tid = 0, .cpu = 0, .value = 1, .time_enabled = 1, .time_running = 1});
AddCounter({.tid = 0, .cpu = 1, .value = 1, .time_enabled = 1, .time_running = 1});
@@ -526,6 +564,7 @@ TEST_F(StatCmdSummaryBuilderTest, per_thread_aggregate) {
ASSERT_NEAR(summaries[1].scale, 1.0, 1e-5);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, per_core_aggregate) {
AddCounter({.tid = 0, .cpu = 0, .value = 1, .time_enabled = 1, .time_running = 1});
AddCounter({.tid = 0, .cpu = 1, .value = 1, .time_enabled = 1, .time_running = 1});
@@ -543,6 +582,7 @@ TEST_F(StatCmdSummaryBuilderTest, per_core_aggregate) {
ASSERT_NEAR(summaries[1].scale, 1.5, 1e-5);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, per_thread_core_aggregate) {
AddCounter({.tid = 0, .cpu = 0, .value = 1, .time_enabled = 1, .time_running = 1});
AddCounter({.tid = 0, .cpu = 1, .value = 2, .time_enabled = 1, .time_running = 1});
@@ -568,6 +608,7 @@ TEST_F(StatCmdSummaryBuilderTest, per_thread_core_aggregate) {
ASSERT_NEAR(summaries[3].scale, 1.0, 1e-5);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, sort_key_count) {
sort_keys_ = {"count"};
AddCounter({.tid = 0, .cpu = 0, .value = 1});
@@ -577,6 +618,7 @@ TEST_F(StatCmdSummaryBuilderTest, sort_key_count) {
ASSERT_EQ(summaries[1].count, 1);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, sort_key_count_per_thread) {
sort_keys_ = {"count_per_thread", "count"};
AddCounter({.tid = 0, .cpu = 0, .value = 1});
@@ -588,6 +630,7 @@ TEST_F(StatCmdSummaryBuilderTest, sort_key_count_per_thread) {
ASSERT_EQ(summaries[2].count, 3);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, sort_key_cpu) {
sort_keys_ = {"cpu"};
AddCounter({.tid = 0, .cpu = 1, .value = 2});
@@ -597,6 +640,7 @@ TEST_F(StatCmdSummaryBuilderTest, sort_key_cpu) {
ASSERT_EQ(summaries[1].cpu, 1);
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummaryBuilderTest, sort_key_pid_tid_name) {
AddCounter({.tid = 0, .cpu = 0, .value = 1});
AddCounter({.tid = 1, .cpu = 0, .value = 2});
@@ -609,6 +653,7 @@ TEST_F(StatCmdSummaryBuilderTest, sort_key_pid_tid_name) {
}
}
+// @CddTest = 6.1/C-0-2
class StatCmdSummariesTest : public ::testing::Test {
protected:
void AddSummary(const std::string event_name, pid_t tid, int cpu, uint64_t count,
@@ -637,6 +682,7 @@ class StatCmdSummariesTest : public ::testing::Test {
std::unique_ptr<CounterSummaries> summaries_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummariesTest, task_clock_comment) {
AddSummary("task-clock", -1, -1, 1e9, 0);
AddSummary("task-clock", 0, -1, 2e9, 0);
@@ -648,6 +694,7 @@ TEST_F(StatCmdSummariesTest, task_clock_comment) {
ASSERT_EQ(*GetComment(3), "3.000000 cpus used");
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummariesTest, cpu_cycles_comment) {
AddSummary("cpu-cycles", -1, -1, 100, 100);
AddSummary("cpu-cycles", 0, -1, 200, 100);
@@ -659,6 +706,7 @@ TEST_F(StatCmdSummariesTest, cpu_cycles_comment) {
ASSERT_EQ(*GetComment(3), "3.000000 GHz");
}
+// @CddTest = 6.1/C-0-2
TEST_F(StatCmdSummariesTest, rate_comment) {
AddSummary("branch-misses", -1, -1, 1e9, 1e9);
AddSummary("branch-misses", 0, -1, 1e6, 1e9);
diff --git a/simpleperf/cmd_trace_sched_test.cpp b/simpleperf/cmd_trace_sched_test.cpp
index 11ba3ba5..a48f97cb 100644
--- a/simpleperf/cmd_trace_sched_test.cpp
+++ b/simpleperf/cmd_trace_sched_test.cpp
@@ -43,10 +43,12 @@ static std::unique_ptr<Command> TraceSchedCmd() {
return CreateCommandInstance("trace-sched");
}
+// @CddTest = 6.1/C-0-2
TEST(trace_sched_cmd, smoke) {
TEST_IN_ROOT({ ASSERT_TRUE(TraceSchedCmd()->Run({"--duration", "1"})); });
}
+// @CddTest = 6.1/C-0-2
TEST(trace_sched_cmd, report_smoke) {
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
diff --git a/simpleperf/command_test.cpp b/simpleperf/command_test.cpp
index 392ec8ac..a8c59655 100644
--- a/simpleperf/command_test.cpp
+++ b/simpleperf/command_test.cpp
@@ -27,6 +27,7 @@ class MockCommand : public Command {
bool Run(const std::vector<std::string>&) override { return true; }
};
+// @CddTest = 6.1/C-0-2
TEST(command, CreateCommandInstance) {
ASSERT_TRUE(CreateCommandInstance("mock1") == nullptr);
RegisterCommand("mock1", [] { return std::unique_ptr<Command>(new MockCommand); });
@@ -35,6 +36,7 @@ TEST(command, CreateCommandInstance) {
ASSERT_TRUE(CreateCommandInstance("mock1") == nullptr);
}
+// @CddTest = 6.1/C-0-2
TEST(command, GetAllCommands) {
size_t command_count = GetAllCommandNames().size();
RegisterCommand("mock1", [] { return std::unique_ptr<Command>(new MockCommand); });
@@ -43,6 +45,7 @@ TEST(command, GetAllCommands) {
ASSERT_EQ(command_count, GetAllCommandNames().size());
}
+// @CddTest = 6.1/C-0-2
TEST(command, GetValueForOption) {
MockCommand command;
uint64_t value;
@@ -70,6 +73,7 @@ TEST(command, GetValueForOption) {
ASSERT_DOUBLE_EQ(double_value, 3.2);
}
+// @CddTest = 6.1/C-0-2
TEST(command, PreprocessOptions) {
MockCommand cmd;
OptionValueMap options;
@@ -156,6 +160,7 @@ TEST(command, PreprocessOptions) {
&ordered_options, nullptr));
}
+// @CddTest = 6.1/C-0-2
TEST(command, OptionValueMap) {
OptionValue value;
value.uint_value = 10;
diff --git a/simpleperf/doc/collect_etm_data_for_autofdo.md b/simpleperf/doc/collect_etm_data_for_autofdo.md
index 059ffb4e..e86f1bba 100644
--- a/simpleperf/doc/collect_etm_data_for_autofdo.md
+++ b/simpleperf/doc/collect_etm_data_for_autofdo.md
@@ -81,20 +81,15 @@ branch with count info for binary2
We need to split perf_inject.data, and make sure one file only contains info for one binary.
-Then we can use [AutoFDO](https://github.com/google/autofdo) to create profile. AutoFDO only works
-for binaries having an executable segment as its first loadable segment. But binaries built in
-Android may not follow this rule. Simpleperf inject command knows how to work around this problem.
-But there is a check in AutoFDO forcing binaries to start with an executable segment. We need to
-disable the check in AutoFDO, by commenting out L127-L136 in
-https://github.com/google/autofdo/commit/188db2834ce74762ed17108ca344916994640708#diff-2d132ecbb5e4f13e0da65419f6d1759dd27d6b696786dd7096c0c34d499b1710R127-R136.
-Then we can use `create_llvm_prof` in AutoFDO to create profiles used by clang.
+Then we can use [AutoFDO](https://github.com/google/autofdo) to create profile. Follow README.md
+in AutoFDO to build create_llvm_prof, then use `create_llvm_prof` to create profiles for clang.
```sh
# perf_inject_binary1.data is split from perf_inject.data, and only contains branch info for binary1.
-host $ autofdo/create_llvm_prof -profile perf_inject_binary1.data -profiler text -binary path_of_binary1 -out a.prof -format binary
+host $ create_llvm_prof -profile perf_inject_binary1.data -profiler text -binary path_of_binary1 -out a.prof -format binary
# perf_inject_kernel.data is split from perf_inject.data, and only contains branch info for [kernel.kallsyms].
-host $ autofdo/create_llvm_prof -profile perf_inject_kernel.data -profiler text -binary vmlinux -out a.prof -format binary
+host $ create_llvm_prof -profile perf_inject_kernel.data -profiler text -binary vmlinux -out a.prof -format binary
```
Then we can use a.prof for PGO during compilation, via `-fprofile-sample-use=a.prof`.
@@ -121,14 +116,13 @@ Step 2: Run `etm_test_loop` on device, and collect ETM data for its running.
(host) <AOSP>$ adb push out/target/product/generic_arm64/system/bin/etm_test_loop /data/local/tmp
(host) <AOSP>$ adb root
(host) <AOSP>$ adb shell
-(device) / # cd /data/local/tmp
-(device) /data/local/tmp # chmod a+x etm_test_loop
-(device) /data/local/tmp # simpleperf record -e cs-etm:u ./etm_test_loop
-simpleperf I cmd_record.cpp:729] Recorded for 0.0370068 seconds. Start post processing.
-simpleperf I cmd_record.cpp:799] Aux data traced: 1689136
-(device) /data/local/tmp # simpleperf inject -i perf.data --output branch-list -o branch_list.data
-simpleperf W dso.cpp:557] failed to read min virtual address of [vdso]: File not found
-(device) /data/local/tmp # exit
+(device) / $ cd /data/local/tmp
+(device) /data/local/tmp $ chmod a+x etm_test_loop
+(device) /data/local/tmp $ simpleperf record -e cs-etm:u ./etm_test_loop
+simpleperf I cmd_record.cpp:809] Recorded for 0.033556 seconds. Start post processing.
+simpleperf I cmd_record.cpp:879] Aux data traced: 1,134,720
+(device) /data/local/tmp $ simpleperf inject -i perf.data --output branch-list -o branch_list.data
+(device) /data/local/tmp $ exit
(host) <AOSP>$ adb pull /data/local/tmp/branch_list.data
```
@@ -137,47 +131,43 @@ Step 3: Convert ETM data to AutoFDO data.
```sh
# Build simpleperf tool on host.
(host) <AOSP>$ make simpleperf_ndk
-(host) <AOSP>$ simpleperf_ndk64 inject -i branch_list.data -o perf_inject_etm_test_loop.data --symdir out/target/product/generic_arm64/symbols/system/bin
-simpleperf W cmd_inject.cpp:505] failed to build instr ranges for binary [vdso]: File not found
+(host) <AOSP>$ simpleperf inject -i branch_list.data -o perf_inject_etm_test_loop.data --symdir out/target/product/generic_arm64/symbols/system/bin
(host) <AOSP>$ cat perf_inject_etm_test_loop.data
-13
-1000-1010:1
-1014-1050:1
+14
+4000-4010:1
+4014-4048:1
...
-112c->0:1
+418c->0:1
+// build_id: 0xa6fc5b506adf9884cdb680b4893c505a00000000
// /data/local/tmp/etm_test_loop
(host) <AOSP>$ create_llvm_prof -profile perf_inject_etm_test_loop.data -profiler text -binary out/target/product/generic_arm64/symbols/system/bin/etm_test_loop -out etm_test_loop.afdo -format binary
(host) <AOSP>$ ls -lh etm_test_loop.afdo
-rw-r--r-- 1 user group 241 Aug 29 16:04 etm_test_loop.afdo
+rw-r--r-- 1 user group 241 Apr 30 09:52 etm_test_loop.afdo
```
Step 4: Use AutoFDO data to build optimized binary.
```sh
-(host) <AOSP>$ mkdir toolchain/pgo-profiles/sampling/
(host) <AOSP>$ cp etm_test_loop.afdo toolchain/pgo-profiles/sampling/
(host) <AOSP>$ vi toolchain/pgo-profiles/sampling/Android.bp
-# edit Android.bp to add a fdo_profile module
-# soong_namespace {}
+# Edit Android.bp to add a fdo_profile module:
#
# fdo_profile {
-# name: "etm_test_loop_afdo",
-# profile: ["etm_test_loop.afdo"],
+# name: "etm_test_loop",
+# profile: "etm_test_loop.afdo"
# }
-```
-
-`soong_namespace` is added to support fdo_profile modules with the same name
-
-In a product config mk file, update `PRODUCT_AFDO_PROFILES` with
-
-```make
-PRODUCT_AFDO_PROFILES += etm_test_loop://toolchain/pgo-profiles/sampling:etm_test_loop_afdo
-```
-
-```sh
+(host) <AOSP>$ vi toolchain/pgo-profiles/sampling/afdo_profiles.mk
+# Edit afdo_profiles.mk to add etm_test_loop profile mapping:
+#
+# AFDO_PROFILES += keystore2://toolchain/pgo-profiles/sampling:keystore2 \
+# ...
+# server_configurable_flags://toolchain/pgo-profiles/sampling:server_configurable_flags \
+# etm_test_loop://toolchain/pgo-profiles/sampling:etm_test_loop
+#
(host) <AOSP>$ vi system/extras/simpleperf/runtest/Android.bp
-# edit Android.bp to enable afdo for etm_test_loop.
+# Edit Android.bp to enable afdo for etm_test_loop:
+#
# cc_binary {
# name: "etm_test_loop",
# srcs: ["etm_test_loop.cpp"],
@@ -186,6 +176,14 @@ PRODUCT_AFDO_PROFILES += etm_test_loop://toolchain/pgo-profiles/sampling:etm_tes
(host) <AOSP>$ make etm_test_loop
```
+We can check if `etm_test_loop.afdo` is used when building etm_test_loop.
+
+```sh
+(host) <AOSP>$ gzip -d out/verbose.log.gz
+(host) <AOSP>$ cat out/verbose.log | grep etm_test_loop.afdo
+ ... -fprofile-sample-use=toolchain/pgo-profiles/sampling/etm_test_loop.afdo ...
+```
+
If comparing the disassembly of `out/target/product/generic_arm64/symbols/system/bin/etm_test_loop`
before and after optimizing with AutoFDO data, we can see different preferences when branching.
diff --git a/simpleperf/doc/scripts_reference.md b/simpleperf/doc/scripts_reference.md
index d118ed2c..af74458e 100644
--- a/simpleperf/doc/scripts_reference.md
+++ b/simpleperf/doc/scripts_reference.md
@@ -151,6 +151,9 @@ $ ./report_html.py --add_disassembly
# Adding disassembly for all binaries can cost a lot of time. So we can choose to only add
# disassembly for selected binaries.
$ ./report_html.py --add_disassembly --binary_filter libgame.so
+# Add disassembly and source code for binaries belonging to an app with package name
+# com.example.myapp.
+$ ./report_html.py --add_source_code --add_disassembly --binary_filter com.example.myapp
# report_html.py accepts more than one recording data file.
$ ./report_html.py -i perf1.data perf2.data
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 607bf7d8..1380ada9 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -875,8 +875,8 @@ class KernelModuleDso : public Dso {
if (elf) {
status = elf->ParseSymbols(symbol_callback);
}
- ReportReadElfSymbolResult(status, path_, GetDebugFilePath(),
- symbols_.empty() ? android::base::WARNING : android::base::DEBUG);
+ // Don't warn when a kernel module is missing. As a backup, we read symbols from /proc/kallsyms.
+ ReportReadElfSymbolResult(status, path_, GetDebugFilePath(), android::base::DEBUG);
SortAndFixSymbols(symbols);
return symbols;
}
@@ -897,6 +897,10 @@ class KernelModuleDso : public Dso {
// and its vaddr_in_file from the kernel module file. Then other symbols in .text section can
// be mapped in the same way. Below we use the second method.
+ if (!IsRegularFile(GetDebugFilePath())) {
+ return;
+ }
+
// 1. Select a module symbol in /proc/kallsyms.
kernel_dso_->LoadSymbols();
const auto& kernel_symbols = kernel_dso_->GetSymbols();
diff --git a/simpleperf/dso_test.cpp b/simpleperf/dso_test.cpp
index 11bcde19..f9199e41 100644
--- a/simpleperf/dso_test.cpp
+++ b/simpleperf/dso_test.cpp
@@ -30,6 +30,7 @@
using namespace simpleperf;
using namespace simpleperf_dso_impl;
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, use_build_id_list) {
// Create a temp symdir with build_id_list.
TemporaryDir tmpdir;
@@ -57,6 +58,7 @@ static std::string ConvertPathSeparator(const std::string& path) {
return result;
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, concatenating_symfs_dir) {
DebugElfFileFinder finder;
ASSERT_TRUE(finder.SetSymFsDir(GetTestDataDir()));
@@ -73,6 +75,7 @@ TEST(DebugElfFileFinder, concatenating_symfs_dir) {
GetTestDataDir() + apk_path + "!/" + NATIVELIB_IN_APK);
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, use_vdso) {
DebugElfFileFinder finder;
std::string fake_vdso32 = "fake_vdso32";
@@ -84,6 +87,7 @@ TEST(DebugElfFileFinder, use_vdso) {
ASSERT_EQ(finder.FindDebugFile("[vdso]", true, build_id), fake_vdso64);
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, add_symbol_dir) {
DebugElfFileFinder finder;
ASSERT_FALSE(finder.AddSymbolDir(GetTestDataDir() + "dir_not_exist"));
@@ -94,6 +98,7 @@ TEST(DebugElfFileFinder, add_symbol_dir) {
symfs_dir + OS_PATH_SEPARATOR + "elf_for_build_id_check");
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, build_id_list) {
DebugElfFileFinder finder;
// Find file in symfs dir with correct build_id_list.
@@ -109,6 +114,7 @@ TEST(DebugElfFileFinder, build_id_list) {
ASSERT_EQ(finder.FindDebugFile("elf", false, CHECK_ELF_FILE_BUILD_ID), "elf");
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, no_build_id) {
DebugElfFileFinder finder;
// If not given a build id, we should match an elf in symfs without build id.
@@ -118,6 +124,7 @@ TEST(DebugElfFileFinder, no_build_id) {
ASSERT_EQ(finder.FindDebugFile("elf", false, build_id), symfs_dir + OS_PATH_SEPARATOR + "elf");
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, find_basename_in_symfs_dir) {
DebugElfFileFinder finder;
// Find normal elf file.
@@ -136,6 +143,7 @@ TEST(DebugElfFileFinder, find_basename_in_symfs_dir) {
symfs_dir + OS_PATH_SEPARATOR + "elf");
}
+// @CddTest = 6.1/C-0-2
TEST(DebugElfFileFinder, build_id_mismatch) {
DebugElfFileFinder finder;
finder.SetSymFsDir(GetTestDataDir());
@@ -148,6 +156,7 @@ TEST(DebugElfFileFinder, build_id_mismatch) {
ASSERT_NE(stderr_output.find("build id mismatch"), std::string::npos);
}
+// @CddTest = 6.1/C-0-2
TEST(dso, dex_file_dso) {
#if defined(__linux__)
for (DsoType dso_type : {DSO_DEX_FILE, DSO_ELF_FILE}) {
@@ -177,6 +186,7 @@ TEST(dso, dex_file_dso) {
#endif // defined(__linux__)
}
+// @CddTest = 6.1/C-0-2
TEST(dso, dex_file_offsets) {
std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_DEX_FILE, "");
ASSERT_TRUE(dso);
@@ -186,6 +196,7 @@ TEST(dso, dex_file_offsets) {
ASSERT_EQ(*dso->DexFileOffsets(), std::vector<uint64_t>({0x1, 0x2, 0x3, 0x4, 0x5}));
}
+// @CddTest = 6.1/C-0-2
TEST(dso, embedded_elf) {
const std::string file_path = GetUrlInApk(GetTestData(APK_FILE), NATIVELIB_IN_APK);
std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_ELF_FILE, file_path);
@@ -205,12 +216,14 @@ TEST(dso, embedded_elf) {
ASSERT_EQ(build_id, native_lib_build_id);
}
+// @CddTest = 6.1/C-0-2
TEST(dso, IpToVaddrInFile) {
std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_ELF_FILE, GetTestData("libc.so"));
ASSERT_TRUE(dso);
ASSERT_EQ(0xa5140, dso->IpToVaddrInFile(0xe9201140, 0xe9201000, 0xa5000));
}
+// @CddTest = 6.1/C-0-2
TEST(dso, kernel_address_randomization) {
// Use ELF_FILE as a fake kernel vmlinux.
const std::string vmlinux_path = GetTestData(ELF_FILE);
@@ -234,6 +247,7 @@ TEST(dso, kernel_address_randomization) {
ASSERT_STREQ(symbol->Name(), "GlobalFunc");
}
+// @CddTest = 6.1/C-0-2
TEST(dso, find_vmlinux_in_symdirs) {
// Create a symdir.
TemporaryDir tmpdir;
@@ -260,6 +274,7 @@ TEST(dso, find_vmlinux_in_symdirs) {
ASSERT_EQ(0x400927, dso->IpToVaddrInFile(0x800527, 0x800000, 0));
}
+// @CddTest = 6.1/C-0-2
TEST(dso, kernel_module) {
// Test finding debug files for kernel modules.
Dso::SetSymFsDir(GetTestDataDir());
@@ -272,14 +287,16 @@ TEST(dso, kernel_module) {
ASSERT_EQ(dso->GetDebugFilePath(), GetTestData(ELF_FILE));
}
+// @CddTest = 6.1/C-0-2
TEST(dso, kernel_module_CalculateMinVaddr) {
// Create fake Dso objects.
auto kernel_dso = Dso::CreateDso(DSO_KERNEL, DEFAULT_KERNEL_MMAP_NAME);
ASSERT_TRUE(kernel_dso);
const uint64_t module_memory_start = 0xffffffa9bc790000ULL;
const uint64_t module_memory_size = 0x8d7000ULL;
+ TemporaryFile tmpfile;
auto module_dso =
- Dso::CreateKernelModuleDso("fake_module.ko", module_memory_start,
+ Dso::CreateKernelModuleDso(tmpfile.path, module_memory_start,
module_memory_start + module_memory_size, kernel_dso.get());
ASSERT_TRUE(module_dso);
@@ -302,6 +319,7 @@ TEST(dso, kernel_module_CalculateMinVaddr) {
ASSERT_EQ(module_dso->IpToVaddrInFile(0xffffffa9bc7a64e8ULL, module_memory_start, 0), 0x144e8);
}
+// @CddTest = 6.1/C-0-2
TEST(dso, symbol_map_file) {
auto dso = Dso::CreateDso(DSO_SYMBOL_MAP_FILE, "perf-123.map");
ASSERT_TRUE(dso);
@@ -310,6 +328,7 @@ TEST(dso, symbol_map_file) {
ASSERT_EQ(0x12345678, dso->IpToVaddrInFile(0x12345678, 0xe9201000, 0xa5000));
}
+// @CddTest = 6.1/C-0-2
TEST(dso, FunctionName) {
Symbol symbol = Symbol("void ctep.v(cteo, ctgc, ctbn)", 0x0, 0x1);
ASSERT_EQ(symbol.FunctionName(), "ctep.v");
@@ -319,6 +338,7 @@ TEST(dso, FunctionName) {
ASSERT_EQ(symbol.FunctionName(), "ctep.v");
}
+// @CddTest = 6.1/C-0-2
TEST(dso, search_debug_file_only_when_needed) {
Dso::SetBuildIds({std::make_pair("/elf", BuildId("1b12a384a9f4a3f3659b7171ca615dbec3a81f71"))});
Dso::SetSymFsDir(GetTestDataDir());
@@ -330,6 +350,7 @@ TEST(dso, search_debug_file_only_when_needed) {
capture.Stop();
}
+// @CddTest = 6.1/C-0-2
TEST(dso, read_symbol_warning) {
{
// Don't warn when the file may not be an ELF file.
@@ -370,6 +391,7 @@ TEST(dso, read_symbol_warning) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(dso, demangle) {
ASSERT_EQ(Dso::Demangle("main"), "main");
ASSERT_EQ(Dso::Demangle("_ZN4main4main17h2a68d4d833d7495aE"), "main::main::h2a68d4d833d7495a");
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index 88587dc3..55074d8a 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -75,6 +75,9 @@ std::vector<int> GetOnlineCpus() {
static void GetAllModuleFiles(const std::string& path,
std::unordered_map<std::string, std::string>* module_file_map) {
+ if (!IsDir(path)) {
+ return;
+ }
for (const auto& name : GetEntriesInDir(path)) {
std::string entry_path = path + "/" + name;
if (IsRegularFile(entry_path) && android::base::EndsWith(name, ".ko")) {
@@ -94,9 +97,13 @@ static std::vector<KernelMmap> GetModulesInUse() {
}
std::unordered_map<std::string, std::string> module_file_map;
#if defined(__ANDROID__)
- // Search directories listed in "File locations" section in
- // https://source.android.com/devices/architecture/kernel/modular-kernels.
- for (const auto& path : {"/vendor/lib/modules", "/odm/lib/modules", "/lib/modules"}) {
+ // On Android, kernel modules are stored in /system/lib/modules, /vendor/lib/modules,
+ // /odm/lib/modules.
+ // See https://source.android.com/docs/core/architecture/partitions/gki-partitions and
+ // https://source.android.com/docs/core/architecture/partitions/vendor-odm-dlkm-partition.
+ // They can also be stored in vendor_kernel_ramdisk.img, which isn't accessible from userspace.
+ // See https://source.android.com/docs/core/architecture/kernel/kernel-module-support.
+ for (const auto& path : {"/system/lib/modules", "/vendor/lib/modules", "/odm/lib/modules"}) {
GetAllModuleFiles(path, &module_file_map);
}
#else
diff --git a/simpleperf/environment_test.cpp b/simpleperf/environment_test.cpp
index 87c4998a..49a9bb53 100644
--- a/simpleperf/environment_test.cpp
+++ b/simpleperf/environment_test.cpp
@@ -29,6 +29,7 @@
namespace fs = std::filesystem;
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(environment, PrepareVdsoFile) {
std::string content;
ASSERT_TRUE(android::base::ReadFileToString("/proc/self/maps", &content));
@@ -46,6 +47,7 @@ TEST(environment, PrepareVdsoFile) {
ASSERT_NE(dso->GetDebugFilePath(), "[vdso]");
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetHardwareFromCpuInfo) {
std::string cpu_info =
"CPU revision : 10\n\n"
@@ -54,6 +56,7 @@ TEST(environment, GetHardwareFromCpuInfo) {
GetHardwareFromCpuInfo(cpu_info));
}
+// @CddTest = 6.1/C-0-2
TEST(environment, MappedFileOnlyExistInMemory) {
ASSERT_TRUE(MappedFileOnlyExistInMemory(""));
ASSERT_TRUE(MappedFileOnlyExistInMemory("[stack]"));
@@ -66,6 +69,7 @@ TEST(environment, MappedFileOnlyExistInMemory) {
ASSERT_FALSE(MappedFileOnlyExistInMemory("/system/lib64/libc.so"));
}
+// @CddTest = 6.1/C-0-2
TEST(environment, SetPerfEventLimits) {
#if defined(__ANDROID__)
if (GetAndroidVersion() <= kAndroidVersionP) {
@@ -101,10 +105,12 @@ TEST(environment, SetPerfEventLimits) {
#endif
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetKernelVersion) {
ASSERT_TRUE(GetKernelVersion());
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetModuleBuildId) {
BuildId build_id;
fs::path dir(GetTestData("sysfs/module/fake_kernel_module/notes"));
@@ -114,6 +120,7 @@ TEST(environment, GetModuleBuildId) {
ASSERT_EQ(build_id, BuildId("3e0ba155286f3454"));
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetKernelAndModuleMmaps) {
TEST_REQUIRE_ROOT();
KernelMmap kernel_mmap;
@@ -124,12 +131,14 @@ TEST(environment, GetKernelAndModuleMmaps) {
ASSERT_GT(kernel_mmap.start_addr, 0);
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetProcessUid) {
std::optional<uid_t> uid = GetProcessUid(getpid());
ASSERT_TRUE(uid.has_value());
ASSERT_EQ(uid.value(), getuid());
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetAppType) {
TEST_REQUIRE_APPS();
ASSERT_EQ(GetAppType("com.android.simpleperf.debuggable"), "debuggable");
@@ -137,12 +146,14 @@ TEST(environment, GetAppType) {
ASSERT_EQ(GetAppType("com.android.simpleperf.app_not_exist"), "not_exist");
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetMemorySize) {
auto value = GetMemorySize();
ASSERT_TRUE(value);
ASSERT_GT(value.value(), 0);
}
+// @CddTest = 6.1/C-0-2
TEST(environment, GetARMCpuModels) {
#if defined(__aarch64__) && defined(__ANDROID__)
auto models = GetARMCpuModels();
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index c75f8049..1a7cdef8 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -233,6 +233,8 @@ bool EventSelectionSet::BuildAndCheckEventSelection(const std::string& event_nam
// enabling/disabling etm devices. So don't adjust frequency by default.
selection->event_attr.freq = 0;
selection->event_attr.sample_period = 1;
+ // An ETM event can't be enabled without mmap aux buffer. So disable it by default.
+ selection->event_attr.disabled = 1;
} else {
selection->event_attr.freq = 1;
// Set default sample freq here may print msg "Adjust sample freq to max allowed sample
@@ -461,6 +463,17 @@ void EventSelectionSet::SetEnableCondition(bool enable_on_open, bool enable_on_e
}
}
+bool EventSelectionSet::IsEnabledOnExec() const {
+ for (const auto& group : groups_) {
+ for (const auto& selection : group.selections) {
+ if (!selection.event_attr.enable_on_exec) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
void EventSelectionSet::SampleIdAll() {
for (auto& group : groups_) {
for (auto& selection : group.selections) {
@@ -939,4 +952,61 @@ bool EventSelectionSet::SetEnableEvents(bool enable) {
return true;
}
+bool EventSelectionSet::EnableETMEvents() {
+ for (auto& group : groups_) {
+ for (auto& sel : group.selections) {
+ if (!sel.event_type_modifier.event_type.IsEtmEvent()) {
+ continue;
+ }
+ for (auto& fd : sel.event_fds) {
+ if (!fd->SetEnableEvent(true)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool EventSelectionSet::DisableETMEvents() {
+ for (auto& group : groups_) {
+ for (auto& sel : group.selections) {
+ if (!sel.event_type_modifier.event_type.IsEtmEvent()) {
+ continue;
+ }
+ // When using ETR, ETM data is flushed to the aux buffer of the last cpu disabling ETM events.
+ // To avoid overflowing the aux buffer for one cpu, rotate the last cpu disabling ETM events.
+ if (etm_event_cpus_.empty()) {
+ for (const auto& fd : sel.event_fds) {
+ etm_event_cpus_.insert(fd->Cpu());
+ }
+ if (etm_event_cpus_.empty()) {
+ continue;
+ }
+ etm_event_cpus_it_ = etm_event_cpus_.begin();
+ }
+ int last_disabled_cpu = *etm_event_cpus_it_;
+ if (++etm_event_cpus_it_ == etm_event_cpus_.end()) {
+ etm_event_cpus_it_ = etm_event_cpus_.begin();
+ }
+
+ for (auto& fd : sel.event_fds) {
+ if (fd->Cpu() != last_disabled_cpu) {
+ if (!fd->SetEnableEvent(false)) {
+ return false;
+ }
+ }
+ }
+ for (auto& fd : sel.event_fds) {
+ if (fd->Cpu() == last_disabled_cpu) {
+ if (!fd->SetEnableEvent(false)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
} // namespace simpleperf
diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h
index e046035b..a892d51e 100644
--- a/simpleperf/event_selection_set.h
+++ b/simpleperf/event_selection_set.h
@@ -122,6 +122,7 @@ class EventSelectionSet {
std::map<int, size_t> GetHardwareCountersForCpus() const;
void SetEnableCondition(bool enable_on_open, bool enable_on_exec);
+ bool IsEnabledOnExec() const;
void SampleIdAll();
// Only set sample rate for events that haven't set sample rate.
void SetSampleRateForNewEvents(const SampleRate& rate);
@@ -179,6 +180,8 @@ class EventSelectionSet {
double check_interval_in_sec = DEFAULT_PERIOD_TO_CHECK_MONITORED_TARGETS_IN_SEC);
bool SetEnableEvents(bool enable);
+ bool EnableETMEvents();
+ bool DisableETMEvents();
private:
struct EventSelection {
@@ -232,6 +235,9 @@ class EventSelectionSet {
std::optional<SampleRate> sample_rate_;
std::optional<std::vector<int>> cpus_;
+ std::set<int> etm_event_cpus_;
+ std::set<int>::const_iterator etm_event_cpus_it_;
+
DISALLOW_COPY_AND_ASSIGN(EventSelectionSet);
};
diff --git a/simpleperf/event_selection_set_test.cpp b/simpleperf/event_selection_set_test.cpp
index 2cf0e0a6..e60d81a8 100644
--- a/simpleperf/event_selection_set_test.cpp
+++ b/simpleperf/event_selection_set_test.cpp
@@ -20,6 +20,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(EventSelectionSet, set_sample_rate_for_new_events) {
EventSelectionSet event_selection_set(false);
ASSERT_TRUE(event_selection_set.AddEventType("cpu-clock:u"));
@@ -43,6 +44,7 @@ TEST(EventSelectionSet, set_sample_rate_for_new_events) {
ASSERT_EQ(attrs[3].attr.sample_freq, 200);
}
+// @CddTest = 6.1/C-0-2
TEST(EventSelectionSet, add_event_with_sample_rate) {
EventSelectionSet event_selection_set(false);
ASSERT_TRUE(event_selection_set.AddEventType("cpu-clock:u"));
@@ -57,6 +59,7 @@ TEST(EventSelectionSet, add_event_with_sample_rate) {
ASSERT_EQ(attrs[1].attr.sample_period, 1);
}
+// @CddTest = 6.1/C-0-2
TEST(EventSelectionSet, set_cpus_for_new_events) {
EventSelectionSet event_selection_set(false);
std::vector<int> online_cpus = GetOnlineCpus();
diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp
index 0d10d12d..d8379141 100644
--- a/simpleperf/event_type.cpp
+++ b/simpleperf/event_type.cpp
@@ -104,7 +104,11 @@ class TracepointStringFinder : public EventTypeFinder {
protected:
void LoadTypes() override {
for (const auto& line : android::base::Split(s_, "\n")) {
- std::vector<std::string> items = android::base::Split(line, " ");
+ std::string str = android::base::Trim(line);
+ if (str.empty()) {
+ continue;
+ }
+ std::vector<std::string> items = android::base::Split(str, " ");
CHECK_EQ(items.size(), 2u);
std::string event_name = items[0];
uint64_t id;
diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h
index 14863caa..d85f71d1 100644
--- a/simpleperf/event_type.h
+++ b/simpleperf/event_type.h
@@ -55,6 +55,7 @@ struct EventType {
bool IsHardwareEvent() const {
return type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE || type == PERF_TYPE_RAW;
}
+ bool IsTracepointEvent() const { return type == PERF_TYPE_TRACEPOINT; }
std::vector<int> GetPmuCpumask();
diff --git a/simpleperf/kallsyms_test.cpp b/simpleperf/kallsyms_test.cpp
index cacd1634..d2bc8583 100644
--- a/simpleperf/kallsyms_test.cpp
+++ b/simpleperf/kallsyms_test.cpp
@@ -39,6 +39,7 @@ static bool KernelSymbolsMatch(const KernelSymbol& sym1, const KernelSymbol& sym
ModulesMatch(sym1.module, sym2.module);
}
+// @CddTest = 6.1/C-0-2
TEST(kallsyms, ProcessKernelSymbols) {
std::string data =
"ffffffffa005c4e4 d __warned.41698 [libsas]\n"
@@ -64,6 +65,7 @@ TEST(kallsyms, ProcessKernelSymbols) {
data, std::bind(&KernelSymbolsMatch, std::placeholders::_1, expected_symbol)));
}
+// @CddTest = 6.1/C-0-2
TEST(kallsyms, ProcessKernelSymbols_ignore_arm_mapping_symbols) {
std::string data =
"aaaaaaaaaaaaaaaa t $x.9 [coresight_etm4x]\n"
@@ -84,17 +86,20 @@ TEST(kallsyms, ProcessKernelSymbols_ignore_arm_mapping_symbols) {
}
#if defined(__ANDROID__)
+// @CddTest = 6.1/C-0-2
TEST(kallsyms, GetKernelStartAddress) {
TEST_REQUIRE_ROOT();
ASSERT_NE(GetKernelStartAddress(), 0u);
}
+// @CddTest = 6.1/C-0-2
TEST(kallsyms, LoadKernelSymbols) {
TEST_REQUIRE_ROOT();
std::string kallsyms;
ASSERT_TRUE(LoadKernelSymbols(&kallsyms));
}
+// @CddTest = 6.1/C-0-2
TEST(kallsyms, print_warning) {
TEST_REQUIRE_NON_ROOT();
const std::string warning_msg = "Access to kernel symbol addresses is restricted.";
diff --git a/simpleperf/perf_regs_test.cpp b/simpleperf/perf_regs_test.cpp
index 0af97478..bc33ca9d 100644
--- a/simpleperf/perf_regs_test.cpp
+++ b/simpleperf/perf_regs_test.cpp
@@ -20,6 +20,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(RegSet, arch) {
ArchType arch_pairs[3][2] = {
{ARCH_X86_32, ARCH_X86_64},
diff --git a/simpleperf/read_apk_test.cpp b/simpleperf/read_apk_test.cpp
index e4dd71f5..c0be177c 100644
--- a/simpleperf/read_apk_test.cpp
+++ b/simpleperf/read_apk_test.cpp
@@ -22,6 +22,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(read_apk, FindElfInApkByOffset) {
ApkInspector inspector;
ASSERT_TRUE(inspector.FindElfInApkByOffset("/dev/null", 0) == nullptr);
@@ -36,6 +37,7 @@ TEST(read_apk, FindElfInApkByOffset) {
ASSERT_EQ(NATIVELIB_SIZE_IN_APK, ee->entry_size());
}
+// @CddTest = 6.1/C-0-2
TEST(read_apk, FindElfInApkByName) {
ASSERT_TRUE(ApkInspector::FindElfInApkByName("/dev/null", "") == nullptr);
ASSERT_TRUE(ApkInspector::FindElfInApkByName(GetTestData(APK_FILE), "") == nullptr);
@@ -45,6 +47,7 @@ TEST(read_apk, FindElfInApkByName) {
ASSERT_EQ(NATIVELIB_SIZE_IN_APK, ee->entry_size());
}
+// @CddTest = 6.1/C-0-2
TEST(read_apk, ParseExtractedInMemoryPath) {
std::string zip_path;
std::string entry_name;
diff --git a/simpleperf/read_dex_file_test.cpp b/simpleperf/read_dex_file_test.cpp
index 843a964c..a9860f83 100644
--- a/simpleperf/read_dex_file_test.cpp
+++ b/simpleperf/read_dex_file_test.cpp
@@ -27,6 +27,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(read_dex_file, smoke) {
std::vector<Symbol> symbols;
auto symbol_callback = [&](DexFileSymbol* symbol) {
diff --git a/simpleperf/read_elf_test.cpp b/simpleperf/read_elf_test.cpp
index e2a2cd88..709205a8 100644
--- a/simpleperf/read_elf_test.cpp
+++ b/simpleperf/read_elf_test.cpp
@@ -32,6 +32,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(read_elf, GetBuildIdFromNoteSection) {
BuildId build_id;
std::vector<char> data;
@@ -62,6 +63,7 @@ TEST(read_elf, GetBuildIdFromNoteSection) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, GetBuildIdFromElfFile) {
BuildId build_id;
ElfStatus status;
@@ -71,6 +73,7 @@ TEST(read_elf, GetBuildIdFromElfFile) {
ASSERT_EQ(build_id, BuildId(elf_file_build_id));
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, GetBuildIdFromEmbeddedElfFile) {
BuildId build_id;
ElfStatus status;
@@ -103,6 +106,7 @@ void CheckElfFileSymbols(const std::map<std::string, ElfFileSymbol>& symbols) {
CheckFunctionSymbols(symbols);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, parse_symbols_from_elf_file_with_correct_build_id) {
std::map<std::string, ElfFileSymbol> symbols;
ElfStatus status;
@@ -113,6 +117,7 @@ TEST(read_elf, parse_symbols_from_elf_file_with_correct_build_id) {
CheckElfFileSymbols(symbols);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, parse_symbols_from_elf_file_without_build_id) {
std::map<std::string, ElfFileSymbol> symbols;
ElfStatus status;
@@ -133,6 +138,7 @@ TEST(read_elf, parse_symbols_from_elf_file_without_build_id) {
CheckElfFileSymbols(symbols);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, parse_symbols_from_elf_file_with_wrong_build_id) {
BuildId build_id("01010101010101010101");
std::map<std::string, ElfFileSymbol> symbols;
@@ -141,6 +147,7 @@ TEST(read_elf, parse_symbols_from_elf_file_with_wrong_build_id) {
ASSERT_EQ(ElfStatus::BUILD_ID_MISMATCH, status);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, ParseSymbolsFromEmbeddedElfFile) {
std::map<std::string, ElfFileSymbol> symbols;
ElfStatus status;
@@ -152,6 +159,7 @@ TEST(read_elf, ParseSymbolsFromEmbeddedElfFile) {
CheckElfFileSymbols(symbols);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, ParseSymbolFromMiniDebugInfoElfFile) {
std::map<std::string, ElfFileSymbol> symbols;
ElfStatus status;
@@ -162,6 +170,7 @@ TEST(read_elf, ParseSymbolFromMiniDebugInfoElfFile) {
CheckFunctionSymbols(symbols);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, arm_mapping_symbol) {
ASSERT_TRUE(IsArmMappingSymbol("$a"));
ASSERT_FALSE(IsArmMappingSymbol("$b"));
@@ -169,6 +178,7 @@ TEST(read_elf, arm_mapping_symbol) {
ASSERT_FALSE(IsArmMappingSymbol("$a_no_dot"));
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, ElfFile_Open) {
auto IsValidElfPath = [](const std::string& path) {
ElfStatus status;
@@ -183,6 +193,7 @@ TEST(read_elf, ElfFile_Open) {
ASSERT_EQ(ElfStatus::NO_ERROR, IsValidElfPath(GetTestData(ELF_FILE)));
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, check_symbol_for_plt_section) {
std::map<std::string, ElfFileSymbol> symbols;
ElfStatus status;
@@ -193,6 +204,7 @@ TEST(read_elf, check_symbol_for_plt_section) {
ASSERT_NE(symbols.find("@plt"), symbols.end());
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, read_elf_with_broken_section_table) {
std::string elf_path = GetTestData("libsgmainso-6.4.36.so");
std::map<std::string, ElfFileSymbol> symbols;
@@ -211,6 +223,7 @@ TEST(read_elf, read_elf_with_broken_section_table) {
ASSERT_EQ(file_offset_of_min_vaddr, 0u);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, ReadMinExecutableVaddr) {
ElfStatus status;
auto elf = ElfFile::Open(GetTestData("libc.so"), &status);
@@ -221,6 +234,7 @@ TEST(read_elf, ReadMinExecutableVaddr) {
ASSERT_EQ(file_offset_of_min_vaddr, 0x29000u);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, NoUndefinedSymbol) {
// Check if we read undefined symbols (like dlerror) from libc.so.
bool has_dlerror = false;
@@ -237,6 +251,7 @@ TEST(read_elf, NoUndefinedSymbol) {
ASSERT_FALSE(has_dlerror);
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, VaddrToOff) {
auto elf = ElfFile::Open(GetTestData(ELF_FILE));
ASSERT_TRUE(elf != nullptr);
@@ -247,6 +262,7 @@ TEST(read_elf, VaddrToOff) {
ASSERT_FALSE(elf->VaddrToOff(0x420000, &off));
}
+// @CddTest = 6.1/C-0-2
TEST(read_elf, GetSectionHeader) {
auto elf = ElfFile::Open(GetTestData(ELF_FILE));
ASSERT_TRUE(elf != nullptr);
diff --git a/simpleperf/read_symbol_map_test.cpp b/simpleperf/read_symbol_map_test.cpp
index 9a5ac39b..4365fc9e 100644
--- a/simpleperf/read_symbol_map_test.cpp
+++ b/simpleperf/read_symbol_map_test.cpp
@@ -25,6 +25,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(read_symbol_map, smoke) {
std::string content(
"\n" // skip
@@ -62,6 +63,7 @@ TEST(read_symbol_map, smoke) {
ASSERT_STREQ("six six", symbols[3].Name());
}
+// @CddTest = 6.1/C-0-2
TEST(read_symbol_map, v8_basic_perf_prof) {
// Interesting sample of jitted function names generated by V8 running the
// JetStream2 benchmark.
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index e43e4bdf..7967362e 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -35,6 +35,7 @@
using namespace simpleperf;
using namespace simpleperf::PerfFileFormat;
+// @CddTest = 6.1/C-0-2
class RecordFileTest : public ::testing::Test {
protected:
void SetUp() override { close(tmpfile_.release()); }
@@ -54,6 +55,7 @@ class RecordFileTest : public ::testing::Test {
EventAttrIds attr_ids_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFileTest, smoke) {
// Write to a record file.
std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
@@ -102,6 +104,7 @@ TEST_F(RecordFileTest, smoke) {
ASSERT_TRUE(reader->Close());
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFileTest, record_more_than_one_attr) {
// Write to a record file.
std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
@@ -126,6 +129,7 @@ TEST_F(RecordFileTest, record_more_than_one_attr) {
}
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFileTest, write_meta_info_feature_section) {
// Write to a record file.
std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
@@ -150,6 +154,7 @@ TEST_F(RecordFileTest, write_meta_info_feature_section) {
ASSERT_EQ(reader->GetMetaInfoFeature(), info_map);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFileTest, write_debug_unwind_feature_section) {
// Write to a record file.
std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
@@ -180,6 +185,7 @@ TEST_F(RecordFileTest, write_debug_unwind_feature_section) {
}
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordFileTest, write_file2_feature_section) {
// Write to a record file.
std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
@@ -254,4 +260,4 @@ TEST_F(RecordFileTest, write_file2_feature_section) {
}
ASSERT_FALSE(error);
ASSERT_EQ(file_id, files.size());
-} \ No newline at end of file
+}
diff --git a/simpleperf/record_lib_test.cpp b/simpleperf/record_lib_test.cpp
index 4c1b7e87..15aa9267 100644
--- a/simpleperf/record_lib_test.cpp
+++ b/simpleperf/record_lib_test.cpp
@@ -22,6 +22,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(get_all_events, smoke) {
std::vector<std::string> events = GetAllEvents();
ASSERT_GT(events.size(), 0u);
@@ -36,6 +37,7 @@ static void DoSomeWork() {
}
}
+// @CddTest = 6.1/C-0-2
TEST(counter, add_event) {
std::unique_ptr<PerfEventSet> perf(
PerfEventSet::CreateInstance(PerfEventSet::Type::kPerfForCounting));
@@ -61,6 +63,7 @@ TEST(counter, add_event) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(counter, different_targets) {
auto test_function = [](std::function<void(PerfEventSet*)> set_target_func) {
std::unique_ptr<PerfEventSet> perf(
@@ -87,6 +90,7 @@ TEST(counter, different_targets) {
[](PerfEventSet* perf) { ASSERT_TRUE(perf->MonitorThreadsInCurrentProcess({getpid()})); });
}
+// @CddTest = 6.1/C-0-2
TEST(counter, start_stop_multiple_times) {
const size_t TEST_COUNT = 10;
std::unique_ptr<PerfEventSet> perf(
@@ -116,6 +120,7 @@ TEST(counter, start_stop_multiple_times) {
}
}
+// @CddTest = 6.1/C-0-2
TEST(counter, no_change_after_stop) {
std::unique_ptr<PerfEventSet> perf(
PerfEventSet::CreateInstance(PerfEventSet::Type::kPerfForCounting));
diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp
index bca0b7ff..ed437501 100644
--- a/simpleperf/record_test.cpp
+++ b/simpleperf/record_test.cpp
@@ -23,6 +23,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
class RecordTest : public ::testing::Test {
protected:
virtual void SetUp() {
@@ -42,16 +43,19 @@ class RecordTest : public ::testing::Test {
perf_event_attr event_attr;
};
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, MmapRecordMatchBinary) {
MmapRecord record(event_attr, true, 1, 2, 0x1000, 0x2000, 0x3000, "MmapRecord", 0);
CheckRecordMatchBinary(record);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, CommRecordMatchBinary) {
CommRecord record(event_attr, 1, 2, "CommRecord", 0, 7);
CheckRecordMatchBinary(record);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, SampleRecordMatchBinary) {
event_attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN;
@@ -59,6 +63,7 @@ TEST_F(RecordTest, SampleRecordMatchBinary) {
CheckRecordMatchBinary(record);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, SampleRecord_exclude_kernel_callchain) {
SampleRecord r(event_attr, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, 0);
ASSERT_TRUE(r.ExcludeKernelCallChain());
@@ -103,6 +108,7 @@ TEST_F(RecordTest, SampleRecord_exclude_kernel_callchain) {
{}, 0));
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, SampleRecord_ReplaceRegAndStackWithCallChain) {
event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
std::vector<std::vector<uint64_t>> user_ip_tests = {
@@ -130,6 +136,7 @@ TEST_F(RecordTest, SampleRecord_ReplaceRegAndStackWithCallChain) {
}
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, SampleRecord_UpdateUserCallChain) {
event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1, PERF_CONTEXT_USER, 2}, {}, 0);
@@ -140,6 +147,7 @@ TEST_F(RecordTest, SampleRecord_UpdateUserCallChain) {
CheckRecordEqual(r, expected);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, SampleRecord_AdjustCallChainGeneratedByKernel) {
event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1, 5, 0, PERF_CONTEXT_USER, 6, 0}, {}, 0);
@@ -154,6 +162,7 @@ TEST_F(RecordTest, SampleRecord_AdjustCallChainGeneratedByKernel) {
CheckRecordEqual(r, expected);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, SampleRecord_PerfSampleReadData) {
event_attr.sample_type |= PERF_SAMPLE_READ;
event_attr.read_format =
@@ -180,6 +189,7 @@ TEST_F(RecordTest, SampleRecord_PerfSampleReadData) {
CheckRecordMatchBinary(r2);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, CommRecord) {
CommRecord r(event_attr, 1, 2, "init_name", 3, 4);
size_t record_size = r.size();
@@ -194,6 +204,7 @@ TEST_F(RecordTest, CommRecord) {
CheckRecordMatchBinary(r);
}
+// @CddTest = 6.1/C-0-2
TEST_F(RecordTest, DebugRecord) {
DebugRecord r(1234, "hello");
ASSERT_EQ(r.size() % sizeof(uint64_t), 0);
diff --git a/simpleperf/report_utils_test.cpp b/simpleperf/report_utils_test.cpp
index ad4b9df3..0d96d7d1 100644
--- a/simpleperf/report_utils_test.cpp
+++ b/simpleperf/report_utils_test.cpp
@@ -27,6 +27,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(ProguardMappingRetrace, smoke) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -151,6 +152,7 @@ class CallChainReportBuilderTest : public testing::Test {
};
};
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, default_option) {
// Test default option: remove_art_frame = true, convert_jit_frame = true.
// The callchain shouldn't include interpreter frames. And the JIT frame is
@@ -170,6 +172,7 @@ TEST_F(CallChainReportBuilderTest, default_option) {
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, not_convert_jit_frame) {
// Test option: remove_art_frame = true, convert_jit_frame = false.
// The callchain shouldn't include interpreter frames. And the JIT frame isn't
@@ -190,6 +193,7 @@ TEST_F(CallChainReportBuilderTest, not_convert_jit_frame) {
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, not_remove_art_frame) {
// Test option: remove_art_frame = false, convert_jit_frame = true.
// The callchain should include interpreter frames. And the JIT frame is
@@ -222,6 +226,7 @@ TEST_F(CallChainReportBuilderTest, not_remove_art_frame) {
ASSERT_EQ(entries[5].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, remove_jit_frame_called_by_dex_frame) {
// Test option: remove_art_frame = true, convert_jit_frame = true.
// The callchain should remove the JIT frame called by a dex frame having the same symbol name.
@@ -242,6 +247,7 @@ TEST_F(CallChainReportBuilderTest, remove_jit_frame_called_by_dex_frame) {
ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::INTERPRETED_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, remove_art_frame_only_near_jvm_method) {
// Test option: remove_art_frame = true, convert_jit_frame = true.
// The callchain should not remove ART symbols not near a JVM method.
@@ -277,6 +283,7 @@ TEST_F(CallChainReportBuilderTest, remove_art_frame_only_near_jvm_method) {
ASSERT_EQ(entries[2].execution_type, CallChainExecutionType::INTERPRETED_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, keep_art_jni_method) {
// Test option: remove_art_frame = true.
// The callchain should remove art_jni_trampoline, but keep jni methods.
@@ -305,6 +312,7 @@ TEST_F(CallChainReportBuilderTest, keep_art_jni_method) {
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::INTERPRETED_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
std::vector<uint64_t> fake_ips = {
0x2200, // 2200, // obfuscated_class.obfuscated_java_method
@@ -364,6 +372,7 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file) {
ASSERT_EQ(entries[2].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, not_remove_synthesized_frame_by_default) {
std::vector<uint64_t> fake_ips = {
0x2200, // 2200, // obfuscated_class.obfuscated_java_method
@@ -400,6 +409,7 @@ TEST_F(CallChainReportBuilderTest, not_remove_synthesized_frame_by_default) {
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, remove_synthesized_frame_with_env_variable) {
// Windows doesn't support setenv and unsetenv. So don't test on it.
#if !defined(__WIN32)
@@ -435,6 +445,7 @@ TEST_F(CallChainReportBuilderTest, remove_synthesized_frame_with_env_variable) {
#endif // !defined(__WIN32)
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file_for_jit_method_with_signature) {
std::vector<uint64_t> fake_ips = {
0x3200, // 3200, // void ctep.v(cteo, ctgc, ctbn)
@@ -460,6 +471,7 @@ TEST_F(CallChainReportBuilderTest, add_proguard_mapping_file_for_jit_method_with
ASSERT_EQ(entries[0].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest,
add_proguard_mapping_file_for_compiled_java_method_with_signature) {
TemporaryFile tmpfile;
@@ -492,6 +504,7 @@ TEST_F(CallChainReportBuilderTest,
}
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, convert_jit_frame_for_jit_method_with_signature) {
std::vector<uint64_t> fake_ips = {
0x2200, // 2200, // ctep.v
@@ -540,6 +553,7 @@ TEST_F(CallChainReportBuilderTest, convert_jit_frame_for_jit_method_with_signatu
ASSERT_EQ(entries[1].execution_type, CallChainExecutionType::JIT_JVM_METHOD);
}
+// @CddTest = 6.1/C-0-2
TEST_F(CallChainReportBuilderTest, remove_method_name) {
// Test excluding method names.
CallChainReportBuilder builder(thread_tree);
@@ -588,6 +602,7 @@ class ThreadReportBuilderTest : public testing::Test {
ThreadTree thread_tree;
};
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadReportBuilderTest, no_setting) {
ThreadReportBuilder builder;
ThreadEntry* thread = thread_tree.FindThread(1);
@@ -595,6 +610,7 @@ TEST_F(ThreadReportBuilderTest, no_setting) {
ASSERT_TRUE(IsReportEqual(report, ThreadReport(1, 1, "thread1")));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadReportBuilderTest, aggregate_threads) {
ThreadReportBuilder builder;
ASSERT_TRUE(builder.AggregateThreads({"thread-pool.*"}));
@@ -609,6 +625,7 @@ TEST_F(ThreadReportBuilderTest, aggregate_threads) {
ASSERT_TRUE(IsReportEqual(report, ThreadReport(1, 2, "thread-pool.*")));
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadReportBuilderTest, aggregate_threads_bad_regex) {
ThreadReportBuilder builder;
ASSERT_FALSE(builder.AggregateThreads({"?thread-pool*"}));
diff --git a/simpleperf/sample_tree_test.cpp b/simpleperf/sample_tree_test.cpp
index bee187d7..e2df1cec 100644
--- a/simpleperf/sample_tree_test.cpp
+++ b/simpleperf/sample_tree_test.cpp
@@ -132,6 +132,7 @@ class SampleTreeTest : public testing::Test {
std::unique_ptr<TestSampleTreeBuilder> sample_tree_builder;
};
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, ip_in_map) {
sample_tree_builder->AddSample(1, 1, 1, false);
sample_tree_builder->AddSample(1, 1, 2, false);
@@ -142,6 +143,7 @@ TEST_F(SampleTreeTest, ip_in_map) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, different_pid) {
sample_tree_builder->AddSample(1, 1, 1, false);
sample_tree_builder->AddSample(2, 2, 1, false);
@@ -152,6 +154,7 @@ TEST_F(SampleTreeTest, different_pid) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, different_tid) {
sample_tree_builder->AddSample(1, 1, 1, false);
sample_tree_builder->AddSample(1, 11, 1, false);
@@ -162,6 +165,7 @@ TEST_F(SampleTreeTest, different_tid) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, different_comm) {
sample_tree_builder->AddSample(1, 1, 1, false);
thread_tree.SetThreadName(1, 1, "p1t1_comm2");
@@ -173,6 +177,7 @@ TEST_F(SampleTreeTest, different_comm) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, different_map) {
sample_tree_builder->AddSample(1, 1, 1, false);
sample_tree_builder->AddSample(1, 1, 6, false);
@@ -183,6 +188,7 @@ TEST_F(SampleTreeTest, different_map) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, unmapped_sample) {
sample_tree_builder->AddSample(1, 1, 0, false);
sample_tree_builder->AddSample(1, 1, 31, false);
@@ -194,6 +200,7 @@ TEST_F(SampleTreeTest, unmapped_sample) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST_F(SampleTreeTest, map_kernel) {
sample_tree_builder->AddSample(1, 1, 10, true);
sample_tree_builder->AddSample(1, 1, 10, false);
@@ -204,6 +211,7 @@ TEST_F(SampleTreeTest, map_kernel) {
CheckSamples(expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST(sample_tree, overlapped_map) {
ThreadTree thread_tree;
TestSampleTreeBuilder sample_tree_builder(&thread_tree);
@@ -226,6 +234,7 @@ TEST(sample_tree, overlapped_map) {
CheckSamples(sample_tree_builder.GetSamples(), expected_samples);
}
+// @CddTest = 6.1/C-0-2
TEST(thread_tree, symbol_ULLONG_MAX) {
ThreadTree thread_tree;
thread_tree.ShowIpForUnknownSymbol();
diff --git a/simpleperf/scripts/report_html.js b/simpleperf/scripts/report_html.js
index 94e8ae5c..a3f899dd 100644
--- a/simpleperf/scripts/report_html.js
+++ b/simpleperf/scripts/report_html.js
@@ -379,10 +379,10 @@ class ChartView {
};
if (isClockEvent(this.eventInfo)) {
this.getSampleWeight = function (eventCount) {
- return (eventCount / 1000000.0).toFixed(3) + ' ms';
+ return (eventCount / 1000000.0).toFixed(3).toLocaleString() + ' ms';
};
} else {
- this.getSampleWeight = (eventCount) => '' + eventCount;
+ this.getSampleWeight = (eventCount) => eventCount.toLocaleString();
}
}
@@ -622,10 +622,10 @@ class SampleTableWeightSelectorView {
return (eventCount) => (eventCount * 100.0 / this.eventCount).toFixed(2) + '%';
}
if (this.curOption == 'event_count') {
- return (eventCount) => '' + eventCount;
+ return (eventCount) => eventCount.toLocaleString();
}
if (this.curOption == 'event_count_in_ms') {
- return (eventCount) => (eventCount / 1000000.0).toFixed(3);
+ return (eventCount) => (eventCount / 1000000.0).toFixed(3).toLocaleString();
}
}
@@ -706,7 +706,7 @@ class SampleTableView {
data: data,
responsive: true,
columnDefs: [
- { orderSequence: [ 'desc' ], targets: [0, 1, 2] },
+ { orderSequence: [ 'desc' ], className: 'textRight', targets: [0, 1, 2] },
],
});
dataTable.column(7).visible(false);
@@ -1082,13 +1082,13 @@ class SampleWeightSelectorView {
}
if (this.curOption == 'event_count') {
return function(eventCount, _) {
- return '' + eventCount;
+ return eventCount.toLocaleString();
};
}
if (this.curOption == 'event_count_in_ms') {
return function(eventCount, _) {
let timeInMs = eventCount / 1000000.0;
- return timeInMs.toFixed(3) + ' ms';
+ return timeInMs.toFixed(3).toLocaleString() + ' ms';
};
}
}
@@ -1590,12 +1590,9 @@ class SourceCodeView {
data.addColumn('string', 'Self');
data.addColumn('string', 'Code');
data.addRows(rows);
- for (let i = 0; i < rows.length; ++i) {
- data.setProperty(i, 0, 'className', 'colForLine');
- for (let j = 1; j <= 2; ++j) {
- data.setProperty(i, j, 'className', 'colForCount');
- }
- }
+ data.setColumnProperty(0, 'className', 'colForLine');
+ data.setColumnProperty(1, 'className', 'colForCount');
+ data.setColumnProperty(2, 'className', 'colForCount');
this.div.append(getHtml('pre', {text: sourceFile.path}));
let wrapperDiv = $('<div>');
wrapperDiv.appendTo(this.div);
@@ -1687,11 +1684,8 @@ class DisassemblyView {
data.addColumn('string', 'Self');
data.addColumn('string', 'Code');
data.addRows(rows);
- for (let i = 0; i < rows.length; ++i) {
- for (let j = 0; j < 2; ++j) {
- data.setProperty(i, j, 'className', 'colForCount');
- }
- }
+ data.setColumnProperty(0, 'className', 'colForCount');
+ data.setColumnProperty(1, 'className', 'colForCount');
let wrapperDiv = $('<div>');
wrapperDiv.appendTo(this.div);
let table = new google.visualization.Table(wrapperDiv.get(0));
diff --git a/simpleperf/scripts/report_html.py b/simpleperf/scripts/report_html.py
index ba143fd0..314a33fe 100755
--- a/simpleperf/scripts/report_html.py
+++ b/simpleperf/scripts/report_html.py
@@ -982,10 +982,11 @@ class ReportGenerator(object):
self.hw.open_tag('script').add(
"google.charts.load('current', {'packages': ['corechart', 'table']});").close_tag()
self.hw.open_tag('style', type='text/css').add("""
- .colForLine { width: 50px; }
- .colForCount { width: 100px; }
+ .colForLine { width: 50px; text-align: right; }
+ .colForCount { width: 100px; text-align: right; }
.tableCell { font-size: 17px; }
.boldTableCell { font-weight: bold; font-size: 17px; }
+ .textRight { text-align: right; }
""").close_tag()
self.hw.close_tag('head')
self.hw.open_tag('body')
@@ -1027,7 +1028,10 @@ def get_args() -> argparse.Namespace:
parser.add_argument('--disassemble-job-size', type=int, default=1024*1024,
help='address range for one disassemble job')
parser.add_argument('--binary_filter', nargs='+', help="""Annotate source code and disassembly
- only for selected binaries.""")
+ only for selected binaries, whose recorded paths contains [BINARY_FILTER] as
+ a substring. Example: to select binaries belonging to an app with package
+ name 'com.example.myapp', use `--binary_filter com.example.myapp`.
+ """)
parser.add_argument(
'-j', '--jobs', type=int, default=os.cpu_count(),
help='Use multithreading to speed up disassembly and source code annotation.')
diff --git a/simpleperf/scripts/simpleperf_utils.py b/simpleperf/scripts/simpleperf_utils.py
index 90f94cf7..e536b1b5 100644
--- a/simpleperf/scripts/simpleperf_utils.py
+++ b/simpleperf/scripts/simpleperf_utils.py
@@ -844,6 +844,7 @@ class Objdump(object):
real_path]
if arch == 'arm' and 'llvm-objdump' in objdump_path:
args += ['--print-imm-hex']
+ logging.debug('disassembling: %s', ' '.join(args))
try:
subproc = subprocess.Popen(args, stdout=subprocess.PIPE)
(stdoutdata, _) = subproc.communicate()
diff --git a/simpleperf/test_util.cpp b/simpleperf/test_util.cpp
index 7e99b5d5..42dee703 100644
--- a/simpleperf/test_util.cpp
+++ b/simpleperf/test_util.cpp
@@ -117,18 +117,23 @@ static bool HasNonZeroInstructionEventCount() {
return false;
}
+bool IsInEmulator() {
+ std::string fingerprint = android::base::GetProperty("ro.system.build.fingerprint", "");
+ return android::base::StartsWith(fingerprint, "google/sdk_gphone") ||
+ android::base::StartsWith(fingerprint, "google/sdk_gpc") ||
+ android::base::StartsWith(fingerprint, "generic/cf") ||
+ android::base::StartsWith(fingerprint, "generic/aosp_cf");
+}
+
bool HasHardwareCounter() {
static int has_hw_counter = -1;
if (has_hw_counter == -1) {
has_hw_counter = 1;
auto arch = GetTargetArch();
- std::string fingerprint = android::base::GetProperty("ro.system.build.fingerprint", "");
- bool is_emulator = android::base::StartsWith(fingerprint, "google/sdk_gphone") ||
- android::base::StartsWith(fingerprint, "google/sdk_gpc") ||
- android::base::StartsWith(fingerprint, "generic/cf");
+
bool in_native_abi = IsInNativeAbi() == std::optional(true);
- if (arch == ARCH_X86_64 || arch == ARCH_X86_32 || !in_native_abi || is_emulator) {
+ if (arch == ARCH_X86_64 || arch == ARCH_X86_32 || !in_native_abi || IsInEmulator()) {
// On x86 and x86_64, or when we are not in native abi, it's likely to run on an emulator or
// vm without hardware perf counters. It's hard to enumerate them all. So check the support
// at runtime.
@@ -171,7 +176,12 @@ bool HasPmuCounter() {
bool HasTracepointEvents() {
static int has_tracepoint_events = -1;
if (has_tracepoint_events == -1) {
- has_tracepoint_events = (GetTraceFsDir() != nullptr) ? 1 : 0;
+ has_tracepoint_events = 0;
+ if (const char* dir = GetTraceFsDir(); dir != nullptr) {
+ if (IsDir(std::string(dir) + "/events/sched/sched_switch")) {
+ has_tracepoint_events = 1;
+ }
+ }
}
return has_tracepoint_events == 1;
}
diff --git a/simpleperf/test_util.h b/simpleperf/test_util.h
index 16483103..4264c9a3 100644
--- a/simpleperf/test_util.h
+++ b/simpleperf/test_util.h
@@ -201,3 +201,5 @@ class AppHelper {
std::vector<std::string> installed_packages_;
std::unique_ptr<Workload> app_start_proc_;
};
+
+bool IsInEmulator();
diff --git a/simpleperf/thread_tree_test.cpp b/simpleperf/thread_tree_test.cpp
index f5b71ec0..7f1768e8 100644
--- a/simpleperf/thread_tree_test.cpp
+++ b/simpleperf/thread_tree_test.cpp
@@ -22,6 +22,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
class ThreadTreeTest : public ::testing::Test {
protected:
void AddMap(uint64_t start, uint64_t end, const std::string& name) {
@@ -76,6 +77,7 @@ class ThreadTreeTest : public ::testing::Test {
ThreadTree thread_tree_;
};
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadTreeTest, maps_smoke) {
AddMap(0, 5, "0");
AddMap(10, 15, "1");
@@ -100,6 +102,7 @@ TEST_F(ThreadTreeTest, maps_smoke) {
CheckMaps();
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadTreeTest, jit_maps_before_fork) {
// Maps for JIT symfiles can arrive before fork records.
thread_tree_.AddThreadMap(0, 0, 0, 1, 0, "0", map_flags::PROT_JIT_SYMFILE_MAP);
@@ -114,6 +117,7 @@ TEST_F(ThreadTreeTest, jit_maps_before_fork) {
ASSERT_EQ(map->flags, map_flags::PROT_JIT_SYMFILE_MAP);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadTreeTest, reused_tid) {
// Process 1 has thread 1 and 2.
thread_tree_.ForkThread(1, 2, 1, 1);
@@ -123,12 +127,14 @@ TEST_F(ThreadTreeTest, reused_tid) {
thread_tree_.ForkThread(2, 2, 1, 1);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadTreeTest, reused_tid_without_thread_exit) {
// Similar to the above test, but the thread exit record is missing.
thread_tree_.ForkThread(1, 2, 1, 1);
thread_tree_.ForkThread(2, 2, 1, 1);
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadTreeTest, add_symbols_for_process) {
std::string symbol_map(
"0x2000 0x20 two\n"
@@ -144,6 +150,7 @@ TEST_F(ThreadTreeTest, add_symbols_for_process) {
ASSERT_STREQ("three", FindSymbol(1, 1, 0x302f)->Name());
}
+// @CddTest = 6.1/C-0-2
TEST_F(ThreadTreeTest, invalid_fork) {
// tid == ptid
ASSERT_FALSE(thread_tree_.ForkThread(1, 2, 1, 2));
diff --git a/simpleperf/tracing_test.cpp b/simpleperf/tracing_test.cpp
index 4e4558b8..f4cec740 100644
--- a/simpleperf/tracing_test.cpp
+++ b/simpleperf/tracing_test.cpp
@@ -32,6 +32,7 @@ static void CheckAdjustFilter(const std::string& filter, bool use_quote,
ASSERT_EQ(android::base::Join(used_fields, ","), used_field_str);
}
+// @CddTest = 6.1/C-0-2
TEST(tracing, adjust_tracepoint_filter) {
std::string filter = "((sig >= 1 && sig < 20) || sig == 32) && comm != \"bash\"";
CheckAdjustFilter(filter, true, filter, "comm,sig");
@@ -67,6 +68,7 @@ std::ostream& operator<<(std::ostream& os, const TracingField& field) {
}
} // namespace simpleperf
+// @CddTest = 6.1/C-0-2
TEST(tracing, ParseTracingFormat) {
std::string data =
"name: sched_wakeup_new\n"
diff --git a/simpleperf/utils_test.cpp b/simpleperf/utils_test.cpp
index 15605338..747c020f 100644
--- a/simpleperf/utils_test.cpp
+++ b/simpleperf/utils_test.cpp
@@ -25,6 +25,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(utils, ConvertBytesToValue) {
char buf[8];
for (int i = 0; i < 8; ++i) {
@@ -36,6 +37,7 @@ TEST(utils, ConvertBytesToValue) {
ASSERT_EQ(0x0706050403020100ULL, ConvertBytesToValue(buf, 8));
}
+// @CddTest = 6.1/C-0-2
TEST(utils, ArchiveHelper) {
std::unique_ptr<ArchiveHelper> ahelper = ArchiveHelper::CreateInstance(GetTestData(APK_FILE));
ASSERT_TRUE(ahelper);
@@ -61,6 +63,7 @@ TEST(utils, ArchiveHelper) {
ASSERT_FALSE(ArchiveHelper::CreateInstance("/dev/zero"));
}
+// @CddTest = 6.1/C-0-2
TEST(utils, GetCpusFromString) {
ASSERT_EQ(GetCpusFromString("0-2"), std::make_optional<std::set<int>>({0, 1, 2}));
ASSERT_EQ(GetCpusFromString("0,2-3"), std::make_optional<std::set<int>>({0, 2, 3}));
@@ -72,11 +75,13 @@ TEST(utils, GetCpusFromString) {
ASSERT_EQ(GetCpusFromString("3,2-1"), std::nullopt);
}
+// @CddTest = 6.1/C-0-2
TEST(utils, GetTidsFromString) {
ASSERT_EQ(GetTidsFromString("0,12,9", false), std::make_optional(std::set<pid_t>({0, 9, 12})));
ASSERT_EQ(GetTidsFromString("-2", false), std::nullopt);
}
+// @CddTest = 6.1/C-0-2
TEST(utils, GetPidsFromStrings) {
ASSERT_EQ(GetPidsFromStrings({"0,12", "9"}, false, false),
std::make_optional(std::set<pid_t>({0, 9, 12})));
@@ -91,6 +96,7 @@ TEST(utils, GetPidsFromStrings) {
#endif // defined(__linux__)
}
+// @CddTest = 6.1/C-0-2
TEST(utils, LineReader) {
TemporaryFile tmpfile;
close(tmpfile.release());
@@ -106,6 +112,7 @@ TEST(utils, LineReader) {
ASSERT_TRUE(reader.ReadLine() == nullptr);
}
+// @CddTest = 6.1/C-0-2
TEST(utils, ReadableCount) {
ASSERT_EQ(ReadableCount(0), "0");
ASSERT_EQ(ReadableCount(204), "204");
diff --git a/simpleperf/workload_test.cpp b/simpleperf/workload_test.cpp
index f99ec753..e1ac147b 100644
--- a/simpleperf/workload_test.cpp
+++ b/simpleperf/workload_test.cpp
@@ -24,6 +24,7 @@
using namespace simpleperf;
+// @CddTest = 6.1/C-0-2
TEST(workload, success) {
IOEventLoop loop;
ASSERT_TRUE(loop.AddSignalEvent(SIGCHLD, [&]() { return loop.ExitLoop(); }));
@@ -34,6 +35,7 @@ TEST(workload, success) {
ASSERT_TRUE(loop.RunLoop());
}
+// @CddTest = 6.1/C-0-2
TEST(workload, execvp_failure) {
auto workload = Workload::CreateWorkload({"/dev/null"});
ASSERT_TRUE(workload != nullptr);
@@ -54,6 +56,7 @@ static void run_signaled_workload() {
exit(0);
}
+// @CddTest = 6.1/C-0-2
TEST(workload, signaled_warning) {
ASSERT_EXIT(run_signaled_workload(), testing::ExitedWithCode(0),
"child process was terminated by signal");
@@ -72,6 +75,7 @@ static void run_exit_nonzero_workload() {
exit(0);
}
+// @CddTest = 6.1/C-0-2
TEST(workload, exit_nonzero_warning) {
ASSERT_EXIT(run_exit_nonzero_workload(), testing::ExitedWithCode(0),
"child process exited with exit code");
diff --git a/tools/check_elf_alignment.sh b/tools/check_elf_alignment.sh
new file mode 100755
index 00000000..b74f34ae
--- /dev/null
+++ b/tools/check_elf_alignment.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+progname="${0##*/}"
+progname="${progname%.sh}"
+
+# usage: check_elf_alignment.sh [path to *.so files|path to *.apk]
+
+cleanup_trap() {
+ if [ -n "${tmp}" -a -d "${tmp}" ]; then
+ rm -rf ${tmp}
+ fi
+ exit $1
+}
+
+usage() {
+ echo "Host side script to check the ELF alignment of shared libraries."
+ echo "Shared libraries are reported ALIGNED when their ELF regions are"
+ echo "16 KB or 64 KB aligned. Otherwise they are reported as UNALIGNED."
+ echo
+ echo "Usage: ${progname} [input-path|input-APK]"
+}
+
+if [ ${#} -ne 1 ]; then
+ usage
+ exit
+fi
+
+case ${1} in
+ --help | -h | -\?)
+ usage
+ exit
+ ;;
+
+ *)
+ dir="${1}"
+ ;;
+esac
+
+if ! [ -f "${dir}" -o -d "${dir}" ]; then
+ echo "Invalid file: ${dir}" >&2
+ exit 1
+fi
+
+if [[ "${dir}" == *.apk ]]; then
+ trap 'cleanup_trap' EXIT
+
+ if { zipalign --help 2>&1 | grep -q "\-P <pagesize_kb>"; }; then
+ echo "=== APK zip-alignment ==="
+ zipalign -v -c -P 16 4 "${dir}" | egrep 'lib/arm64-v8a|lib/x86_64|Verification'
+ echo "========================="
+ else
+ echo "NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher."
+ echo " You can install the latest build-tools by running the below command"
+ echo " and updating your \$PATH:"
+ echo
+ echo " sdkmanager \"build-tools;35.0.0-rc3\""
+ fi
+
+ dir_filename=$(basename "${dir}")
+ tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX")
+ unzip "${dir}" lib/* -d "${tmp}" >/dev/null 2>&1
+ dir="${tmp}"
+fi
+
+RED="\e[31m"
+GREEN="\e[32m"
+ENDCOLOR="\e[0m"
+
+unaligned_libs=()
+
+echo
+echo "=== ELF alignment ==="
+
+matches="$(find "${dir}" -name "*.so" -type f)"
+IFS=$'\n'
+for match in $matches; do
+ res="$(objdump -p ${match} | grep LOAD | awk '{ print $NF }' | head -1)"
+ if [[ $res =~ "2**14" ]] || [[ $res =~ "2**16" ]]; then
+ echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)"
+ else
+ echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)"
+ unaligned_libs+=("${match}")
+ fi
+done
+
+if [ ${#unaligned_libs[@]} -gt 0 ]; then
+ echo -e "${RED}Found ${#unaligned_libs[@]} unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).${ENDCOLOR}"
+elif [ -n "${dir_filename}" ]; then
+ echo -e "ELF Verification Successful"
+fi
+echo "====================="