blob: a306c2c1dcc745cf3140f4073daba4cb08d2e951 [file] [log] [blame]
/*
* Copyright (C) 2018 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.NullOutputReceiver;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.log.LogUtil.CLog;
import java.util.concurrent.TimeUnit;
/**
* A {@link IMetricCollector} that collects traces during the test using trace-cmd, and logs them to
* the invocation.
*
* <p>This trace collector allows for USB disconnection during the test (as in power testing).
*
* <p>The system default tool, atrace, is used in tandem with this collector to set the
* android-specific sysfs flags.
*
* <p>A trace-cmd (https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git) binary
* compatible with Android must be specified.
*
* <p>This will upload the trace.dat format (see man 5 trace-cmd.dat) produced by trace-cmd.
*/
@OptionClass(alias = "trace-cmd")
public class TraceCmdCollector extends AtraceCollector {
/* Params for use of trace-cmd binary
* The upstream tool, trace-cmd (https://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git)
* will scrape the kernel buffers to disk at a configurable interval.
* This is advantageous because:
* 1) a packed format is produced, using less disk usage.
* 2) no conversion of packed data to human-readable text occurs, resulting in less runtime
* processing overhead.
* 3) an arbitrarily large file can be produced.
* 4) wakeups can be scheduled at a large enough interval to minimize side-effects.
*
* Since its not a default system tool, a trace-cmd binary compatible with the target
* device must be pushed to the device, and specified with --trace-cmd-binary
*/
@Option(
name = "trace-cmd-binary",
description = "The path on the device of the trace-cmd binary to use"
)
private String mTraceCmdBinary = null;
/* 'trace-cmd record' will be issued with these args.
* the valid arguments are described in 'man 1 trace-cmd-record' (https://linux.die.net/man/1/trace-cmd-record)
* The default is configured to wake up and spill to disk a 10s interval (-s), and use the boot clock.
*/
@Option(
name = "trace-cmd-recording-args",
description = "The flags to pass to 'trace-cmd record'"
)
private String mTraceCmdRecordArgs =
"-e sched:sched_waking "
+ "-e sched:sched_wakeup -e sched:sched_wakeup_new "
+ "-e sched:sched_switch -e power:cpu_idle "
+ "-e power:cpu_frequency -e power:cpu_frequency_limits "
+ "-e power:suspend_resume -e power:clock_set_rate "
+ "-e power:clock_enable -e power:clock_disable "
+ "-b 12000 -C boot -s 10000000 ";
@Override
protected LogDataType getLogType() {
return LogDataType.KERNEL_TRACE;
}
@Override
protected void startTracing(ITestDevice device) throws DeviceNotAvailableException {
if (mTraceCmdBinary == null) {
CLog.w("--trace-cmd-binary was not set, skipping trace metric collection");
return;
}
/* trace-cmd will periodically scrape the kernel buffer to disk at a configurable rate.
* No-raw-buffer -> human-readable-text will be performed by the kernel either.
* The events set by atrace should still stay enabled.
*/
super.startTracing(device);
StringBuilder traceCmd = new StringBuilder(100);
traceCmd.append("nohup ");
traceCmd.append(mTraceCmdBinary);
traceCmd.append(" record -o ");
traceCmd.append(fullLogPath());
traceCmd.append(" ");
traceCmd.append(mTraceCmdRecordArgs);
traceCmd.append(" > /dev/null 2>&1 &");
CLog.i("Issuing trace-cmd: %s ", traceCmd.toString());
CollectingOutputReceiver c = new CollectingOutputReceiver();
device.executeShellCommand("chmod +x " + mTraceCmdBinary, c, 1, TimeUnit.SECONDS, 1);
device.executeShellCommand(traceCmd.toString(), c, 1, TimeUnit.SECONDS, 1);
}
@Override
protected void stopTracing(ITestDevice device) throws DeviceNotAvailableException {
if (mTraceCmdBinary == null) {
CLog.w("trace-cmd was not set, skipping attempt to stop trace collection");
return;
}
// sigterm the trace process and monitor for the process's demise.
// Failure to wait can result in a partial log being pulled.
// Since it was started with nohup in a separate shell, trace-cmd is not a child
// of this shell, and 'wait' won't work.
CLog.i("Collecting trace-cmd log from device: " + device.getSerialNumber());
device.executeShellCommand(
"for PID in $(pidof trace-cmd); "
+ "do while kill -s sigint $PID; do sleep 0.3; done; done;",
new NullOutputReceiver(),
60,
TimeUnit.SECONDS,
1);
}
}