diff --git a/src/config.py b/src/config.py index 0852be1..6ffb4c6 100644 --- a/src/config.py +++ b/src/config.py @@ -19,6 +19,7 @@ from .base import ANDROID_SDK_VERSION_T, Command, ValidationError from .config_builder import create_common_config_parser, PREDEFINED_PERFETTO_CONFIGS +from .device import OsCodes from .handle_input import HandleInput from .profiler import verify_trigger_args from .utils import run_subprocess, TEXTPROTO_FILE_EXTENSIONS @@ -28,7 +29,7 @@ def add_config_parser(subparsers): common_config_args = argparse.ArgumentParser(add_help=False) common_config_args.add_argument( 'config_name', - choices=['lightweight', 'default', 'memory', 'qnx'], + choices=['lightweight', 'default', 'memory', 'qnx', 'android-qnx'], help='Name of the predefined config to copy') common_profiler_args = create_common_config_parser() @@ -132,7 +133,7 @@ def create_config_command(args): def execute_show_or_pull_command(command, device): android_sdk_version = ANDROID_SDK_VERSION_T - if device is not None: + if device is not None and device.os() == OsCodes.OS_ANDROID: device.root_device() android_sdk_version = device.get_android_sdk_version() diff --git a/src/config_builder.py b/src/config_builder.py index 1ebeac9..0d433a2 100644 --- a/src/config_builder.py +++ b/src/config_builder.py @@ -145,7 +145,7 @@ def create_trigger_config(trigger_names, trigger_mode, trigger_timeout_ms, def build_predefined_config(command, - android_sdk_version, + android_sdk_version=None, predefined_ftrace_events=None, sys_stats_events=None, predefined_atrace_events=None, @@ -260,7 +260,7 @@ def build_predefined_config(command, return None, error cpufreq_period_string = "cpufreq_period_ms: 500" - if android_sdk_version < ANDROID_SDK_VERSION_T: + if android_sdk_version is None or android_sdk_version < ANDROID_SDK_VERSION_T: cpufreq_period_string = "" trigger_config = "" @@ -571,7 +571,6 @@ def build_qnx_config(command, android_sdk_version): # QNX config does not use Android specific data sources return build_predefined_config( command, - android_sdk_version, predefined_ftrace_events=[], sys_stats_events="", predefined_atrace_events="", @@ -586,11 +585,29 @@ def build_qnx_config(command, android_sdk_version): extra_configs=extra_configs) +def build_android_qnx_config(command, android_sdk_version): + # Android-QNX config merges Android default with QNX config + extra_configs = f''' + data_sources {{ + config {{ + name: "qnx.kernel" + target_buffer: 2 + }} + }} + + trace_all_machines: true + ''' + + return build_predefined_config( + command, android_sdk_version, extra_configs=extra_configs) + + PREDEFINED_PERFETTO_CONFIGS = { 'default': build_default_config, 'lightweight': build_lightweight_config, 'memory': build_memory_config, - 'qnx': build_qnx_config + 'qnx': build_qnx_config, + 'android-qnx': build_android_qnx_config } diff --git a/tests/config_command_executor_unit_test.py b/tests/config_command_executor_unit_test.py index dcdb99a..fc7b1e7 100644 --- a/tests/config_command_executor_unit_test.py +++ b/tests/config_command_executor_unit_test.py @@ -21,7 +21,7 @@ import io from pathlib import Path from unittest import mock -from src.device import AndroidDevice, get_device +from src.device import AndroidDevice, OsCodes, get_device from src.base import ValidationError from src.config import PREDEFINED_PERFETTO_CONFIGS from tests.test_utils import generate_adb_devices_result, generate_mock_completed_process, run_cli @@ -354,6 +354,175 @@ ''' +TEST_ANDROID_QNX_CONFIG = f'''\ +buffers: {{ + size_kb: 4096 + fill_policy: RING_BUFFER +}} +buffers {{ + size_kb: 4096 + fill_policy: RING_BUFFER +}} +buffers: {{ + size_kb: 260096 + fill_policy: RING_BUFFER +}} +data_sources: {{ + config {{ + name: "linux.process_stats" + process_stats_config {{ + scan_all_processes_on_start: true + }} + }} +}} +data_sources: {{ + config {{ + name: "android.log" + android_log_config {{ + min_prio: PRIO_VERBOSE + }} + }} +}} +data_sources {{ + config {{ + name: "android.packages_list" + }} +}} +data_sources: {{ + config {{ + name: "linux.sys_stats" + target_buffer: 1 + sys_stats_config {{ + stat_period_ms: 500 + stat_counters: STAT_CPU_TIMES + stat_counters: STAT_FORK_COUNT + meminfo_period_ms: 1000 + meminfo_counters: MEMINFO_ACTIVE_ANON + meminfo_counters: MEMINFO_ACTIVE_FILE + meminfo_counters: MEMINFO_INACTIVE_ANON + meminfo_counters: MEMINFO_INACTIVE_FILE + meminfo_counters: MEMINFO_KERNEL_STACK + meminfo_counters: MEMINFO_MLOCKED + meminfo_counters: MEMINFO_SHMEM + meminfo_counters: MEMINFO_SLAB + meminfo_counters: MEMINFO_SLAB_UNRECLAIMABLE + meminfo_counters: MEMINFO_VMALLOC_USED + meminfo_counters: MEMINFO_MEM_FREE + meminfo_counters: MEMINFO_SWAP_FREE + vmstat_period_ms: 1000 + vmstat_counters: VMSTAT_PGFAULT + vmstat_counters: VMSTAT_PGMAJFAULT + vmstat_counters: VMSTAT_PGFREE + vmstat_counters: VMSTAT_PGPGIN + vmstat_counters: VMSTAT_PGPGOUT + vmstat_counters: VMSTAT_PSWPIN + vmstat_counters: VMSTAT_PSWPOUT + vmstat_counters: VMSTAT_PGSCAN_DIRECT + vmstat_counters: VMSTAT_PGSTEAL_DIRECT + vmstat_counters: VMSTAT_PGSCAN_KSWAPD + vmstat_counters: VMSTAT_PGSTEAL_KSWAPD + vmstat_counters: VMSTAT_WORKINGSET_REFAULT + cpufreq_period_ms: 500 + }} + }} +}} +data_sources: {{ + config {{ + name: "android.surfaceflinger.frametimeline" + target_buffer: 2 + }} +}} +data_sources: {{ + config {{ + name: "linux.ftrace" + target_buffer: 2 + ftrace_config {{ + ftrace_events: "dmabuf_heap/dma_heap_stat" + ftrace_events: "ftrace/print" + ftrace_events: "gpu_mem/gpu_mem_total" + ftrace_events: "ion/ion_stat" + ftrace_events: "kmem/ion_heap_grow" + ftrace_events: "kmem/ion_heap_shrink" + ftrace_events: "kmem/rss_stat" + ftrace_events: "lowmemorykiller/lowmemory_kill" + ftrace_events: "mm_event/mm_event_record" + ftrace_events: "oom/mark_victim" + ftrace_events: "oom/oom_score_adj_update" + ftrace_events: "power/cpu_frequency" + ftrace_events: "power/cpu_idle" + ftrace_events: "power/gpu_frequency" + ftrace_events: "power/suspend_resume" + ftrace_events: "power/wakeup_source_activate" + ftrace_events: "power/wakeup_source_deactivate" + ftrace_events: "sched/sched_blocked_reason" + ftrace_events: "sched/sched_process_exit" + ftrace_events: "sched/sched_process_free" + ftrace_events: "sched/sched_switch" + ftrace_events: "sched/sched_wakeup" + ftrace_events: "sched/sched_wakeup_new" + ftrace_events: "sched/sched_waking" + ftrace_events: "task/task_newtask" + ftrace_events: "task/task_rename" + ftrace_events: "vmscan/*" + ftrace_events: "workqueue/*" + atrace_categories: "aidl" + atrace_categories: "am" + atrace_categories: "dalvik" + atrace_categories: "binder_lock" + atrace_categories: "binder_driver" + atrace_categories: "bionic" + atrace_categories: "camera" + atrace_categories: "disk" + atrace_categories: "freq" + atrace_categories: "idle" + atrace_categories: "gfx" + atrace_categories: "hal" + atrace_categories: "input" + atrace_categories: "pm" + atrace_categories: "power" + atrace_categories: "res" + atrace_categories: "rro" + atrace_categories: "sched" + atrace_categories: "sm" + atrace_categories: "ss" + atrace_categories: "thermal" + atrace_categories: "video" + atrace_categories: "view" + atrace_categories: "wm" + atrace_apps: "*" + buffer_size_kb: 16384 + drain_period_ms: 150 + symbolize_ksyms: true + }} + }} +}} +data_sources {{ + config {{ + name: "qnx.kernel" + target_buffer: 2 + }} +}} + +trace_all_machines: true + +data_sources {{ + config {{ + name: "perfetto.metatrace" + target_buffer: 2 + }} + producer_name_filter: "perfetto.traced_probes" +}} + +write_into_file: true +file_write_period_ms: 5000 +max_file_size_bytes: 100000000000 +flush_period_ms: 5000 +incremental_state_config {{ + clear_period_ms: 5000 +}} + +''' + class ConfigCommandExecutorUnitTest(unittest.TestCase): @@ -362,6 +531,7 @@ def setUp(self): self.mock_get_device_patcher = mock.patch("src.torq.get_device") self.mock_get_device = self.mock_get_device_patcher.start() self.mock_device = mock.create_autospec(AndroidDevice, instance=True) + self.mock_device.os.return_value = OsCodes.OS_ANDROID self.mock_get_device.return_value = (self.mock_device, None) self.mock_device.get_android_sdk_version.return_value = ( ANDROID_SDK_VERSION_T) @@ -388,6 +558,12 @@ def test_config_show(self): self.assertEqual(self.stderr_output.getvalue(), "") self.assertEqual(self.stdout_output.getvalue(), TEST_DEFAULT_CONFIG) + def test_config_show_android_qnx(self): + run_cli("torq config show android-qnx") + + self.assertEqual(self.stderr_output.getvalue(), "") + self.assertEqual(self.stdout_output.getvalue(), TEST_ANDROID_QNX_CONFIG) + @mock.patch.object(subprocess, "run", autospec=True) def test_config_show_no_device_connected(self, mock_subprocess_run): self.mock_get_device.return_value = (None, None) @@ -397,6 +573,16 @@ def test_config_show_no_device_connected(self, mock_subprocess_run): self.assertEqual(self.stderr_output.getvalue(), "") self.assertEqual(self.stdout_output.getvalue(), TEST_DEFAULT_CONFIG) + @mock.patch.object(subprocess, "run", autospec=True) + def test_config_show_no_device_connected_android_qnx(self, + mock_subprocess_run): + self.mock_get_device.return_value = (None, None) + + run_cli("torq config show android-qnx") + + self.assertEqual(self.stderr_output.getvalue(), "") + self.assertEqual(self.stdout_output.getvalue(), TEST_ANDROID_QNX_CONFIG) + @mock.patch.object(subprocess, "run", autospec=True) def test_config_show_old_android_version(self, mock_subprocess_run): mock_subprocess_run.return_value = ( diff --git a/tests/torq_unit_test.py b/tests/torq_unit_test.py index 1e2d014..0e6f157 100644 --- a/tests/torq_unit_test.py +++ b/tests/torq_unit_test.py @@ -343,17 +343,19 @@ def test_verify_args_invalid_perfetto_config_path(self, mock_is_file): self.assertEqual(error.message, ("Command is invalid because" " --perfetto-config is not a" " valid file path: unexisting-file")) - self.assertEqual(error.suggestion, ("Predefined perfetto configs can be" - " used:\n" - "\t torq --perfetto-config default\n" - "\t torq --perfetto-config" - " lightweight\n" - "\t torq --perfetto-config memory\n" - "\t torq --perfetto-config qnx\n" - "\t A filepath with a config can also" - " be used:\n" - "\t torq --perfetto-config" - " ")) + self.assertEqual(error.suggestion, + ("Predefined perfetto configs can be" + " used:\n" + "\t torq --perfetto-config default\n" + "\t torq --perfetto-config" + " lightweight\n" + "\t torq --perfetto-config memory\n" + "\t torq --perfetto-config qnx\n" + "\t torq --perfetto-config android-qnx\n" + "\t A filepath with a config can also" + " be used:\n" + "\t torq --perfetto-config" + " ")) args = parse_cli("torq --perfetto-config mock-directory") @@ -362,17 +364,19 @@ def test_verify_args_invalid_perfetto_config_path(self, mock_is_file): self.assertEqual(error.message, ("Command is invalid because" " --perfetto-config is not a" " valid file path: mock-directory")) - self.assertEqual(error.suggestion, ("Predefined perfetto configs can be" - " used:\n" - "\t torq --perfetto-config default\n" - "\t torq --perfetto-config" - " lightweight\n" - "\t torq --perfetto-config memory\n" - "\t torq --perfetto-config qnx\n" - "\t A filepath with a config can also" - " be used:\n" - "\t torq --perfetto-config" - " ")) + self.assertEqual(error.suggestion, + ("Predefined perfetto configs can be" + " used:\n" + "\t torq --perfetto-config default\n" + "\t torq --perfetto-config" + " lightweight\n" + "\t torq --perfetto-config memory\n" + "\t torq --perfetto-config qnx\n" + "\t torq --perfetto-config android-qnx\n" + "\t A filepath with a config can also" + " be used:\n" + "\t torq --perfetto-config" + " ")) def test_verify_args_from_user_and_event_valid_dependency(self): args = parse_cli(("torq -e user-switch --from-user 0"