diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-10-18 16:51:51 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-10-18 16:51:51 +0000 |
commit | 1b8312235f3b947d3f49ab35ec2e249b11c2673b (patch) | |
tree | 988e80c2146ebbaba9566333815755e9d3b5a057 /src/com/android | |
parent | 55396cb7426bf8a74dd41c0ebb1d63893221400e (diff) | |
parent | 4cbf9cb7fdd2af9333b8256b19d77296273c685e (diff) | |
download | tradefederation-1b8312235f3b947d3f49ab35ec2e249b11c2673b.tar.gz |
Snap for 4402310 from 4cbf9cb7fdd2af9333b8256b19d77296273c685e to oc-m2-release
Change-Id: I806922dc8762c1ea708988c5ff060b09794205f8
Diffstat (limited to 'src/com/android')
8 files changed, 408 insertions, 3 deletions
diff --git a/src/com/android/tradefed/config/Configuration.java b/src/com/android/tradefed/config/Configuration.java index 60aa5e790..9e6b05f47 100644 --- a/src/com/android/tradefed/config/Configuration.java +++ b/src/com/android/tradefed/config/Configuration.java @@ -24,6 +24,7 @@ import com.android.tradefed.config.OptionSetter.FieldDef; import com.android.tradefed.device.IDeviceRecovery; import com.android.tradefed.device.IDeviceSelection; import com.android.tradefed.device.TestDeviceOptions; +import com.android.tradefed.device.metric.IMetricCollector; import com.android.tradefed.log.ILeveledLogOutput; import com.android.tradefed.log.StdoutLogger; import com.android.tradefed.profiler.ITestProfiler; @@ -87,6 +88,7 @@ public class Configuration implements IConfiguration { public static final String CONFIGURATION_DESCRIPTION_TYPE_NAME = "config_desc"; public static final String DEVICE_NAME = "device"; public static final String TEST_PROFILER_TYPE_NAME = "test_profiler"; + public static final String DEVICE_METRICS_COLLECTOR_TYPE_NAME = "metrics_collector"; public static final String SANDBOX_TYPE_NAME = "sandbox"; private static Map<String, ObjTypeInfo> sObjTypeMap = null; @@ -161,6 +163,9 @@ public class Configuration implements IConfiguration { CONFIGURATION_DESCRIPTION_TYPE_NAME, new ObjTypeInfo(ConfigurationDescriptor.class, false)); sObjTypeMap.put(TEST_PROFILER_TYPE_NAME, new ObjTypeInfo(ITestProfiler.class, false)); + sObjTypeMap.put( + DEVICE_METRICS_COLLECTOR_TYPE_NAME, + new ObjTypeInfo(IMetricCollector.class, true)); } return sObjTypeMap; } @@ -211,6 +216,7 @@ public class Configuration implements IConfiguration { setSystemStatusCheckers(new ArrayList<ISystemStatusChecker>()); setConfigurationDescriptor(new ConfigurationDescriptor()); setProfiler(new StubTestProfiler()); + setDeviceMetricCollectors(new ArrayList<>()); } /** @@ -349,6 +355,13 @@ public class Configuration implements IConfiguration { RESULT_REPORTER_TYPE_NAME); } + @SuppressWarnings("unchecked") + @Override + public List<IMetricCollector> getMetricCollectors() { + return (List<IMetricCollector>) + getConfigurationObjectList(DEVICE_METRICS_COLLECTOR_TYPE_NAME); + } + /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override @@ -642,6 +655,11 @@ public class Configuration implements IConfiguration { setConfigurationObjectListNoThrow(RESULT_REPORTER_TYPE_NAME, listeners); } + @Override + public void setDeviceMetricCollectors(List<IMetricCollector> collectors) { + setConfigurationObjectListNoThrow(DEVICE_METRICS_COLLECTOR_TYPE_NAME, collectors); + } + /** * {@inheritDoc} */ diff --git a/src/com/android/tradefed/config/IConfiguration.java b/src/com/android/tradefed/config/IConfiguration.java index 88e2b43c5..4270b4abc 100644 --- a/src/com/android/tradefed/config/IConfiguration.java +++ b/src/com/android/tradefed/config/IConfiguration.java @@ -22,6 +22,7 @@ import com.android.tradefed.config.ConfigurationDef.OptionDef; import com.android.tradefed.device.IDeviceRecovery; import com.android.tradefed.device.IDeviceSelection; import com.android.tradefed.device.TestDeviceOptions; +import com.android.tradefed.device.metric.IMetricCollector; import com.android.tradefed.log.ILeveledLogOutput; import com.android.tradefed.profiler.ITestProfiler; import com.android.tradefed.result.ILogSaver; @@ -129,6 +130,9 @@ public interface IConfiguration { */ public ITestProfiler getProfiler(); + /** Gets the {@link IMetricCollector}s from the configuration. */ + public List<IMetricCollector> getMetricCollectors(); + /** * Gets the {@link ICommandOptions} to use from the configuration. * @@ -346,6 +350,9 @@ public interface IConfiguration { */ public void setTestInvocationListener(ITestInvocationListener listener); + /** Set the list of {@link IMetricCollector}s, replacing any existing values. */ + public void setDeviceMetricCollectors(List<IMetricCollector> collectors); + /** * Set the {@link ITestProfiler}, replacing any existing values * diff --git a/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java b/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java new file mode 100644 index 000000000..9f6fbc097 --- /dev/null +++ b/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tradefed.device.metric; + +import com.android.ddmlib.testrunner.TestIdentifier; +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.invoker.IInvocationContext; +import com.android.tradefed.result.ITestInvocationListener; +import com.android.tradefed.result.InputStreamSource; +import com.android.tradefed.result.LogDataType; + +import java.util.List; +import java.util.Map; + +/** + * Base implementation of {@link IMetricCollector} that allows to start and stop collection on + * {@link #onTestRunStart(DeviceMetricData)} and {@link #onTestRunEnd(DeviceMetricData)}. + */ +public class BaseDeviceMetricCollector implements IMetricCollector { + + private IInvocationContext mContext; + private ITestInvocationListener mForwarder; + private DeviceMetricData mRunData; + + @Override + public ITestInvocationListener init( + IInvocationContext context, ITestInvocationListener listener) { + mContext = context; + mForwarder = listener; + return this; + } + + @Override + public List<ITestDevice> getDevices() { + return mContext.getDevices(); + } + + @Override + public List<IBuildInfo> getBuildInfos() { + return mContext.getBuildInfos(); + } + + @Override + public ITestInvocationListener getInvocationListener() { + return mForwarder; + } + + @Override + public void onTestRunStart(DeviceMetricData runData) { + // Does nothing + } + + @Override + public void onTestRunEnd(DeviceMetricData runData) { + // Does nothing + } + + /** =================================== */ + /** Invocation Listeners for forwarding */ + @Override + public final void invocationStarted(IInvocationContext context) { + mForwarder.invocationStarted(context); + } + + @Override + public final void invocationFailed(Throwable cause) { + mForwarder.invocationFailed(cause); + } + + @Override + public final void invocationEnded(long elapsedTime) { + mForwarder.invocationEnded(elapsedTime); + } + + @Override + public final void testLog(String dataName, LogDataType dataType, InputStreamSource dataStream) { + mForwarder.testLog(dataName, dataType, dataStream); + } + + /** Test run callbacks */ + @Override + public final void testRunStarted(String runName, int testCount) { + mRunData = new DeviceMetricData(); + onTestRunStart(mRunData); + mForwarder.testRunStarted(runName, testCount); + } + + @Override + public final void testRunFailed(String errorMessage) { + mForwarder.testRunFailed(errorMessage); + } + + @Override + public final void testRunStopped(long elapsedTime) { + mForwarder.testRunStopped(elapsedTime); + } + + @Override + public final void testRunEnded(long elapsedTime, Map<String, String> runMetrics) { + onTestRunEnd(mRunData); + mRunData.addToMetrics(runMetrics); + mForwarder.testRunEnded(elapsedTime, runMetrics); + } + + /** Test cases callbacks */ + @Override + public final void testStarted(TestIdentifier test) { + testStarted(test, System.currentTimeMillis()); + } + + @Override + public final void testStarted(TestIdentifier test, long startTime) { + mForwarder.testStarted(test, startTime); + } + + @Override + public final void testFailed(TestIdentifier test, String trace) { + mForwarder.testFailed(test, trace); + } + + @Override + public final void testEnded(TestIdentifier test, Map<String, String> testMetrics) { + testEnded(test, System.currentTimeMillis(), testMetrics); + } + + @Override + public final void testEnded( + TestIdentifier test, long endTime, Map<String, String> testMetrics) { + mForwarder.testEnded(test, endTime, testMetrics); + } + + @Override + public final void testAssumptionFailure(TestIdentifier test, String trace) { + mForwarder.testAssumptionFailure(test, trace); + } + + @Override + public final void testIgnored(TestIdentifier test) { + mForwarder.testIgnored(test); + } +} diff --git a/src/com/android/tradefed/device/metric/DeviceMetricData.java b/src/com/android/tradefed/device/metric/DeviceMetricData.java new file mode 100644 index 000000000..d31324d43 --- /dev/null +++ b/src/com/android/tradefed/device/metric/DeviceMetricData.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tradefed.device.metric; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Object to hold all the data collected by metric collectors. TODO: Add the data holding and + * receiving of data methods. + */ +public class DeviceMetricData implements Serializable { + private static final long serialVersionUID = 1; + + // TODO: expend type supports to more complex type: Object, File, etc. + private LinkedHashMap<String, String> mCurrentStringMetrics = new LinkedHashMap<>(); + + public void addStringMetric(String key, String value) { + mCurrentStringMetrics.put(key, value); + } + + /** + * Push all the data received so far to the map of metrics that will be reported. This should + * also clean up the resources after pushing them. + * + * @param metrics The metrics currently available. + */ + public void addToMetrics(Map<String, String> metrics) { + // TODO: dump all the metrics collected to the map of metrics to be reported. + metrics.putAll(mCurrentStringMetrics); + } +} diff --git a/src/com/android/tradefed/device/metric/IMetricCollector.java b/src/com/android/tradefed/device/metric/IMetricCollector.java new file mode 100644 index 000000000..b6d0ef77b --- /dev/null +++ b/src/com/android/tradefed/device/metric/IMetricCollector.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tradefed.device.metric; + +import com.android.tradefed.build.IBuildInfo; +import com.android.tradefed.device.ITestDevice; +import com.android.tradefed.invoker.IInvocationContext; +import com.android.tradefed.result.ITestInvocationListener; + +import java.util.List; + +/** + * This interface will be added as a decorator when reporting tests results in order to collect + * matching metrics. + */ +public interface IMetricCollector extends ITestInvocationListener { + + /** + * Initialization of the collector with the current context and where to forward results. + * + * @param context the {@link IInvocationContext} for the invocation in progress. + * @param listener the {@link ITestInvocationListener} where to put results. + * @return the new listener wrapping the original one. + */ + public ITestInvocationListener init( + IInvocationContext context, ITestInvocationListener listener); + + /** Returns the list of devices available in the invocation. */ + public List<ITestDevice> getDevices(); + + /** Returns the list of build information available in the invocation. */ + public List<IBuildInfo> getBuildInfos(); + + /** Returns the original {@link ITestInvocationListener} where we are forwarding the results. */ + public ITestInvocationListener getInvocationListener(); + + /** + * Callback when a test run is started. + * + * @param runData the {@link DeviceMetricData} holding the data for the run. + */ + public void onTestRunStart(DeviceMetricData runData); + + /** + * Callback when a test run is ended. This should be the time for clean up. + * + * @param runData the {@link DeviceMetricData} holding the data for the run. Will be the same + * object as during {@link #onTestRunStart(DeviceMetricData)}. + */ + public void onTestRunEnd(DeviceMetricData runData); +} diff --git a/src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java b/src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java new file mode 100644 index 000000000..7c1f9a71f --- /dev/null +++ b/src/com/android/tradefed/device/metric/ScheduledDeviceMetricCollector.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tradefed.device.metric; + +import com.android.tradefed.config.Option; +import com.android.tradefed.log.LogUtil.CLog; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * A {@link IMetricCollector} that allows to run a collection task periodically at a set interval. + */ +public abstract class ScheduledDeviceMetricCollector extends BaseDeviceMetricCollector { + + @Option( + name = "fixed-schedule-rate", + description = "Schedule the timetask as a fixed schedule rate" + ) + private boolean mFixedScheduleRate = false; + + @Option( + name = "interval", + description = "the interval between two tasks being scheduled", + isTimeVal = true + ) + private long mIntervalMs = 60 * 1000l; + + private Timer timer; + + @Override + public final void onTestRunStart(DeviceMetricData runData) { + CLog.d("starting"); + onStart(runData); + timer = new Timer(); + TimerTask timerTask = + new TimerTask() { + @Override + public void run() { + try { + collect(runData); + } catch (InterruptedException e) { + timer.cancel(); + Thread.currentThread().interrupt(); + CLog.e("Interrupted exception thrown from task:"); + CLog.e(e); + } + } + }; + + if (mFixedScheduleRate) { + timer.scheduleAtFixedRate(timerTask, 0, mIntervalMs); + } else { + timer.schedule(timerTask, 0, mIntervalMs); + } + } + + @Override + public final void onTestRunEnd(DeviceMetricData runData) { + if (timer != null) { + timer.cancel(); + timer.purge(); + } + onEnd(runData); + CLog.d("finished"); + } + + /** + * Task periodically & asynchronously run during the test running. + * + * @param runData the {@link DeviceMetricData} where to put metrics. + * @throws InterruptedException + */ + abstract void collect(DeviceMetricData runData) throws InterruptedException; + + /** + * Executed when entering this collector. + * + * @param runData the {@link DeviceMetricData} where to put metrics. + */ + void onStart(DeviceMetricData runData) { + // Does nothing. + } + + /** + * Executed when finishing this collector. + * + * @param runData the {@link DeviceMetricData} where to put metrics. + */ + void onEnd(DeviceMetricData runData) { + // Does nothing. + } +} diff --git a/src/com/android/tradefed/invoker/TestInvocation.java b/src/com/android/tradefed/invoker/TestInvocation.java index dd9a4fb3c..13cdae075 100644 --- a/src/com/android/tradefed/invoker/TestInvocation.java +++ b/src/com/android/tradefed/invoker/TestInvocation.java @@ -32,6 +32,7 @@ import com.android.tradefed.device.ITestDevice; import com.android.tradefed.device.ITestDevice.RecoveryMode; import com.android.tradefed.device.StubDevice; import com.android.tradefed.device.TestDeviceState; +import com.android.tradefed.device.metric.IMetricCollector; import com.android.tradefed.invoker.shard.IShardHelper; import com.android.tradefed.invoker.shard.ShardBuildCloner; import com.android.tradefed.log.ILeveledLogOutput; @@ -762,8 +763,15 @@ public class TestInvocation implements ITestInvocation { * @param listener the {@link ITestInvocationListener} of test results * @throws DeviceNotAvailableException */ - private void runTests(IInvocationContext context, IConfiguration config, - ITestInvocationListener listener) throws DeviceNotAvailableException { + @VisibleForTesting + void runTests( + IInvocationContext context, IConfiguration config, ITestInvocationListener listener) + throws DeviceNotAvailableException { + // Wrap collectors in each other and collection will be sequential + for (IMetricCollector collector : config.getMetricCollectors()) { + listener = collector.init(context, listener); + } + for (IRemoteTest test : config.getTests()) { // For compatibility of those receivers, they are assumed to be single device alloc. if (test instanceof IDeviceTest) { diff --git a/src/com/android/tradefed/testtype/StubTest.java b/src/com/android/tradefed/testtype/StubTest.java index 0809e4145..d0d7ff8d7 100644 --- a/src/com/android/tradefed/testtype/StubTest.java +++ b/src/com/android/tradefed/testtype/StubTest.java @@ -27,6 +27,7 @@ import com.android.tradefed.result.ITestInvocationListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; /** @@ -91,7 +92,7 @@ public class StubTest implements IShardableTest { TestIdentifier testId = new TestIdentifier("StubTest", "StubMethod"); listener.testStarted(testId); listener.testEnded(testId, Collections.emptyMap()); - listener.testRunEnded(500, Collections.emptyMap()); + listener.testRunEnded(500, new LinkedHashMap<>()); } } |