summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Lafon <stlafon@google.com>2017-12-06 15:54:41 -0800
committerStefan Lafon <stlafon@google.com>2017-12-07 10:10:48 -0800
commit9709fa26f1e3f713e0558c5cce71c28f208afbe9 (patch)
tree27c05cbc7b414ef3b8ccae5a03fd6ae0a2ad3466
parent057087457b123f1810d028ac044e2ece9e7610e3 (diff)
Track PSS in loadtest.
Test: Ran the loadtest. Not changing statsd. Change-Id: Idc43cba59ec2c9d4213e20b395a083fdda58e8c4
-rw-r--r--cmds/statsd/tools/loadtest/AndroidManifest.xml1
-rw-r--r--cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml7
-rw-r--r--cmds/statsd/tools/loadtest/res/values/strings.xml1
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java53
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java5
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java3
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java78
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java69
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java51
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java17
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java167
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java149
-rw-r--r--cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java27
13 files changed, 456 insertions, 172 deletions
diff --git a/cmds/statsd/tools/loadtest/AndroidManifest.xml b/cmds/statsd/tools/loadtest/AndroidManifest.xml
index d74c707a011f..2bf8ca95d846 100644
--- a/cmds/statsd/tools/loadtest/AndroidManifest.xml
+++ b/cmds/statsd/tools/loadtest/AndroidManifest.xml
@@ -39,5 +39,6 @@
</activity>
<receiver android:name=".LoadtestActivity$PusherAlarmReceiver" />
<receiver android:name=".LoadtestActivity$StopperAlarmReceiver"/>
+ <receiver android:name=".PerfData$PerfAlarmReceiver"/>
</application>
</manifest>
diff --git a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
index 82964ab1d821..1e28f6730709 100644
--- a/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
+++ b/cmds/statsd/tools/loadtest/res/layout/activity_loadtest.xml
@@ -166,12 +166,6 @@
android:layout_height="wrap_content"
android:text="@string/display_output"
android:textSize="30dp"/>
- <Button
- android:id="@+id/display_perf"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/display_perf"
- android:textSize="30dp"/>
<Space
android:layout_width="1dp"
@@ -179,6 +173,7 @@
<TextView
android:id="@+id/report_text"
+ android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
diff --git a/cmds/statsd/tools/loadtest/res/values/strings.xml b/cmds/statsd/tools/loadtest/res/values/strings.xml
index 991350332da0..cb38298873f0 100644
--- a/cmds/statsd/tools/loadtest/res/values/strings.xml
+++ b/cmds/statsd/tools/loadtest/res/values/strings.xml
@@ -21,7 +21,6 @@
<string name="bucket_label">bucket size (mins):&#160;</string>
<string name="burst_label">burst:&#160;</string>
<string name="display_output">Show metrics data</string>
- <string name="display_perf">Show perf data</string>
<string name="placebo">placebo</string>
<string name="period_label">logging period (secs):&#160;</string>
<string name="replication_label">metric replication:&#160;</string>
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
new file mode 100644
index 000000000000..d2ff892680a7
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryDataRecorder.java
@@ -0,0 +1,53 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.Log;
+import java.text.ParseException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class BatteryDataRecorder extends PerfDataRecorder {
+ private static final String TAG = "loadtest.BatteryDataRecorder";
+ private static final String DUMP_FILENAME = TAG + "_dump.tmp";
+
+ public BatteryDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ // Reset batterystats.
+ runDumpsysStats(context, DUMP_FILENAME, "batterystats", "--reset");
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ // Nothing to do as for battery, the whole data is in the final dumpsys call.
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ StringBuilder sb = new StringBuilder();
+ // Don't use --checkin.
+ runDumpsysStats(context, DUMP_FILENAME, "batterystats");
+ readDumpData(context, DUMP_FILENAME, new BatteryStatsParser(), sb);
+ writeData(context, "battery_", "time,battery_level", sb);
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
index 96e6bef600d1..203d97acefd8 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/BatteryStatsParser.java
@@ -21,13 +21,13 @@ import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class BatteryStatsParser {
+public class BatteryStatsParser implements PerfParser {
private static final Pattern LINE_PATTERN =
Pattern.compile("\\s*\\+*(\\S*)\\s\\(\\d+\\)\\s(\\d\\d\\d)\\s.*");
private static final Pattern TIME_PATTERN =
Pattern.compile("(\\d+)?(h)?(\\d+)?(m)?(\\d+)?(s)?(\\d+)?(ms)?");
- private static final String TAG = "BatteryStatsParser";
+ private static final String TAG = "loadtest.BatteryStatsParser";
private boolean mHistoryStarted;
private boolean mHistoryEnded;
@@ -35,6 +35,7 @@ public class BatteryStatsParser {
public BatteryStatsParser() {
}
+ @Override
@Nullable
public String parseLine(String line) {
if (mHistoryEnded) {
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
index 8d20f9759c96..95a592b58211 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
@@ -18,7 +18,6 @@ package com.android.statsd.loadtest;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
-import android.util.StatsLog;
import com.android.internal.os.StatsdConfigProto.Bucket;
import com.android.internal.os.StatsdConfigProto.Predicate;
@@ -45,7 +44,7 @@ import java.util.List;
public class ConfigFactory {
public static final String CONFIG_NAME = "LOADTEST";
- private static final String TAG = "ConfigFactory";
+ private static final String TAG = "loadtest.ConfigFactory";
private final StatsdConfig mTemplate;
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
index 3ae85a7d0bf2..522dea61d188 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/LoadtestActivity.java
@@ -65,8 +65,9 @@ import android.widget.Toast;
public class LoadtestActivity extends Activity {
private static final String TAG = "StatsdLoadtest";
- private static final String TYPE = "type";
- private static final String ALARM = "push_alarm";
+ public static final String TYPE = "type";
+ private static final String PUSH_ALARM = "push_alarm";
+ public static final String PERF_ALARM = "perf_alarm";
private static final String START = "start";
private static final String STOP = "stop";
@@ -74,7 +75,7 @@ public class LoadtestActivity extends Activity {
@Override
public void onReceive(Context context, Intent intent) {
Intent activityIntent = new Intent(context, LoadtestActivity.class);
- activityIntent.putExtra(TYPE, ALARM);
+ activityIntent.putExtra(TYPE, PUSH_ALARM);
context.startActivity(activityIntent);
}
}
@@ -105,6 +106,9 @@ public class LoadtestActivity extends Activity {
private TextView mReportText;
private CheckBox mPlaceboCheckBox;
+ /** When the load test started. */
+ private long mStartedTimeMillis;
+
/** For measuring perf data. */
private PerfData mPerfData;
@@ -180,7 +184,7 @@ public class LoadtestActivity extends Activity {
@Override
public void onClick(View view) {
if (mStarted) {
- stopLoadtest(true);
+ stopLoadtest();
} else {
startLoadtest();
}
@@ -194,20 +198,11 @@ public class LoadtestActivity extends Activity {
}
});
- findViewById(R.id.display_perf).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mPerfData.publishData(LoadtestActivity.this, mPlacebo, mReplication, mBucketMins,
- mPeriodSecs, mBurst);
- }
- });
-
mAlarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mStatsManager = (StatsManager) getSystemService("stats");
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mFactory = new ConfigFactory(this);
- mPerfData = new PerfData();
- stopLoadtest(false);
+ stopLoadtest();
mReportText.setText("");
}
@@ -218,14 +213,17 @@ public class LoadtestActivity extends Activity {
return;
}
switch (type) {
- case ALARM:
- onAlarm(intent);
- break;
+ case PERF_ALARM:
+ onPerfAlarm();
+ break;
+ case PUSH_ALARM:
+ onAlarm();
+ break;
case START:
startLoadtest();
break;
- case STOP:
- stopLoadtest(true);
+ case STOP:
+ stopLoadtest();
break;
default:
throw new IllegalArgumentException("Unknown type: " + type);
@@ -235,12 +233,23 @@ public class LoadtestActivity extends Activity {
@Override
public void onDestroy() {
Log.d(TAG, "Destroying");
- stopLoadtest(false);
+ mPerfData.onDestroy();
+ stopLoadtest();
clearConfigs();
super.onDestroy();
}
- private void onAlarm(Intent intent) {
+ private void onPerfAlarm() {
+ if (mPerfData != null) {
+ mPerfData.onAlarm(this);
+ }
+ // Piggy-back on that alarm to show the elapsed time.
+ long elapsedTimeMins = (long) Math.floor(
+ (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+ mReportText.setText("Loadtest in progress. Elapsed time = " + elapsedTimeMins + " min(s)");
+ }
+
+ private void onAlarm() {
Log.d(TAG, "ON ALARM");
// Set the next task.
@@ -259,7 +268,7 @@ public class LoadtestActivity extends Activity {
/** Schedules the next cycle of pushing atoms into logd. */
private void scheduleNext() {
Intent intent = new Intent(this, PusherAlarmReceiver.class);
- intent.putExtra(TYPE, ALARM);
+ intent.putExtra(TYPE, PUSH_ALARM);
mPushPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
long nextTime = SystemClock.elapsedRealtime() + mPeriodSecs * 1000;
mAlarmMgr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, mPushPendingIntent);
@@ -271,7 +280,7 @@ public class LoadtestActivity extends Activity {
}
// Clean up the state.
- stopLoadtest(false);
+ stopLoadtest();
// Prepare to push a sequence of atoms to logd.
mPusher = new SequencePusher(mBurst, mPlacebo);
@@ -291,15 +300,17 @@ public class LoadtestActivity extends Activity {
// Log atoms.
scheduleNext();
- // Reset battery data.
- mPerfData.resetData(this);
+ // Start tracking performance.
+ mPerfData = new PerfData(this, mPlacebo, mReplication, mBucketMins, mPeriodSecs, mBurst);
+ mPerfData.startRecording(this);
- mReportText.setText("");
+ mReportText.setText("Loadtest in progress.");
+ mStartedTimeMillis = SystemClock.elapsedRealtime();
updateStarted(true);
}
- private synchronized void stopLoadtest(boolean publishPerfData) {
+ private synchronized void stopLoadtest() {
if (mPushPendingIntent != null) {
Log.d(TAG, "Canceling pre-existing push alarm");
mAlarmMgr.cancel(mPushPendingIntent);
@@ -314,12 +325,17 @@ public class LoadtestActivity extends Activity {
mWakeLock.release();
mWakeLock = null;
}
- fetchAndDisplayData();
+ if (mPerfData != null) {
+ mPerfData.stopRecording(this);
+ mPerfData.onDestroy();
+ mPerfData = null;
+ }
+
+ long elapsedTimeMins = (long) Math.floor(
+ (SystemClock.elapsedRealtime() - mStartedTimeMillis) / 60 / 1000);
+ mReportText.setText("Loadtest ended. Elapsed time = " + elapsedTimeMins + " min(s)");
clearConfigs();
updateStarted(false);
- if (publishPerfData) {
- mPerfData.publishData(this, mPlacebo, mReplication, mBucketMins, mPeriodSecs, mBurst);
- }
}
private synchronized void updateStarted(boolean started) {
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
new file mode 100644
index 000000000000..01eebf2ad1cf
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemInfoParser.java
@@ -0,0 +1,69 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.util.Log;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Parses PSS info from dumpsys meminfo */
+public class MemInfoParser implements PerfParser {
+
+ private static final Pattern LINE_PATTERN =
+ Pattern.compile("\\s*(\\d*,*\\d*)K:\\s(\\S*)\\s\\.*");
+ private static final String PSS_BY_PROCESS = "Total PSS by process:";
+ private static final String TAG = "loadtest.MemInfoParser";
+
+ private boolean mPssStarted;
+ private boolean mPssEnded;
+ private final long mStartTimeMillis;
+
+ public MemInfoParser(long startTimeMillis) {
+ mStartTimeMillis = startTimeMillis;
+ }
+
+ @Override
+ @Nullable
+ public String parseLine(String line) {
+ if (mPssEnded) {
+ return null;
+ }
+ if (!mPssStarted) {
+ if (line.contains(PSS_BY_PROCESS)) {
+ mPssStarted = true;
+ }
+ return null;
+ }
+ if (line.isEmpty()) {
+ mPssEnded = true;
+ return null;
+ }
+ Matcher lineMatcher = LINE_PATTERN.matcher(line);
+ if (lineMatcher.find() && lineMatcher.group(1) != null && lineMatcher.group(2) != null) {
+ if (lineMatcher.group(2).equals("statsd")) {
+ long timeDeltaMillis = SystemClock.elapsedRealtime() - mStartTimeMillis;
+ return timeDeltaMillis + "," + convertToPss(lineMatcher.group(1));
+ }
+ }
+ return null;
+ }
+
+ private String convertToPss(String input) {
+ return input.replace(",", "");
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
new file mode 100644
index 000000000000..d82a0eadea65
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/MemoryDataRecorder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class MemoryDataRecorder extends PerfDataRecorder {
+ private static final String TAG = "loadtest.MemoryDataDataRecorder";
+ private static final String DUMP_FILENAME = TAG + "_dump.tmp";
+
+ private long mStartTimeMillis;
+ private StringBuilder mSb;
+
+ public MemoryDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ }
+
+ @Override
+ public void startRecording(Context context) {
+ mStartTimeMillis = SystemClock.elapsedRealtime();
+ mSb = new StringBuilder();
+ }
+
+ @Override
+ public void onAlarm(Context context) {
+ Log.d(TAG, "GOT ALARM IN MEM");
+ runDumpsysStats(context, DUMP_FILENAME, "meminfo");
+ readDumpData(context, DUMP_FILENAME, new MemInfoParser(mStartTimeMillis), mSb);
+ }
+
+ @Override
+ public void stopRecording(Context context) {
+ writeData(context, "meminfo_", "time,pss", mSb);
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
index 57f85b5db317..81a84f53b503 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/NumericalWatcher.java
@@ -15,29 +15,14 @@
*/
package com.android.statsd.loadtest;
-import android.app.Activity;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
-import android.util.StatsLog;
-import android.util.StatsManager;
-import android.view.View;
-import android.widget.EditText;
import android.widget.TextView;
-import android.widget.Toast;
-import android.os.IStatsManager;
-import android.os.ServiceManager;
-import android.view.View.OnFocusChangeListener;
public abstract class NumericalWatcher implements TextWatcher {
- private static final String TAG = "NumericalWatcher";
+ private static final String TAG = "loadtest.NumericalWatcher";
private final TextView mTextView;
private final int mMin;
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
index e3e23f58a26f..466524756c48 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfData.java
@@ -16,147 +16,86 @@
package com.android.statsd.loadtest;
import android.annotation.Nullable;
-import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
+import android.os.SystemClock;
import android.util.Log;
-import android.os.Debug;
-
-import java.io.BufferedReader;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
+
+import java.util.HashSet;
+import java.util.Set;
/** Prints some information about the device via Dumpsys in order to evaluate health metrics. */
-public class PerfData {
+public class PerfData extends PerfDataRecorder {
- private static final String TAG = "PerfData";
- private static final String DUMP_FILENAME = TAG + "_dump.tmp";
+ private static final String TAG = "loadtest.PerfData";
- public void resetData(Context context) {
- runDumpsysStats(context, "batterystats", "--reset");
- }
+ /** Polling period for performance snapshots like memory. */
+ private static final long POLLING_PERIOD_MILLIS = 1 * 60 * 1000;
- public void publishData(Context context, boolean placebo, int replication, long bucketMins,
- long periodSecs, int burst) {
- publishBatteryData(context, placebo, replication, bucketMins, periodSecs, burst);
+ public final static class PerfAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent activityIntent = new Intent(context, LoadtestActivity.class);
+ activityIntent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
+ context.startActivity(activityIntent);
+ }
}
- private void publishBatteryData(Context context, boolean placebo, int replication,
- long bucketMins, long periodSecs, int burst) {
- // Don't use --checkin.
- runDumpsysStats(context, "batterystats");
- writeBatteryData(context, placebo, replication, bucketMins, periodSecs, burst);
- }
+ private AlarmManager mAlarmMgr;
- private void runDumpsysStats(Context context, String cmd, String... args) {
- boolean success = false;
- // Call dumpsys Dump statistics to a file.
- FileOutputStream fo = null;
- try {
- fo = context.openFileOutput(DUMP_FILENAME, Context.MODE_PRIVATE);
- if (!Debug.dumpService(cmd, fo.getFD(), args)) {
- Log.w(TAG, "Dumpsys failed.");
- }
- success = true;
- } catch (IOException | SecurityException | NullPointerException e) {
- // SecurityException may occur when trying to dump multi-user info.
- // NPE can occur during dumpService (root cause unknown).
- throw new RuntimeException(e);
- } finally {
- closeQuietly(fo);
- }
+ /** Used to periodically poll some dumpsys data. */
+ private PendingIntent mPendingIntent;
+
+ private final Set<PerfDataRecorder> mRecorders;
+
+ public PerfData(Context context, boolean placebo, int replication, long bucketMins,
+ long periodSecs, int burst) {
+ super(placebo, replication, bucketMins, periodSecs, burst);
+ mRecorders = new HashSet();
+ mRecorders.add(new BatteryDataRecorder(placebo, replication, bucketMins, periodSecs, burst));
+ mRecorders.add(new MemoryDataRecorder(placebo, replication, bucketMins, periodSecs, burst));
+ mAlarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
- private String readDumpFile(Context context) {
- StringBuilder sb = new StringBuilder();
- FileInputStream fi = null;
- BufferedReader br = null;
- try {
- fi = context.openFileInput(DUMP_FILENAME);
- br = new BufferedReader(new InputStreamReader(fi));
- String line = br.readLine();
- while (line != null) {
- sb.append(line);
- sb.append(System.lineSeparator());
- line = br.readLine();
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- closeQuietly(br);
+ public void onDestroy() {
+ if (mPendingIntent != null) {
+ mAlarmMgr.cancel(mPendingIntent);
+ mPendingIntent = null;
}
- return sb.toString();
}
- private static void closeQuietly(@Nullable Closeable c) {
- if (c != null) {
- try {
- c.close();
- } catch (IOException ignore) {
- }
+ @Override
+ public void startRecording(Context context) {
+ Intent intent = new Intent(context, PerfAlarmReceiver.class);
+ intent.putExtra(LoadtestActivity.TYPE, LoadtestActivity.PERF_ALARM);
+ mPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
+ mAlarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, -1 /* now */,
+ POLLING_PERIOD_MILLIS, mPendingIntent);
+
+ for (PerfDataRecorder recorder : mRecorders) {
+ recorder.startRecording(context);
}
}
- public void writeBatteryData(Context context, boolean placebo, int replication, long bucketMins,
- long periodSecs, int burst) {
- BatteryStatsParser parser = new BatteryStatsParser();
- FileInputStream fi = null;
- BufferedReader br = null;
- String suffix = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
- File batteryDataFile = new File(getStorageDir(), "battery_" + suffix + ".csv");
- Log.d(TAG, "Writing battery data to " + batteryDataFile.getAbsolutePath());
-
- FileWriter writer = null;
- try {
- fi = context.openFileInput(DUMP_FILENAME);
- writer = new FileWriter(batteryDataFile);
- writer.append("time,battery_level"
- + getColumnName(placebo, replication, bucketMins, periodSecs, burst) + "\n");
- br = new BufferedReader(new InputStreamReader(fi));
- String line = br.readLine();
- while (line != null) {
- String recordLine = parser.parseLine(line);
- if (recordLine != null) {
- writer.append(recordLine);
- }
- line = br.readLine();
- }
- writer.flush();
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- closeQuietly(writer);
- closeQuietly(br);
+ @Override
+ public void onAlarm(Context context) {
+ for (PerfDataRecorder recorder : mRecorders) {
+ recorder.onAlarm(context);
}
}
- private File getStorageDir() {
- File file = new File(Environment.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOCUMENTS), "loadtest");
- if (!file.mkdirs()) {
- Log.e(TAG, "Directory not created");
+ @Override
+ public void stopRecording(Context context) {
+ if (mPendingIntent != null) {
+ mAlarmMgr.cancel(mPendingIntent);
+ mPendingIntent = null;
}
- return file;
- }
- private String getColumnName(boolean placebo, int replication, long bucketMins, long periodSecs,
- int burst) {
- if (placebo) {
- return "_placebo_p=" + periodSecs;
+ for (PerfDataRecorder recorder : mRecorders) {
+ recorder.stopRecording(context);
}
- return "_r=" + replication + "_bkt=" + bucketMins + "_p=" + periodSecs + "_bst=" + burst;
}
}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
new file mode 100644
index 000000000000..15a8e5c87131
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfDataRecorder.java
@@ -0,0 +1,149 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Environment;
+import android.util.Log;
+import android.os.Debug;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public abstract class PerfDataRecorder {
+ private static final String TAG = "loadtest.PerfDataRecorder";
+
+ protected final String mFileSuffix;
+ protected final String mColumnSuffix;
+
+ protected PerfDataRecorder(boolean placebo, int replication, long bucketMins, long periodSecs,
+ int burst) {
+ mFileSuffix = new SimpleDateFormat("YYYY_MM_dd_HH_mm_ss").format(new Date());
+ mColumnSuffix = getColumnSuffix(placebo, replication, bucketMins, periodSecs, burst);
+ }
+
+ /** Starts recording performance data. */
+ public abstract void startRecording(Context context);
+
+ /** Called periodically. For the recorder to sample data, if needed. */
+ public abstract void onAlarm(Context context);
+
+ /** Stops recording performance data, and writes it to disk. */
+ public abstract void stopRecording(Context context);
+
+ /** Runs the dumpsys command. */
+ protected void runDumpsysStats(Context context, String dumpFilename, String cmd,
+ String... args) {
+ boolean success = false;
+ // Call dumpsys Dump statistics to a file.
+ FileOutputStream fo = null;
+ try {
+ fo = context.openFileOutput(dumpFilename, Context.MODE_PRIVATE);
+ if (!Debug.dumpService(cmd, fo.getFD(), args)) {
+ Log.w(TAG, "Dumpsys failed.");
+ }
+ success = true;
+ } catch (IOException | SecurityException | NullPointerException e) {
+ // SecurityException may occur when trying to dump multi-user info.
+ // NPE can occur during dumpService (root cause unknown).
+ throw new RuntimeException(e);
+ } finally {
+ closeQuietly(fo);
+ }
+ }
+
+ /**
+ * Reads a text file and parses each line, one by one. The result of the parsing is stored
+ * in the passed {@link StringBuffer}.
+ */
+ protected void readDumpData(Context context, String dumpFilename, PerfParser parser,
+ StringBuilder sb) {
+ FileInputStream fi = null;
+ BufferedReader br = null;
+ try {
+ fi = context.openFileInput(dumpFilename);
+ br = new BufferedReader(new InputStreamReader(fi));
+ String line = br.readLine();
+ while (line != null) {
+ String recordLine = parser.parseLine(line);
+ if (recordLine != null) {
+ sb.append(recordLine).append('\n');
+ }
+ line = br.readLine();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ closeQuietly(br);
+ }
+ }
+
+ /** Writes CSV data to a file. */
+ protected void writeData(Context context, String filePrefix, String columnPrefix,
+ StringBuilder sb) {
+ File dataFile = new File(getStorageDir(), filePrefix + mFileSuffix + ".csv");
+
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(dataFile);
+ writer.append(columnPrefix + mColumnSuffix + "\n");
+ writer.append(sb.toString());
+ writer.flush();
+ Log.d(TAG, "Finished writing data at " + dataFile.getAbsolutePath());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ closeQuietly(writer);
+ }
+ }
+
+ /** Gets the suffix to use in the column name for perf data. */
+ private String getColumnSuffix(boolean placebo, int replication, long bucketMins,
+ long periodSecs, int burst) {
+ if (placebo) {
+ return "_placebo_p=" + periodSecs;
+ }
+ return "_r=" + replication + "_bkt=" + bucketMins + "_p=" + periodSecs + "_bst=" + burst;
+ }
+
+
+ private File getStorageDir() {
+ File file = new File(Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOCUMENTS), "loadtest");
+ if (!file.mkdirs()) {
+ Log.e(TAG, "Directory not created");
+ }
+ return file;
+ }
+
+ private void closeQuietly(@Nullable Closeable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+}
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
new file mode 100644
index 000000000000..e000918fa0f7
--- /dev/null
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/PerfParser.java
@@ -0,0 +1,27 @@
+/*
+ * 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.statsd.loadtest;
+
+import android.annotation.Nullable;
+
+public interface PerfParser {
+
+ /**
+ * Parses one line of the dumpsys output, and returns a string to write to the data file,
+ * or null if no string should be written.
+ */
+ @Nullable String parseLine(String line);
+}