Merge "Created a controller to start systrace on vts test"
diff --git a/Android.mk b/Android.mk
index bd05750..216361d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,6 +26,7 @@
VTS_PYTHON_ZIP := $(HOST_OUT)/vts_runner_python/vts_runner_python.zip
VTS_OUT_ROOT := $(HOST_OUT)/vts
VTS_CAMERAITS_ZIP := $(VTS_OUT_ROOT)/CameraITS.zip
+VTS_SYSTRACE_ZIP := $(VTS_OUT_ROOT)/Systrace.zip
VTS_TESTCASES_OUT := $(VTS_OUT_ROOT)/android-vts/testcases
.PHONY: $(VTS_PYTHON_ZIP) $(VTS_CAMERAITS_ZIP)
@@ -142,13 +143,20 @@
$(hide) rm -rf $(VTS_TESTCASES_OUT)/CameraITS/*
$(hide) unzip $@ -d $(VTS_TESTCASES_OUT)/CameraITS
+$(VTS_SYSTRACE_ZIP): $(SOONG_ZIP)
+ @echo "copying systrace tool from external/chromium-trace"
+ $(hide) find external/chromium-trace -path external/chromium-trace/.git -prune -or -print | sort > $@.list
+ $(hide) $(SOONG_ZIP) -d -o $@ -C . -l $@.list
+ @rm -f $@.list
+ $(hide) unzip $@ -d $(VTS_OUT_ROOT)/android-vts/tools
+
.PHONY: vts
my_deps_copy_pairs :=
$(foreach d,$(ADDITIONAL_VTS_JARS),\
$(eval my_deps_copy_pairs += $(d):$(VTS_OUT_ROOT)/android-vts/tools/$(notdir $(d))))
-vts: $(VTS_PYTHON_ZIP) $(VTS_CAMERAITS_ZIP) $(call copy-many-files,$(my_deps_copy_pairs))
+vts: $(VTS_PYTHON_ZIP) $(VTS_CAMERAITS_ZIP) $(VTS_SYSTRACE_ZIP) $(call copy-many-files,$(my_deps_copy_pairs))
endif # vts
endif # linux
diff --git a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
index ef4ae6a..62ac365 100644
--- a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
+++ b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
@@ -93,6 +93,7 @@
static final String ENABLE_PROFILING = "enable_profiling";
static final String ENABLE_COVERAGE = "enable_coverage";
static final String HWBINDER_SERVICE = "hwbinder_service";
+ static final String SYSTRACE_PROCESS_NAME = "systrace_process_name";
static final String TEMPLATE_BINARY_TEST_PATH = "vts/testcases/template/binary_test/binary_test";
static final String TEMPLATE_GTEST_BINARY_TEST_PATH = "vts/testcases/template/gtest_binary_test/gtest_binary_test";
static final String TEMPLATE_LLVMFUZZER_TEST_PATH = "vts/testcases/template/llvmfuzzer_test/llvmfuzzer_test";
@@ -218,6 +219,9 @@
+ "running an extended binary test without a python test file. Available options: gtest")
private String mBinaryTestType = "";
+ @Option(name = "systrace-process-name", description = "Process name for systrace.")
+ private String mSystraceProcessName = null;
+
@Option(name = "collect-tests-only",
description = "Only invoke the test binary to collect list of applicable test cases. "
+ "All test run callbacks will be triggered, but test execution will "
@@ -576,6 +580,11 @@
jsonObject.put(BINARY_TEST_DISABLE_FRAMEWORK, mBinaryTestDisableFramework);
CLog.i("Added %s to the Json object", BINARY_TEST_DISABLE_FRAMEWORK);
}
+
+ if (mSystraceProcessName != null) {
+ jsonObject.put(SYSTRACE_PROCESS_NAME, mSystraceProcessName);
+ CLog.i("Added %s to the Json object", SYSTRACE_PROCESS_NAME);
+ }
}
/**
diff --git a/proto/VtsReportMessage.proto b/proto/VtsReportMessage.proto
index 4f230ee..f9dca10 100644
--- a/proto/VtsReportMessage.proto
+++ b/proto/VtsReportMessage.proto
@@ -134,6 +134,9 @@
// profiling reports
repeated ProfilingReportMessage profiling = 41;
+
+ // systrace report message per file
+ repeated SystraceReportMessage systrace = 42;
}
@@ -161,6 +164,14 @@
repeated bytes options = 41;
}
+// To specify a systrace report.
+message SystraceReportMessage {
+ // the target process name used by systrace
+ optional bytes process_name = 1;
+
+ // the produced html report
+ repeated bytes html = 11;
+}
// To specify a coverage report.
message CoverageReportMessage {
@@ -226,6 +237,9 @@
// profiling reports
repeated ProfilingReportMessage profiling = 21;
+ // systrace report per file
+ repeated SystraceReportMessage systrace = 22;
+
// execution start and end time stamp.
optional int64 start_timestamp = 101;
optional int64 end_timestamp = 102;
diff --git a/proto/VtsReportMessage_pb2.py b/proto/VtsReportMessage_pb2.py
index af72c02..758d336 100644
--- a/proto/VtsReportMessage_pb2.py
+++ b/proto/VtsReportMessage_pb2.py
@@ -14,7 +14,7 @@
DESCRIPTOR = _descriptor.FileDescriptor(
name='VtsReportMessage.proto',
package='android.vts',
- serialized_pb='\n\x16VtsReportMessage.proto\x12\x0b\x61ndroid.vts\"\xe0\x01\n\x18\x41ndroidDeviceInfoMessage\x12\x14\n\x0cproduct_type\x18\x01 \x01(\x0c\x12\x17\n\x0fproduct_variant\x18\x02 \x01(\x0c\x12\x14\n\x0c\x62uild_flavor\x18\x0b \x01(\x0c\x12\x10\n\x08\x62uild_id\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\x15 \x01(\x0c\x12\x13\n\x0b\x62uild_alias\x18\x16 \x01(\x0c\x12\x11\n\tapi_level\x18\x1f \x01(\x0c\x12\x10\n\x08\x61\x62i_name\x18\x33 \x01(\x0c\x12\x13\n\x0b\x61\x62i_bitness\x18\x34 \x01(\x0c\x12\x0e\n\x06serial\x18\x65 \x01(\x0c\"g\n\x10\x41ndroidBuildInfo\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x0b \x01(\x0c\x12\x12\n\nbuild_type\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\r \x01(\x0c\x12\x15\n\rbuild_summary\x18\x15 \x01(\x0c\"\x1f\n\x0bVtsHostInfo\x12\x10\n\x08hostname\x18\x01 \x01(\x0c\"\xf5\x01\n\x15TestCaseReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x30\n\x0btest_result\x18\x0b \x01(\x0e\x32\x1b.android.vts.TestCaseResult\x12\x17\n\x0fstart_timestamp\x18\x15 \x01(\x03\x12\x15\n\rend_timestamp\x18\x16 \x01(\x03\x12\x34\n\x08\x63overage\x18\x1f \x03(\x0b\x32\".android.vts.CoverageReportMessage\x12\x36\n\tprofiling\x18) \x03(\x0b\x32#.android.vts.ProfilingReportMessage\"\xa0\x02\n\x16ProfilingReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12+\n\x04type\x18\x02 \x01(\x0e\x32\x1d.android.vts.VtsProfilingType\x12@\n\x0fregression_mode\x18\x03 \x01(\x0e\x32\'.android.vts.VtsProfilingRegressionMode\x12\x17\n\x0fstart_timestamp\x18\x0b \x01(\x03\x12\x15\n\rend_timestamp\x18\x0c \x01(\x03\x12\r\n\x05label\x18\x15 \x03(\x0c\x12\r\n\x05value\x18\x16 \x03(\x03\x12\x14\n\x0cx_axis_label\x18\x1f \x01(\x0c\x12\x14\n\x0cy_axis_label\x18 \x01(\x0c\x12\x0f\n\x07options\x18) \x03(\x0c\"\xe5\x01\n\x15\x43overageReportMessage\x12\x11\n\tfile_path\x18\x0b \x01(\x0c\x12\x14\n\x0cproject_name\x18\x0c \x01(\x0c\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x1c\n\x14line_coverage_vector\x18\x17 \x03(\x05\x12\x18\n\x10total_line_count\x18\x65 \x01(\x05\x12\x1a\n\x12\x63overed_line_count\x18\x66 \x01(\x05\x12\x14\n\x08\x64ir_path\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x15\n\tfile_name\x18\x02 \x01(\x0c\x42\x02\x18\x01\x12\x10\n\x04html\x18\x03 \x01(\x0c\x42\x02\x18\x01\"\xed\x03\n\x11TestReportMessage\x12\x12\n\ntest_suite\x18\x01 \x01(\x0c\x12\x0c\n\x04test\x18\x02 \x01(\x0c\x12+\n\ttest_type\x18\x03 \x01(\x0e\x32\x18.android.vts.VtsTestType\x12:\n\x0b\x64\x65vice_info\x18\x04 \x03(\x0b\x32%.android.vts.AndroidDeviceInfoMessage\x12\x31\n\nbuild_info\x18\x05 \x01(\x0b\x32\x1d.android.vts.AndroidBuildInfo\x12\x18\n\x10subscriber_email\x18\x06 \x03(\x0c\x12+\n\thost_info\x18\x07 \x01(\x0b\x32\x18.android.vts.VtsHostInfo\x12\x35\n\ttest_case\x18\x0b \x03(\x0b\x32\".android.vts.TestCaseReportMessage\x12\x36\n\tprofiling\x18\x15 \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x17\n\x0fstart_timestamp\x18\x65 \x01(\x03\x12\x15\n\rend_timestamp\x18\x66 \x01(\x03\x12\x34\n\x08\x63overage\x18g \x03(\x0b\x32\".android.vts.CoverageReportMessage*\xb3\x01\n\x0eTestCaseResult\x12\x12\n\x0eUNKNOWN_RESULT\x10\x00\x12\x19\n\x15TEST_CASE_RESULT_PASS\x10\x01\x12\x19\n\x15TEST_CASE_RESULT_FAIL\x10\x02\x12\x19\n\x15TEST_CASE_RESULT_SKIP\x10\x03\x12\x1e\n\x1aTEST_CASE_RESULT_EXCEPTION\x10\x04\x12\x1c\n\x18TEST_CASE_RESULT_TIMEOUT\x10\x05*\x9c\x01\n\x0bVtsTestType\x12\x18\n\x14UNKNOWN_VTS_TESTTYPE\x10\x00\x12\x1e\n\x1aVTS_HOST_DRIVEN_STRUCTURAL\x10\x01\x12\x1b\n\x17VTS_HOST_DRIVEN_FUZZING\x10\x02\x12\x19\n\x15VTS_TARGET_SIDE_GTEST\x10\x03\x12\x1b\n\x17VTS_TARGET_SIDE_FUZZING\x10\x04*\xa3\x01\n\x1aVtsProfilingRegressionMode\x12\x1b\n\x17UNKNOWN_REGRESSION_MODE\x10\x00\x12 \n\x1cVTS_REGRESSION_MODE_DISABLED\x10\x01\x12\"\n\x1eVTS_REGRESSION_MODE_INCREASING\x10\x02\x12\"\n\x1eVTS_REGRESSION_MODE_DECREASING\x10\x03*{\n\x10VtsProfilingType\x12\x1e\n\x1aUNKNOWN_VTS_PROFILING_TYPE\x10\x00\x12 \n\x1cVTS_PROFILING_TYPE_TIMESTAMP\x10\x01\x12%\n!VTS_PROFILING_TYPE_LABELED_VECTOR\x10\x02\x42)\n\x15\x63om.android.vts.protoB\x10VtsReportMessage')
+ serialized_pb='\n\x16VtsReportMessage.proto\x12\x0b\x61ndroid.vts\"\xe0\x01\n\x18\x41ndroidDeviceInfoMessage\x12\x14\n\x0cproduct_type\x18\x01 \x01(\x0c\x12\x17\n\x0fproduct_variant\x18\x02 \x01(\x0c\x12\x14\n\x0c\x62uild_flavor\x18\x0b \x01(\x0c\x12\x10\n\x08\x62uild_id\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\x15 \x01(\x0c\x12\x13\n\x0b\x62uild_alias\x18\x16 \x01(\x0c\x12\x11\n\tapi_level\x18\x1f \x01(\x0c\x12\x10\n\x08\x61\x62i_name\x18\x33 \x01(\x0c\x12\x13\n\x0b\x61\x62i_bitness\x18\x34 \x01(\x0c\x12\x0e\n\x06serial\x18\x65 \x01(\x0c\"g\n\x10\x41ndroidBuildInfo\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x0b \x01(\x0c\x12\x12\n\nbuild_type\x18\x0c \x01(\x0c\x12\x0e\n\x06\x62ranch\x18\r \x01(\x0c\x12\x15\n\rbuild_summary\x18\x15 \x01(\x0c\"\x1f\n\x0bVtsHostInfo\x12\x10\n\x08hostname\x18\x01 \x01(\x0c\"\xab\x02\n\x15TestCaseReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x30\n\x0btest_result\x18\x0b \x01(\x0e\x32\x1b.android.vts.TestCaseResult\x12\x17\n\x0fstart_timestamp\x18\x15 \x01(\x03\x12\x15\n\rend_timestamp\x18\x16 \x01(\x03\x12\x34\n\x08\x63overage\x18\x1f \x03(\x0b\x32\".android.vts.CoverageReportMessage\x12\x36\n\tprofiling\x18) \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x34\n\x08systrace\x18* \x03(\x0b\x32\".android.vts.SystraceReportMessage\"\xa0\x02\n\x16ProfilingReportMessage\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12+\n\x04type\x18\x02 \x01(\x0e\x32\x1d.android.vts.VtsProfilingType\x12@\n\x0fregression_mode\x18\x03 \x01(\x0e\x32\'.android.vts.VtsProfilingRegressionMode\x12\x17\n\x0fstart_timestamp\x18\x0b \x01(\x03\x12\x15\n\rend_timestamp\x18\x0c \x01(\x03\x12\r\n\x05label\x18\x15 \x03(\x0c\x12\r\n\x05value\x18\x16 \x03(\x03\x12\x14\n\x0cx_axis_label\x18\x1f \x01(\x0c\x12\x14\n\x0cy_axis_label\x18 \x01(\x0c\x12\x0f\n\x07options\x18) \x03(\x0c\";\n\x15SystraceReportMessage\x12\x14\n\x0cprocess_name\x18\x01 \x01(\x0c\x12\x0c\n\x04html\x18\x0b \x03(\x0c\"\xe5\x01\n\x15\x43overageReportMessage\x12\x11\n\tfile_path\x18\x0b \x01(\x0c\x12\x14\n\x0cproject_name\x18\x0c \x01(\x0c\x12\x10\n\x08revision\x18\r \x01(\x0c\x12\x1c\n\x14line_coverage_vector\x18\x17 \x03(\x05\x12\x18\n\x10total_line_count\x18\x65 \x01(\x05\x12\x1a\n\x12\x63overed_line_count\x18\x66 \x01(\x05\x12\x14\n\x08\x64ir_path\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x15\n\tfile_name\x18\x02 \x01(\x0c\x42\x02\x18\x01\x12\x10\n\x04html\x18\x03 \x01(\x0c\x42\x02\x18\x01\"\xa3\x04\n\x11TestReportMessage\x12\x12\n\ntest_suite\x18\x01 \x01(\x0c\x12\x0c\n\x04test\x18\x02 \x01(\x0c\x12+\n\ttest_type\x18\x03 \x01(\x0e\x32\x18.android.vts.VtsTestType\x12:\n\x0b\x64\x65vice_info\x18\x04 \x03(\x0b\x32%.android.vts.AndroidDeviceInfoMessage\x12\x31\n\nbuild_info\x18\x05 \x01(\x0b\x32\x1d.android.vts.AndroidBuildInfo\x12\x18\n\x10subscriber_email\x18\x06 \x03(\x0c\x12+\n\thost_info\x18\x07 \x01(\x0b\x32\x18.android.vts.VtsHostInfo\x12\x35\n\ttest_case\x18\x0b \x03(\x0b\x32\".android.vts.TestCaseReportMessage\x12\x36\n\tprofiling\x18\x15 \x03(\x0b\x32#.android.vts.ProfilingReportMessage\x12\x34\n\x08systrace\x18\x16 \x03(\x0b\x32\".android.vts.SystraceReportMessage\x12\x17\n\x0fstart_timestamp\x18\x65 \x01(\x03\x12\x15\n\rend_timestamp\x18\x66 \x01(\x03\x12\x34\n\x08\x63overage\x18g \x03(\x0b\x32\".android.vts.CoverageReportMessage*\xb3\x01\n\x0eTestCaseResult\x12\x12\n\x0eUNKNOWN_RESULT\x10\x00\x12\x19\n\x15TEST_CASE_RESULT_PASS\x10\x01\x12\x19\n\x15TEST_CASE_RESULT_FAIL\x10\x02\x12\x19\n\x15TEST_CASE_RESULT_SKIP\x10\x03\x12\x1e\n\x1aTEST_CASE_RESULT_EXCEPTION\x10\x04\x12\x1c\n\x18TEST_CASE_RESULT_TIMEOUT\x10\x05*\x9c\x01\n\x0bVtsTestType\x12\x18\n\x14UNKNOWN_VTS_TESTTYPE\x10\x00\x12\x1e\n\x1aVTS_HOST_DRIVEN_STRUCTURAL\x10\x01\x12\x1b\n\x17VTS_HOST_DRIVEN_FUZZING\x10\x02\x12\x19\n\x15VTS_TARGET_SIDE_GTEST\x10\x03\x12\x1b\n\x17VTS_TARGET_SIDE_FUZZING\x10\x04*\xa3\x01\n\x1aVtsProfilingRegressionMode\x12\x1b\n\x17UNKNOWN_REGRESSION_MODE\x10\x00\x12 \n\x1cVTS_REGRESSION_MODE_DISABLED\x10\x01\x12\"\n\x1eVTS_REGRESSION_MODE_INCREASING\x10\x02\x12\"\n\x1eVTS_REGRESSION_MODE_DECREASING\x10\x03*{\n\x10VtsProfilingType\x12\x1e\n\x1aUNKNOWN_VTS_PROFILING_TYPE\x10\x00\x12 \n\x1cVTS_PROFILING_TYPE_TIMESTAMP\x10\x01\x12%\n!VTS_PROFILING_TYPE_LABELED_VECTOR\x10\x02\x42)\n\x15\x63om.android.vts.protoB\x10VtsReportMessage')
_TESTCASERESULT = _descriptor.EnumDescriptor(
name='TestCaseResult',
@@ -49,8 +49,8 @@
],
containing_type=None,
options=None,
- serialized_start=1672,
- serialized_end=1851,
+ serialized_start=1841,
+ serialized_end=2020,
)
TestCaseResult = enum_type_wrapper.EnumTypeWrapper(_TESTCASERESULT)
@@ -83,8 +83,8 @@
],
containing_type=None,
options=None,
- serialized_start=1854,
- serialized_end=2010,
+ serialized_start=2023,
+ serialized_end=2179,
)
VtsTestType = enum_type_wrapper.EnumTypeWrapper(_VTSTESTTYPE)
@@ -113,8 +113,8 @@
],
containing_type=None,
options=None,
- serialized_start=2013,
- serialized_end=2176,
+ serialized_start=2182,
+ serialized_end=2345,
)
VtsProfilingRegressionMode = enum_type_wrapper.EnumTypeWrapper(_VTSPROFILINGREGRESSIONMODE)
@@ -139,8 +139,8 @@
],
containing_type=None,
options=None,
- serialized_start=2178,
- serialized_end=2301,
+ serialized_start=2347,
+ serialized_end=2470,
)
VtsProfilingType = enum_type_wrapper.EnumTypeWrapper(_VTSPROFILINGTYPE)
@@ -389,6 +389,13 @@
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
+ _descriptor.FieldDescriptor(
+ name='systrace', full_name='android.vts.TestCaseReportMessage.systrace', index=6,
+ number=42, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
],
extensions=[
],
@@ -399,7 +406,7 @@
is_extendable=False,
extension_ranges=[],
serialized_start=405,
- serialized_end=650,
+ serialized_end=704,
)
@@ -489,8 +496,43 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=653,
- serialized_end=941,
+ serialized_start=707,
+ serialized_end=995,
+)
+
+
+_SYSTRACEREPORTMESSAGE = _descriptor.Descriptor(
+ name='SystraceReportMessage',
+ full_name='android.vts.SystraceReportMessage',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='process_name', full_name='android.vts.SystraceReportMessage.process_name', index=0,
+ number=1, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value="",
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='html', full_name='android.vts.SystraceReportMessage.html', index=1,
+ number=11, type=12, cpp_type=9, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ extension_ranges=[],
+ serialized_start=997,
+ serialized_end=1056,
)
@@ -573,8 +615,8 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=944,
- serialized_end=1173,
+ serialized_start=1059,
+ serialized_end=1288,
)
@@ -649,21 +691,28 @@
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
- name='start_timestamp', full_name='android.vts.TestReportMessage.start_timestamp', index=9,
+ name='systrace', full_name='android.vts.TestReportMessage.systrace', index=9,
+ number=22, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ _descriptor.FieldDescriptor(
+ name='start_timestamp', full_name='android.vts.TestReportMessage.start_timestamp', index=10,
number=101, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
- name='end_timestamp', full_name='android.vts.TestReportMessage.end_timestamp', index=10,
+ name='end_timestamp', full_name='android.vts.TestReportMessage.end_timestamp', index=11,
number=102, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
- name='coverage', full_name='android.vts.TestReportMessage.coverage', index=11,
+ name='coverage', full_name='android.vts.TestReportMessage.coverage', index=12,
number=103, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
@@ -678,13 +727,14 @@
options=None,
is_extendable=False,
extension_ranges=[],
- serialized_start=1176,
- serialized_end=1669,
+ serialized_start=1291,
+ serialized_end=1838,
)
_TESTCASEREPORTMESSAGE.fields_by_name['test_result'].enum_type = _TESTCASERESULT
_TESTCASEREPORTMESSAGE.fields_by_name['coverage'].message_type = _COVERAGEREPORTMESSAGE
_TESTCASEREPORTMESSAGE.fields_by_name['profiling'].message_type = _PROFILINGREPORTMESSAGE
+_TESTCASEREPORTMESSAGE.fields_by_name['systrace'].message_type = _SYSTRACEREPORTMESSAGE
_PROFILINGREPORTMESSAGE.fields_by_name['type'].enum_type = _VTSPROFILINGTYPE
_PROFILINGREPORTMESSAGE.fields_by_name['regression_mode'].enum_type = _VTSPROFILINGREGRESSIONMODE
_TESTREPORTMESSAGE.fields_by_name['test_type'].enum_type = _VTSTESTTYPE
@@ -693,12 +743,14 @@
_TESTREPORTMESSAGE.fields_by_name['host_info'].message_type = _VTSHOSTINFO
_TESTREPORTMESSAGE.fields_by_name['test_case'].message_type = _TESTCASEREPORTMESSAGE
_TESTREPORTMESSAGE.fields_by_name['profiling'].message_type = _PROFILINGREPORTMESSAGE
+_TESTREPORTMESSAGE.fields_by_name['systrace'].message_type = _SYSTRACEREPORTMESSAGE
_TESTREPORTMESSAGE.fields_by_name['coverage'].message_type = _COVERAGEREPORTMESSAGE
DESCRIPTOR.message_types_by_name['AndroidDeviceInfoMessage'] = _ANDROIDDEVICEINFOMESSAGE
DESCRIPTOR.message_types_by_name['AndroidBuildInfo'] = _ANDROIDBUILDINFO
DESCRIPTOR.message_types_by_name['VtsHostInfo'] = _VTSHOSTINFO
DESCRIPTOR.message_types_by_name['TestCaseReportMessage'] = _TESTCASEREPORTMESSAGE
DESCRIPTOR.message_types_by_name['ProfilingReportMessage'] = _PROFILINGREPORTMESSAGE
+DESCRIPTOR.message_types_by_name['SystraceReportMessage'] = _SYSTRACEREPORTMESSAGE
DESCRIPTOR.message_types_by_name['CoverageReportMessage'] = _COVERAGEREPORTMESSAGE
DESCRIPTOR.message_types_by_name['TestReportMessage'] = _TESTREPORTMESSAGE
@@ -732,6 +784,12 @@
# @@protoc_insertion_point(class_scope:android.vts.ProfilingReportMessage)
+class SystraceReportMessage(_message.Message):
+ __metaclass__ = _reflection.GeneratedProtocolMessageType
+ DESCRIPTOR = _SYSTRACEREPORTMESSAGE
+
+ # @@protoc_insertion_point(class_scope:android.vts.SystraceReportMessage)
+
class CoverageReportMessage(_message.Message):
__metaclass__ = _reflection.GeneratedProtocolMessageType
DESCRIPTOR = _COVERAGEREPORTMESSAGE
diff --git a/runners/host/base_test.py b/runners/host/base_test.py
index dd8ff84..92a341d 100644
--- a/runners/host/base_test.py
+++ b/runners/host/base_test.py
@@ -138,6 +138,7 @@
def getUserParam(self,
param_name,
error_if_not_found=False,
+ log_warning_and_continue_if_not_found=False,
default_value=None):
"""Get the value of a single user parameter.
@@ -152,6 +153,8 @@
will be accessed.
error_if_not_found: bool, whether to raise error if parameter not exists. Default:
False
+ log_warning_and_continue_if_not_found: bool, log a warning message if parameter value
+ not found.
default_value: object, default value to return if not found. If error_if_not_found is
True, this parameter has no effect. Default: None
@@ -171,10 +174,11 @@
curr_obj = self.user_params
for param in param_name:
if param not in curr_obj:
+ msg = "Missing user param '%s' in test configuration." % param_name
if error_if_not_found:
- raise errors.BaseTestError(
- ("Missing user param '%s' "
- "in test configuration.") % name)
+ raise errors.BaseTestError(msg)
+ elif log_warning_and_continue_if_not_found:
+ logging.warn(msg)
return default_value
curr_obj = curr_obj[param]
diff --git a/runners/host/base_test_with_webdb.py b/runners/host/base_test_with_webdb.py
index bc1d22e..450871a 100644
--- a/runners/host/base_test_with_webdb.py
+++ b/runners/host/base_test_with_webdb.py
@@ -41,6 +41,7 @@
from vts.utils.python.build.api import artifact_fetcher
from vts.utils.python.coverage import coverage_utils
from vts.utils.python.profiling import profiling_utils
+from vts.utils.python.systrace import systrace_controller
_ANDROID_DEVICE = "AndroidDevice"
_MAX = "max"
@@ -67,6 +68,7 @@
a GAE-side bigtable.
_profiling: a dict containing the current profiling information.
_profiling_data: a list of profiling data generated for each test case.
+ _systrace_controller: SystraceController object
"""
BRANCH = "master" # TODO: read from tradefed parameters
@@ -81,9 +83,7 @@
super(BaseTestWithWebDbClass, self).__init__(configs)
def _setUpClass(self):
- """Proxy function to guarantee the base implementation of setUpClass
- is called.
- """
+ """Proxy function to guarantee the base implementation of setUpClass is called."""
self.getUserParams(opt_param_names=[
self.USE_GAE_DB, keys.ConfigKeys.IKEY_BIGTABLE_BASE_URL,
keys.ConfigKeys.IKEY_MODULES, keys.ConfigKeys.IKEY_ENABLE_COVERAGE,
@@ -95,29 +95,40 @@
self.enable_profiling = self.getUserParam(
keys.ConfigKeys.IKEY_ENABLE_PROFILING, default_value=False)
+ self._systrace_controller = None
+ systrace_process_name = self.getUserParam(
+ keys.ConfigKeys.IKEY_SYSTRACE_PROCESS_NAME, default_value=None)
+ data_file_path = self.getUserParam(
+ keys.ConfigKeys.IKEY_DATA_FILE_PATH, default_value=None)
+ if systrace_process_name:
+ systrace_process_name = str(systrace_process_name)
+ if data_file_path:
+ android_vts_path = os.path.normpath(
+ os.path.join(data_file_path, '..'))
+
+ self._systrace_controller = systrace_controller.SystraceController(
+ android_vts_path, systrace_process_name)
+ else:
+ logging.error('Cannot create systrace controller object: '
+ 'data_file_path not available')
+
+ self.test_module_name = self.getUserParam(
+ keys.ConfigKeys.KEY_TESTBED_NAME,
+ log_warning_and_continue_if_not_found=True,
+ default_value=self.__class__.__name__)
+ self.test_module_name = str(self.test_module_name)
+ logging.info("Test module name: %s", self.test_module_name)
+
if getattr(self, self.USE_GAE_DB, False):
logging.info("GAE-DB: turned on")
self._report_msg = ReportMsg.TestReportMessage()
- test_module_name = self.__class__.__name__
- if hasattr(self, keys.ConfigKeys.KEY_TESTBED_NAME):
- user_specified_test_name = getattr(
- self, keys.ConfigKeys.KEY_TESTBED_NAME, None)
- if user_specified_test_name:
- test_module_name = str(user_specified_test_name)
- else:
- logging.warn("%s field = %s",
- keys.ConfigKeys.KEY_TESTBED_NAME,
- user_specified_test_name)
- else:
- logging.warn("%s not defined in the given test config",
- keys.ConfigKeys.KEY_TESTBED_NAME)
- logging.info("Test module name: %s", test_module_name)
- self._report_msg.test = test_module_name
+ self._report_msg.test = self.test_module_name
self._report_msg.test_type = ReportMsg.VTS_HOST_DRIVEN_STRUCTURAL
self._report_msg.start_timestamp = self.GetTimestamp()
self._report_msg.host_info.hostname = socket.gethostname()
self.SetDeviceInfo(self._report_msg)
self.InitializeCoverage()
+
self._profiling = {}
self._profiling_data = []
return super(BaseTestWithWebDbClass, self)._setUpClass()
@@ -126,7 +137,7 @@
"""Calls sub-class's tearDownClass first and then uploads to web DB."""
result = super(BaseTestWithWebDbClass, self)._tearDownClass()
if (getattr(self, self.USE_GAE_DB, False) and
- getattr(self, keys.ConfigKeys.IKEY_BIGTABLE_BASE_URL, "")):
+ getattr(self, keys.ConfigKeys.IKEY_BIGTABLE_BASE_URL, "")):
# Handle case when runner fails, tests aren't executed
if (self.results.executed and
self.results.executed[-1].test_name == "setup_class"):
@@ -227,22 +238,84 @@
return super(BaseTestWithWebDbClass, self)._testEntry(test_name)
def _testExit(self, test_name):
- """Proxy function to guarantee the base implementation of tearDownTest
- is called.
+ """Proxy function to guarantee the base implementation of tearDownTest is called.
+
+ Args:
+ test_name: string, test name
"""
+ test_end_time = self.GetTimestamp()
if getattr(self, self.USE_GAE_DB, False):
if self._current_test_report_msg:
- self._current_test_report_msg.end_timestamp = self.GetTimestamp(
- )
+ self._current_test_report_msg.end_timestamp = test_end_time
+ if self._systrace_controller and self._systrace_controller.is_valid:
+ if self.getUserParam(
+ keys.ConfigKeys.IKEY_SYSTRACE_UPLAD_TO_DASHBOARD,
+ default_value=False):
+ try:
+ systrace_msg = self._current_test_report_msg.systrace.add(
+ )
+ systrace_msg.process_name = self._systrace_controller.process_name
+ html = self._systrace_controller.ReadLastOutput()
+ if html is None:
+ logging.error(
+ 'Failed to read systrace output.')
+ else:
+ systrace_msg.html.append(html)
+ logging.info(
+ 'Systrace html data added to report message. Length: %s',
+ len(html))
+ suc = self._systrace_controller.ClearLastOutput()
+ if not suc:
+ logging.error(
+ 'failed to clear last systrace output.')
+ except Exception as e: # TODO(yuexima): more specific exceptions catch
+ logging.error(
+ 'Failed to add systrace to resport message %s',
+ e)
+
+ report_path = self.getUserParam(
+ keys.ConfigKeys.IKEY_SYSTRACE_REPORT_PATH,
+ default_value=None)
+ if report_path:
+ report_destination_file = os.path.join(
+ report_path,
+ '{module}_{test}_{process}_{time}.html'.format(
+ module=self.test_module_name,
+ test=test_name,
+ process=self._systrace_controller.process_name,
+ time=test_end_time))
+ self._systrace_controller.SaveLastOutput(
+ report_destination_file)
+ logging.info('Systrace output saved to %s',
+ report_destination_file)
else:
logging.info(
"test result of '%s' is empty and will not be uploaded.",
test_name)
return super(BaseTestWithWebDbClass, self)._testExit(test_name)
+ def _setUpTest(self, test_name):
+ """Proxy function to guarantee the base implementation of _setUpTest is called.
+
+ Args:
+ test_name: string, test name
+ """
+ if self._systrace_controller:
+ self._systrace_controller.Start()
+ return super(BaseTestWithWebDbClass, self)._setUpTest(test_name)
+
+ def _tearDownTest(self, test_name):
+ """Proxy function to guarantee the base implementation of test_name is called.
+
+ Args:
+ test_name: string, test name
+ """
+ if self._systrace_controller:
+ self._systrace_controller.Stop()
+ return super(BaseTestWithWebDbClass, self)._tearDownTest(test_name)
+
def _onFail(self, record):
- """Proxy function to guarantee the base implementation of onFail is
- called.
+ """Proxy function to guarantee the base implementation of _onFail is called.
Args:
record: The records.TestResultRecord object for the failed test
@@ -253,11 +326,10 @@
return super(BaseTestWithWebDbClass, self)._onFail(record)
def _onPass(self, record):
- """Proxy function to guarantee the base implementation of onPass is
- called.
+ """Proxy function to guarantee the base implementation of _onPass is called.
Args:
- record: The records.TestResultRecord object for the passed test
+ record: The records.TestResultRecord object for the failed test
case.
"""
if getattr(self, self.USE_GAE_DB, False):
@@ -265,11 +337,10 @@
return super(BaseTestWithWebDbClass, self)._onPass(record)
def _onSkip(self, record):
- """Proxy function to guarantee the base implementation of onSkip is
- called.
+ """Proxy function to guarantee the base implementation of _onSkip is called.
Args:
- record: The records.TestResultRecord object for the skipped test
+ record: The records.TestResultRecord object for the failed test
case.
"""
if getattr(self, self.USE_GAE_DB, False):
@@ -277,11 +348,10 @@
return super(BaseTestWithWebDbClass, self)._onSkip(record)
def _onSilent(self, record):
- """Proxy function to guarantee the base implementation of onSilent is
- called.
+ """Proxy function to guarantee the base implementation of _onSilent is called.
Args:
- record: The records.TestResultRecord object for the skipped test
+ record: The records.TestResultRecord object for the failed test
case.
"""
if getattr(self, self.USE_GAE_DB, False):
@@ -290,8 +360,7 @@
return super(BaseTestWithWebDbClass, self)._onSilent(record)
def _onException(self, record):
- """Proxy function to guarantee the base implementation of onException
- is called.
+ """Proxy function to guarantee the base implementation of _onException is called.
Args:
record: The records.TestResultRecord object for the failed test
@@ -346,14 +415,15 @@
self._profiling[name].end_timestamp = self.GetTimestamp()
return True
- def AddProfilingDataLabeledVector(self,
- name,
- labels,
- values,
- options=[],
- x_axis_label="x-axis",
- y_axis_label="y-axis",
- regression_mode=ReportMsg.VTS_REGRESSION_MODE_INCREASING):
+ def AddProfilingDataLabeledVector(
+ self,
+ name,
+ labels,
+ values,
+ options=[],
+ x_axis_label="x-axis",
+ y_axis_label="y-axis",
+ regression_mode=ReportMsg.VTS_REGRESSION_MODE_INCREASING):
"""Adds the profiling data in order to upload to the web DB.
Args:
@@ -466,9 +536,8 @@
# Fetch repo dictionary
try:
- revision_dict = build_client.GetRepoDictionary(self.BRANCH,
- build_flavor,
- device_build_id)
+ revision_dict = build_client.GetRepoDictionary(
+ self.BRANCH, build_flavor, device_build_id)
except:
logging.error("Could not read build info for branch: %s, " +
"target: %s, id: %s", self.BRANCH, build_flavor,
@@ -545,13 +614,18 @@
# auto-process coverage data
checksum_gcno_dict = getattr(self, self.CHECKSUM_GCNO_DICT)
coverage_utils.ProcessCoverageData(
- report_msg, gcda_dict, revision_dict,
+ report_msg,
+ gcda_dict,
+ revision_dict,
checksum_gcno_dict=checksum_gcno_dict)
else:
# explicitly process coverage data for the specified modules
modules = getattr(self, keys.ConfigKeys.IKEY_MODULES)
coverage_utils.ProcessCoverageData(
- report_msg, gcda_dict, revision_dict, modules=modules,
+ report_msg,
+ gcda_dict,
+ revision_dict,
+ modules=modules,
cov_zip=cov_zip)
return True
@@ -589,14 +663,17 @@
for api, latencies in merged_profiling_data.values.items():
if latencies:
merged_profiling_data.labels.append(api)
- merged_profiling_data.aggregated_values["max"].append(max(latencies))
- merged_profiling_data.aggregated_values["min"].append(min(latencies))
- merged_profiling_data.aggregated_values["avg"].append(sum(latencies) / len(latencies))
+ merged_profiling_data.aggregated_values["max"].append(
+ max(latencies))
+ merged_profiling_data.aggregated_values["min"].append(
+ min(latencies))
+ merged_profiling_data.aggregated_values["avg"].append(
+ sum(latencies) / len(latencies))
for tag in [_MAX, _MIN, _AVG]:
if merged_profiling_data.name is None:
- name = tag
+ name = tag
else:
- name = merged_profiling_data.name + "_" + tag
+ name = merged_profiling_data.name + "_" + tag
self.AddProfilingDataLabeledVector(
name,
merged_profiling_data.labels,
diff --git a/runners/host/keys.py b/runners/host/keys.py
index c11bda7..7393f28 100644
--- a/runners/host/keys.py
+++ b/runners/host/keys.py
@@ -39,7 +39,6 @@
IKEY_BINARY_TEST_SOURCES = "binary_test_sources"
IKEY_BINARY_TEST_WORKING_DIRECTORIES = "binary_test_working_directories"
IKEY_BINARY_TEST_LD_LIBRARY_PATHS = "binary_test_ld_library_paths"
- IKEY_BINARY_TEST_PROFILING_LIBRARY_PATHS = "binary_test_profiling_library_paths"
IKEY_BINARY_TEST_DISABLE_FRAMEWORK = "binary_test_disable_framework"
# Internal keys, used internally, not exposed to user's config files.
@@ -65,6 +64,12 @@
# Keys for profiling
IKEY_ENABLE_PROFILING = "enable_profiling"
+ IKEY_BINARY_TEST_PROFILING_LIBRARY_PATHS = "binary_test_profiling_library_paths"
+
+ # Keys for systrace (for hal tests)
+ IKEY_SYSTRACE_PROCESS_NAME = "systrace_process_name"
+ IKEY_SYSTRACE_REPORT_PATH = "systrace_report_path"
+ IKEY_SYSTRACE_UPLAD_TO_DASHBOARD = "systrace_upload_to_dashboard"
# Keys for coverage
IKEY_ENABLE_COVERAGE = "enable_coverage"
diff --git a/utils/python/systrace/__init__.py b/utils/python/systrace/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/utils/python/systrace/__init__.py
diff --git a/utils/python/systrace/systrace_controller.py b/utils/python/systrace/systrace_controller.py
new file mode 100644
index 0000000..4f5d6dc
--- /dev/null
+++ b/utils/python/systrace/systrace_controller.py
@@ -0,0 +1,205 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import tempfile
+import shutil
+import subprocess
+import logging
+
+PATH_SYSTRACE_SCRIPT = os.path.join('tools/external/chromium-trace',
+ 'systrace.py')
+EXPECTED_START_STDOUT = 'Starting tracing'
+
+
+class SystraceController(object):
+ '''A util to start/stop systrace through shell command.
+
+ Attributes:
+ _android_vts_path: string, path to android-vts
+ _path_output: string, systrace temporally output path
+ _path_systrace_script: string, path to systrace controller python script
+ _subprocess: subprocess.Popen, a subprocess objects of systrace shell command
+ is_valid: boolean, whether the current environment setting for
+ systrace is valid
+ process_name: string, process name to trace
+ '''
+
+ def __init__(self, android_vts_path, process_name):
+ self._android_vts_path = android_vts_path
+ self._path_output = None
+ self._path_systrace_script = os.path.join(android_vts_path,
+ PATH_SYSTRACE_SCRIPT)
+ self.is_valid = os.path.exists(self._path_systrace_script)
+ if not self.is_valid:
+ logging.error('invalid systrace script path: %s',
+ self._path_systrace_script)
+ self.process_name = process_name
+
+ @property
+ def is_valid(self):
+ ''''returns whether the current environment setting is valid'''
+ return self._is_valid
+
+ @is_valid.setter
+ def is_valid(self, is_valid):
+ ''''Set valid status'''
+ self._is_valid = is_valid
+
+ def Start(self):
+ '''Start systrace process.
+
+ Use shell command to start a python systrace script
+
+ Returns:
+ True if successfully started systrace; False otherwise.
+ '''
+ self._subprocess = None
+ self._path_output = None
+
+ if not self.is_valid:
+ logging.error(
+ 'Cannot start systrace: configuration is not correct for %s.',
+ self.process_name)
+ return False
+
+ # TODO: check target device for compatibility (e.g. has systrace hooks)
+
+ self._path_output = os.path.join(tempfile.mkdtemp(),
+ self.process_name + '.html')
+
+ cmd = ('python -u {script} hal sched '
+ '-a {process_name} -o {output}').format(
+ script=self._path_systrace_script,
+ process_name=self.process_name,
+ output=self._path_output)
+ process = subprocess.Popen(
+ str(cmd),
+ shell=True,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ line = ''
+ success = False
+ while process.poll() is None:
+ line += process.stdout.read(1)
+
+ if not line:
+ break
+ elif EXPECTED_START_STDOUT in line:
+ success = True
+ break
+
+ if not success:
+ logging.error('Failed to start systrace on process %s',
+ process_name)
+ stdout, stderr = process.communicate()
+ logging.error('stdout: %s', line + stdout)
+ logging.error('stderr: %s', stderr)
+ logging.error('ret_code: %s', process.returncode)
+ return False
+
+ self._subprocess = process
+ logging.info('Systrace started for %s', self.process_name)
+ return True
+
+ def Stop(self):
+ '''Stop systrace process.
+
+ Returns:
+ True if successfully stopped systrace; False otherwise.
+ '''
+ if not self.is_valid or not self._subprocess:
+ logging.warn(
+ 'Cannot stop systrace: systrace was not started for %s.',
+ self.process_name)
+ return False
+
+ # Press enter to stop systrace script
+ self._subprocess.stdin.write('\n')
+ self._subprocess.stdin.flush()
+
+ # Wait for output to be written down
+ self._subprocess.communicate()
+ logging.info('Systrace stopped for %s', self.process_name)
+ return True
+
+ def ReadLastOutput(self):
+ '''Read systrace output html.
+
+ Returns:
+ string, data of systrace html output. None if failed to read.
+ '''
+ if not self.is_valid or not self._subprocess:
+ logging.warn(
+ 'Cannot read output: systrace was not started for %s.',
+ self.process_name)
+ return None
+
+ try:
+ with open(self._outputs[process_name], 'r') as f:
+ data = f.read()
+ logging.info('Systrace output length for %s: %s', process_name,
+ len(data))
+ return data
+ except Exception as e:
+ logging.error('Cannot read output: file open failed, %s', e)
+ return None
+
+ def SaveLastOutput(self, report_path=None):
+ if not report_path:
+ logging.error('report path supplied is None')
+ return False
+
+ if not self._path_output:
+ logging.error(
+ 'systrace did not started correctly. Output path is empty.')
+ return False
+
+ parent_dir = os.path.dirname(report_path)
+ if not os.path.exists(parent_dir):
+ try:
+ os.makedirs(parent_dir)
+ except Exception as e:
+ logging.error('error happened while creating directory: %s', e)
+ return False
+
+ try:
+ shutil.copy(self._path_output, report_path)
+ except Exception as e: # TODO(yuexima): more specific error catch
+ logging.error('failed to copy output to report path: %s', e)
+ return False
+
+ return True
+
+ def ClearLastOutput(self):
+ '''Clear systrace output html.
+
+ Since output are created in temp directories, this step is optional.
+
+ Returns:
+ True if successfully deleted temp output file; False otherwise.
+ '''
+
+ if self._path_output:
+ try:
+ shutil.rmtree(self._path_output)
+ except Exception as e:
+ logging.error('failed to remove systrace output file. %s', e)
+ return False
+
+ return True