blob: b46e642b5e92b5e8d429727fa90cd1e2ca2f2716 [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.tests.sysmem.host;
import com.android.tradefed.result.FileInputStreamSource;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* Utilities for sampling and reporting memory metrics.
*/
class Metrics {
private Device mDevice;
private TestMetrics mMetrics;
private TestLogData mLogs;
/**
* Constructs a metrics instance that will output high level metrics and
* more detailed breakdowns using the given <code>metrics</code> and
* <code>logs</code> objects.
*
* @param device the device to sample metrics from
* @param metrics where to log the high level metrics when taking a sample
* @param logs where to log detailed breakdowns when taking a sample
*/
Metrics(Device device, TestMetrics metrics, TestLogData logs) {
this.mDevice = device;
this.mMetrics = metrics;
this.mLogs = logs;
}
/**
* Writes the given <code>text</code> to a log with the given label.
*/
private void logText(String label, String text) throws TestException {
try {
File file = File.createTempFile(label, "txt");
PrintStream ps = new PrintStream(file);
ps.print(text);
try (FileInputStreamSource dataStream = new FileInputStreamSource(file)) {
mLogs.addTestLog(label, LogDataType.TEXT, dataStream);
}
} catch (IOException e) {
throw new TestException(e);
}
}
/**
* Samples the current memory use on the system. Outputs high level test
* metrics and detailed breakdowns to the TestMetrics and TestLogData
* objects provided when constructing this Metrics instance. The metrics
* and log names are prefixed with the given label.
*
* @param label prefix to use for metrics and logs output for this sample.
*/
void sample(String label) throws TestException {
// adb root access is required to get showmap
mDevice.enableAdbRoot();
int pid = mDevice.getProcessPid("system_server");
// Read showmap for system server and add it as a test log
String showmap = mDevice.executeShellCommand("showmap " + pid);
logText(label + ".system_server.showmap", showmap);
// Extract VSS, PSS and RSS from the showmap and output them as metrics.
// The last lines of the showmap output looks something like:
// CHECKSTYLE:OFF Generated code
// virtual shared shared private private
// size RSS PSS clean dirty clean dirty swap swapPSS # object
//-------- -------- -------- -------- -------- -------- -------- -------- -------- ---- ------------------------------
// 928480 113016 24860 87348 7916 3632 14120 1968 1968 1900 TOTAL
// CHECKSTYLE:ON Generated code
try {
int pos = showmap.lastIndexOf("----");
Scanner sc = new Scanner(showmap.substring(pos));
sc.next();
long vss = sc.nextLong();
long rss = sc.nextLong();
long pss = sc.nextLong();
mMetrics.addTestMetric(label + ".system_server.vss", Long.toString(vss));
mMetrics.addTestMetric(label + ".system_server.rss", Long.toString(rss));
mMetrics.addTestMetric(label + ".system_server.pss", Long.toString(pss));
} catch (InputMismatchException e) {
throw new TestException("unexpected showmap format", e);
}
// Run debuggerd -j to get GC stats for system server and add it as a
// test log
String debuggerd = mDevice.executeShellCommand("debuggerd -j " + pid);
logText(label + ".system_server.debuggerd", debuggerd);
// TODO: Experiment with other additional metrics.
// TODO: Consider launching an instrumentation to collect metrics from
// within the device itself.
}
}