Merge "New framework performance tests." into ics-mr1
diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk
new file mode 100644
index 0000000..03893d6
--- /dev/null
+++ b/tests/FrameworkPerf/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := FrameworkPerf
+
+LOCAL_AAPT_FLAGS = -c 120dpi,240dpi,160dpi,161dpi,320dpi,nodpi
+
+include $(BUILD_PACKAGE)
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
new file mode 100644
index 0000000..f69d550
--- /dev/null
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworkperf">
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-sdk android:minSdkVersion="5" />
+
+ <application>
+ <activity android:name="FrameworkPerfActivity" android:label="Framework Perf">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <service android:name="SchedulerService">
+ </service>
+ </application>
+</manifest>
diff --git a/tests/FrameworkPerf/res/drawable-161dpi/stat_sample_scale.png b/tests/FrameworkPerf/res/drawable-161dpi/stat_sample_scale.png
new file mode 100755
index 0000000..6c9ba0a
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-161dpi/stat_sample_scale.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-161dpi/wallpaper_goldengate_scale.jpg b/tests/FrameworkPerf/res/drawable-161dpi/wallpaper_goldengate_scale.jpg
new file mode 100644
index 0000000..2271091
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-161dpi/wallpaper_goldengate_scale.jpg
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-hdpi/stat_happy.png b/tests/FrameworkPerf/res/drawable-hdpi/stat_happy.png
new file mode 100755
index 0000000..27f5bb7
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-hdpi/stat_happy.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-mdpi/stat_happy.png b/tests/FrameworkPerf/res/drawable-mdpi/stat_happy.png
new file mode 100644
index 0000000..3a8791b
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-mdpi/stat_happy.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-nodpi/stat_sample.png b/tests/FrameworkPerf/res/drawable-nodpi/stat_sample.png
new file mode 100755
index 0000000..6c9ba0a
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-nodpi/stat_sample.png
Binary files differ
diff --git a/tests/FrameworkPerf/res/drawable-nodpi/wallpaper_goldengate.jpg b/tests/FrameworkPerf/res/drawable-nodpi/wallpaper_goldengate.jpg
new file mode 100644
index 0000000..2271091
--- /dev/null
+++ b/tests/FrameworkPerf/res/drawable-nodpi/wallpaper_goldengate.jpg
Binary files differ
diff --git a/tests/FrameworkPerf/res/layout/main.xml b/tests/FrameworkPerf/res/layout/main.xml
new file mode 100644
index 0000000..2e9c500
--- /dev/null
+++ b/tests/FrameworkPerf/res/layout/main.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <Button android:id="@+id/start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start"
+ />
+ <Button android:id="@+id/stop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/stop"
+ />
+ </LinearLayout>
+
+ <ScrollView android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ >
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+ </ScrollView>
+
+</LinearLayout>
diff --git a/tests/FrameworkPerf/res/values/attrs.xml b/tests/FrameworkPerf/res/values/attrs.xml
new file mode 100644
index 0000000..5823537
--- /dev/null
+++ b/tests/FrameworkPerf/res/values/attrs.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<resources>
+ <!-- Base attributes that are available to all Item objects. -->
+ <declare-styleable name="MenuItem">
+
+ <!-- The ID of the item. -->
+ <attr name="android:id" />
+
+ <!-- The category applied to the item.
+ (This will be or'ed with the orderInCategory attribute.) -->
+ <attr name="android:menuCategory" />
+
+ <!-- The order within the category applied to the item.
+ (This will be or'ed with the category attribute.) -->
+ <attr name="android:orderInCategory" />
+
+ <!-- The title associated with the item. -->
+ <attr name="android:title" />
+
+ <!-- The condensed title associated with the item. This is used in situations where the
+ normal title may be too long to be displayed. -->
+ <attr name="android:titleCondensed" />
+
+ <!-- The icon associated with this item. This icon will not always be shown, so
+ the title should be sufficient in describing this item. -->
+ <attr name="android:icon" />
+
+ <!-- The alphabetic shortcut key. This is the shortcut when using a keyboard
+ with alphabetic keys. -->
+ <attr name="android:alphabeticShortcut" />
+
+ <!-- The numeric shortcut key. This is the shortcut when using a numeric (e.g., 12-key)
+ keyboard. -->
+ <attr name="android:numericShortcut" />
+
+ <!-- Whether the item is capable of displaying a check mark. -->
+ <attr name="android:checkable" />
+
+ <!-- Whether the item is checked. Note that you must first have enabled checking with
+ the checkable attribute or else the check mark will not appear. -->
+ <attr name="android:checked" />
+
+ <!-- Whether the item is shown/visible. -->
+ <attr name="android:visible" />
+
+ <!-- Whether the item is enabled. -->
+ <attr name="android:enabled" />
+ </declare-styleable>
+</resources>
diff --git a/tests/FrameworkPerf/res/values/strings.xml b/tests/FrameworkPerf/res/values/strings.xml
new file mode 100644
index 0000000..82fd713
--- /dev/null
+++ b/tests/FrameworkPerf/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<resources>
+ <string name="start">Start</string>
+ <string name="stop">Stop</string>
+ <string name="data_usage_menu_roaming">Data roaming</string>
+ <string name="data_usage_menu_restrict_background">Restrict background data</string>
+ <string name="data_usage_menu_split_4g">Separate 4G usage</string>
+ <string name="data_usage_menu_show_wifi">Show Wi-Fi usage</string>
+ <string name="data_usage_menu_show_ethernet">Show Ethernet usage</string>
+</resources>
diff --git a/tests/FrameworkPerf/res/xml/simple.xml b/tests/FrameworkPerf/res/xml/simple.xml
new file mode 100644
index 0000000..4e938aa
--- /dev/null
+++ b/tests/FrameworkPerf/res/xml/simple.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/data_usage_menu_roaming"
+ android:title="@string/data_usage_menu_roaming"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_restrict_background"
+ android:title="@string/data_usage_menu_restrict_background"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_split_4g"
+ android:title="@string/data_usage_menu_split_4g"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_show_wifi"
+ android:title="@string/data_usage_menu_show_wifi"
+ android:checkable="true" />
+ <item
+ android:id="@+id/data_usage_menu_show_ethernet"
+ android:title="@string/data_usage_menu_show_ethernet"
+ android:checkable="true" />
+</menu>
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
new file mode 100644
index 0000000..9f05a55
--- /dev/null
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/FrameworkPerfActivity.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2011 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.frameworkperf;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * So you thought sync used up your battery life.
+ */
+public class FrameworkPerfActivity extends Activity {
+ final Handler mHandler = new Handler();
+
+ TextView mLog;
+ PowerManager.WakeLock mPartialWakeLock;
+
+ long mMaxRunTime = 5000;
+ boolean mStarted;
+
+ final TestRunner mRunner = new TestRunner();
+
+ final Op[] mOpPairs = new Op[] {
+ new MethodCallOp(), new NoOp(),
+ new MethodCallOp(), new CpuOp(),
+ new MethodCallOp(), new SchedulerOp(),
+ new MethodCallOp(), new GcOp(),
+ new SchedulerOp(), new SchedulerOp(),
+ new GcOp(), new NoOp(),
+ new IpcOp(), new NoOp(),
+ new IpcOp(), new CpuOp(),
+ new IpcOp(), new SchedulerOp(),
+ new IpcOp(), new GcOp(),
+ new ParseXmlResOp(), new NoOp(),
+ new ParseLargeXmlResOp(), new NoOp(),
+ new LayoutInflaterOp(), new NoOp(),
+ new LayoutInflaterLargeOp(), new NoOp(),
+ new LoadSmallBitmapOp(), new NoOp(),
+ new LoadLargeBitmapOp(), new NoOp(),
+ new LoadSmallScaledBitmapOp(), new NoOp(),
+ new LoadLargeScaledBitmapOp(), new NoOp(),
+ };
+
+ final Op[] mAvailOps = new Op[] {
+ new NoOp(),
+ new CpuOp(),
+ new SchedulerOp(),
+ new MethodCallOp(),
+ new IpcOp(),
+ new ParseXmlResOp(),
+ new ParseLargeXmlResOp(),
+ new LoadSmallBitmapOp(),
+ new LoadLargeBitmapOp(),
+ new LoadSmallScaledBitmapOp(),
+ new LoadLargeScaledBitmapOp(),
+ };
+
+ int mCurOpIndex = 0;
+
+ class RunResult {
+ final String name;
+ final String fgLongName;
+ final String bgLongName;
+ final long fgTime;
+ final long fgOps;
+ final long bgTime;
+ final long bgOps;
+
+ RunResult(TestRunner op) {
+ name = op.getName();
+ fgLongName = op.getForegroundLongName();
+ bgLongName = op.getBackgroundLongName();
+ fgTime = op.getForegroundTime();
+ fgOps = op.getForegroundOps();
+ bgTime = op.getBackgroundTime();
+ bgOps = op.getBackgroundOps();
+ }
+
+ float getFgMsPerOp() {
+ return fgOps != 0 ? (fgTime / (float)fgOps) : 0;
+ }
+
+ float getBgMsPerOp() {
+ return bgOps != 0 ? (bgTime / (float)bgOps) : 0;
+ }
+ }
+
+ final ArrayList<RunResult> mResults = new ArrayList<RunResult>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set the layout for this activity. You can find it
+ // in res/layout/hello_activity.xml
+ setContentView(R.layout.main);
+
+ findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
+ @Override public void onClick(View v) {
+ startRunning();
+ }
+ });
+ findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
+ @Override public void onClick(View v) {
+ stopRunning();
+ }
+ });
+ mLog = (TextView)findViewById(R.id.log);
+
+ PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
+ mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Scheduler");
+ mPartialWakeLock.setReferenceCounted(false);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ stopRunning();
+ if (mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.release();
+ }
+ }
+
+ void startCurOp() {
+ mRunner.run(mHandler, mOpPairs[mCurOpIndex], mOpPairs[mCurOpIndex+1], new Runnable() {
+ @Override public void run() {
+ RunResult result = new RunResult(mRunner);
+ log(String.format("%s: fg=%d*%gms/op (%dms) / bg=%d*%gms/op (%dms)",
+ result.name, result.fgOps, result.getFgMsPerOp(), result.fgTime,
+ result.bgOps, result.getBgMsPerOp(), result.bgTime));
+ mResults.add(result);
+ if (!mStarted) {
+ log("Stop");
+ stopRunning();
+ return;
+ }
+ mCurOpIndex+=2;
+ if (mCurOpIndex >= mOpPairs.length) {
+ log("Finished");
+ stopRunning();
+ return;
+ }
+ startCurOp();
+ }
+ });
+ }
+
+ void startRunning() {
+ if (!mStarted) {
+ log("Start");
+ mStarted = true;
+ updateWakeLock();
+ startService(new Intent(this, SchedulerService.class));
+ mCurOpIndex = 0;
+ mResults.clear();
+ startCurOp();
+ }
+ }
+
+ void stopRunning() {
+ if (mStarted) {
+ mStarted = false;
+ updateWakeLock();
+ stopService(new Intent(this, SchedulerService.class));
+ for (int i=0; i<mResults.size(); i++) {
+ RunResult result = mResults.get(i);
+ float fgMsPerOp = result.getFgMsPerOp();
+ float bgMsPerOp = result.getBgMsPerOp();
+ String fgMsPerOpStr = fgMsPerOp != 0 ? Float.toString(fgMsPerOp) : "";
+ String bgMsPerOpStr = bgMsPerOp != 0 ? Float.toString(bgMsPerOp) : "";
+ Log.i("Perf", "\t" + result.name + "\t" + result.fgOps
+ + "\t" + result.getFgMsPerOp() + "\t" + result.fgTime
+ + "\t" + result.fgLongName + "\t" + result.bgOps
+ + "\t" + result.getBgMsPerOp() + "\t" + result.bgTime
+ + "\t" + result.bgLongName);
+ }
+ }
+ }
+
+ void updateWakeLock() {
+ if (mStarted) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (!mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.acquire();
+ }
+ } else {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ if (mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.release();
+ }
+ }
+ }
+
+ void log(String s) {
+ mLog.setText(mLog.getText() + "\n" + s);
+ Log.i("Perf", s);
+ }
+
+ enum BackgroundMode {
+ NOTHING,
+ CPU,
+ SCHEDULER
+ };
+
+ public class TestRunner {
+ Handler mHandler;
+ Op mForegroundOp;
+ Op mBackgroundOp;
+ Runnable mDoneCallback;
+
+ RunnerThread mBackgroundThread;
+ RunnerThread mForegroundThread;
+ long mStartTime;
+
+ boolean mBackgroundRunning;
+ boolean mForegroundRunning;
+
+ long mBackgroundEndTime;
+ long mBackgroundOps;
+ long mForegroundEndTime;
+ long mForegroundOps;
+
+ public TestRunner() {
+ }
+
+ public String getForegroundName() {
+ return mForegroundOp.getName();
+ }
+
+ public String getBackgroundName() {
+ return mBackgroundOp.getName();
+ }
+
+ public String getName() {
+ String fgName = mForegroundOp.getName();
+ String bgName = mBackgroundOp.getName();
+ StringBuilder res = new StringBuilder();
+ if (fgName != null) {
+ res.append(fgName);
+ res.append("Fg");
+ }
+ if (bgName != null) {
+ res.append(bgName);
+ res.append("Bg");
+ }
+ return res.toString();
+ }
+
+ public String getForegroundLongName() {
+ return mForegroundOp.getLongName();
+ }
+
+ public String getBackgroundLongName() {
+ return mBackgroundOp.getLongName();
+ }
+
+ public void run(Handler handler, Op foreground, Op background, Runnable doneCallback) {
+ mHandler = handler;
+ mForegroundOp = foreground;
+ mBackgroundOp = background;
+ mDoneCallback = doneCallback;
+ mBackgroundThread = new RunnerThread("background", new Runnable() {
+ @Override public void run() {
+ boolean running;
+ int ops = 0;
+ do {
+ running = mBackgroundOp.onRun();
+ ops++;
+ } while (evalRepeat(running, true) && running);
+ mBackgroundEndTime = SystemClock.uptimeMillis();
+ mBackgroundOps = ops * mBackgroundOp.getOpsPerRun();
+ threadFinished(false);
+ }
+ }, Process.THREAD_PRIORITY_BACKGROUND);
+ mForegroundThread = new RunnerThread("background", new Runnable() {
+ @Override public void run() {
+ boolean running;
+ int ops = 0;
+ do {
+ running = mForegroundOp.onRun();
+ ops++;
+ } while (evalRepeat(true, running) && running);
+ mForegroundEndTime = SystemClock.uptimeMillis();
+ mForegroundOps = ops * mForegroundOp.getOpsPerRun();
+ threadFinished(true);
+ }
+ }, Process.THREAD_PRIORITY_FOREGROUND);
+
+ mForegroundOp.onInit(FrameworkPerfActivity.this);
+ mBackgroundOp.onInit(FrameworkPerfActivity.this);
+
+ synchronized (this) {
+ mStartTime = SystemClock.uptimeMillis();
+ mBackgroundRunning = true;
+ mForegroundRunning = true;
+ }
+
+ mBackgroundThread.start();
+ mForegroundThread.start();
+ }
+
+ public long getForegroundTime() {
+ return mForegroundEndTime-mStartTime;
+ }
+
+ public long getForegroundOps() {
+ return mForegroundOps;
+ }
+
+ public long getBackgroundTime() {
+ return mBackgroundEndTime-mStartTime;
+ }
+
+ public long getBackgroundOps() {
+ return mBackgroundOps;
+ }
+
+ private boolean evalRepeat(boolean bgRunning, boolean fgRunning) {
+ synchronized (this) {
+ if (!bgRunning) {
+ mBackgroundRunning = false;
+ }
+ if (!fgRunning) {
+ mForegroundRunning = false;
+ }
+ if (!mBackgroundRunning && !mForegroundRunning) {
+ return false;
+ }
+ long now = SystemClock.uptimeMillis();
+ if (now > (mStartTime+mMaxRunTime)) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private void threadFinished(boolean foreground) {
+ synchronized (this) {
+ if (foreground) {
+ mForegroundRunning = false;
+ } else {
+ mBackgroundRunning = false;
+ }
+ if (!mBackgroundRunning && !mForegroundRunning) {
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ if (mDoneCallback != null) {
+ mDoneCallback.run();
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ class RunnerThread extends Thread {
+ private final Runnable mOp;
+ private final int mPriority;
+
+ RunnerThread(String name, Runnable op, int priority) {
+ super(name);
+ mOp = op;
+ mPriority = priority;
+ }
+
+ public void run() {
+ Process.setThreadPriority(mPriority);
+ mOp.run();
+ }
+ }
+
+ static public abstract class Op {
+ final String mName;
+ final String mLongName;
+
+ public Op(String name, String longName) {
+ mName = name;
+ mLongName = longName;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getLongName() {
+ return mLongName;
+ }
+
+ void onInit(Context context) {
+ }
+
+ abstract boolean onRun();
+
+ int getOpsPerRun() {
+ return 1;
+ }
+ }
+
+ static class NoOp extends Op {
+ NoOp() {
+ super(null, "Nothing");
+ }
+
+ boolean onRun() {
+ return false;
+ }
+
+ int getOpsPerRun() {
+ return 0;
+ }
+ }
+
+ static class CpuOp extends Op {
+ CpuOp() {
+ super("CPU", "Consume CPU");
+ }
+
+ boolean onRun() {
+ return true;
+ }
+ }
+
+ static class SchedulerOp extends Op {
+ SchedulerOp() {
+ super("Sched", "Change scheduler group");
+ }
+
+ boolean onRun() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ return true;
+ }
+ }
+
+ static class GcOp extends Op {
+ GcOp() {
+ super("Gc", "Run garbage collector");
+ }
+
+ boolean onRun() {
+ byte[] stuff = new byte[1024*1024];
+ return true;
+ }
+ }
+
+ static class MethodCallOp extends Op {
+ MethodCallOp() {
+ super("MethodCall", "Method call");
+ }
+
+ boolean onRun() {
+ final int N = getOpsPerRun();
+ for (int i=0; i<N; i++) {
+ someFunc(i);
+ }
+ return true;
+ }
+
+ int someFunc(int foo) {
+ return 0;
+ }
+
+ int getOpsPerRun() {
+ return 500;
+ }
+ }
+
+ static class IpcOp extends Op {
+ PackageManager mPm;
+ String mProcessName;
+
+ IpcOp() {
+ super("Ipc", "IPC to system process");
+ }
+
+ void onInit(Context context) {
+ mPm = context.getPackageManager();
+ mProcessName = context.getApplicationInfo().processName;
+ }
+
+ boolean onRun() {
+ final int N = getOpsPerRun();
+ for (int i=0; i<N; i++) {
+ mPm.queryContentProviders(mProcessName, Process.myUid(), 0);
+ }
+ return true;
+ }
+
+ int getOpsPerRun() {
+ return 100;
+ }
+ }
+
+ static class ParseXmlResOp extends Op {
+ Context mContext;
+
+ ParseXmlResOp() {
+ super("ParseXmlRes", "Parse compiled XML resource");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ SimpleInflater inf = new SimpleInflater(mContext);
+ inf.inflate(R.xml.simple);
+ return true;
+ }
+ }
+
+ static class ParseLargeXmlResOp extends Op {
+ Context mContext;
+
+ ParseLargeXmlResOp() {
+ super("ParseLargeXmlRes", "Parse large XML resource");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ SimpleInflater inf = new SimpleInflater(mContext);
+ inf.inflate(R.xml.simple_large);
+ return true;
+ }
+ }
+
+ static class LayoutInflaterOp extends Op {
+ Context mContext;
+
+ LayoutInflaterOp() {
+ super("LayoutInflaterOp", "Inflate layout resource");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ inf.inflate(R.layout.small_layout, null);
+ return true;
+ }
+ }
+
+ static class LayoutInflaterLargeOp extends Op {
+ Context mContext;
+
+ LayoutInflaterLargeOp() {
+ super("LayoutInflaterLargeOp", "Inflate large layout resource");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ inf.inflate(R.layout.large_layout, null);
+ return true;
+ }
+ }
+
+ static class LoadSmallBitmapOp extends Op {
+ Context mContext;
+
+ LoadSmallBitmapOp() {
+ super("LoadSmallBitmap", "Load small raw bitmap");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+ Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+ R.drawable.stat_sample, opts);
+ bm.recycle();
+ return true;
+ }
+ }
+
+ static class LoadLargeBitmapOp extends Op {
+ Context mContext;
+
+ LoadLargeBitmapOp() {
+ super("LoadLargeBitmap", "Load large raw bitmap");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+ Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+ R.drawable.wallpaper_goldengate, opts);
+ bm.recycle();
+ return true;
+ }
+ }
+
+ static class LoadSmallScaledBitmapOp extends Op {
+ Context mContext;
+
+ LoadSmallScaledBitmapOp() {
+ super("LoadSmallScaledBitmap", "Load small raw bitmap that is scaled for density");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+ Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+ R.drawable.stat_sample_scale, opts);
+ bm.recycle();
+ return true;
+ }
+ }
+
+ static class LoadLargeScaledBitmapOp extends Op {
+ Context mContext;
+
+ LoadLargeScaledBitmapOp() {
+ super("LoadLargeScaledBitmap", "Load large raw bitmap that is scaled for density");
+ }
+
+ void onInit(Context context) {
+ mContext = context;
+ }
+
+ boolean onRun() {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
+ Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
+ R.drawable.wallpaper_goldengate_scale, opts);
+ bm.recycle();
+ return true;
+ }
+ }
+}
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
new file mode 100644
index 0000000..7691e64
--- /dev/null
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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.frameworkperf;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SchedulerService extends Service {
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Notification status = new Notification(R.drawable.stat_happy, null,
+ System.currentTimeMillis());
+ status.flags |= Notification.FLAG_ONGOING_EVENT;
+ status.setLatestEventInfo(this, "Scheduler Test running",
+ "Scheduler Test running", PendingIntent.getActivity(this, 0,
+ new Intent(this, FrameworkPerfActivity.class)
+ .setAction(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0));
+ startForeground(1, status);
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SimpleInflater.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SimpleInflater.java
new file mode 100644
index 0000000..5cbb12a
--- /dev/null
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SimpleInflater.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 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.frameworkperf;
+
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Xml;
+import android.view.InflateException;
+
+public class SimpleInflater {
+ /** Menu tag name in XML. */
+ private static final String XML_MENU = "menu";
+
+ /** Group tag name in XML. */
+ private static final String XML_GROUP = "group";
+
+ /** Item tag name in XML. */
+ private static final String XML_ITEM = "item";
+
+ private Context mContext;
+
+ public SimpleInflater(Context context) {
+ mContext = context;
+ }
+
+ public void inflate(int menuRes) {
+ XmlResourceParser parser = null;
+ try {
+ parser = mContext.getResources().getLayout(menuRes);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ parseMenu(parser, attrs);
+ } catch (XmlPullParserException e) {
+ throw new InflateException("Error inflating menu XML", e);
+ } catch (IOException e) {
+ throw new InflateException("Error inflating menu XML", e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ }
+
+ private void parseMenu(XmlPullParser parser, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ int eventType = parser.getEventType();
+ String tagName;
+ boolean lookingForEndOfUnknownTag = false;
+ String unknownTagName = null;
+
+ // This loop will skip to the menu start tag
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ tagName = parser.getName();
+ if (tagName.equals(XML_MENU)) {
+ // Go to next tag
+ eventType = parser.next();
+ break;
+ }
+
+ throw new RuntimeException("Expecting menu, got " + tagName);
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ boolean reachedEndOfMenu = false;
+ while (!reachedEndOfMenu) {
+ switch (eventType) {
+ case XmlPullParser.START_TAG:
+ if (lookingForEndOfUnknownTag) {
+ break;
+ }
+
+ tagName = parser.getName();
+ if (tagName.equals(XML_ITEM)) {
+ readItem(attrs);
+ } else if (tagName.equals(XML_MENU)) {
+ parseMenu(parser, attrs);
+ } else {
+ lookingForEndOfUnknownTag = true;
+ unknownTagName = tagName;
+ }
+ break;
+
+ case XmlPullParser.END_TAG:
+ tagName = parser.getName();
+ if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
+ lookingForEndOfUnknownTag = false;
+ unknownTagName = null;
+ } else if (tagName.equals(XML_ITEM)) {
+ } else if (tagName.equals(XML_MENU)) {
+ reachedEndOfMenu = true;
+ }
+ break;
+
+ case XmlPullParser.END_DOCUMENT:
+ throw new RuntimeException("Unexpected end of document");
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ public void readItem(AttributeSet attrs) {
+ TypedArray a = mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.MenuItem);
+
+ // Inherit attributes from the group as default value
+ int itemId = a.getResourceId(R.styleable.MenuItem_android_id, 0);
+ final int category = a.getInt(R.styleable.MenuItem_android_menuCategory, 0);
+ final int order = a.getInt(R.styleable.MenuItem_android_orderInCategory, 0);
+ CharSequence itemTitle = a.getText(R.styleable.MenuItem_android_title);
+ CharSequence itemTitleCondensed = a.getText(R.styleable.MenuItem_android_titleCondensed);
+ int itemIconResId = a.getResourceId(R.styleable.MenuItem_android_icon, 0);
+ String itemAlphabeticShortcut = a.getString(R.styleable.MenuItem_android_alphabeticShortcut);
+ String itemNumericShortcut = a.getString(R.styleable.MenuItem_android_numericShortcut);
+ int itemCheckable = 0;
+ if (a.hasValue(R.styleable.MenuItem_android_checkable)) {
+ // Item has attribute checkable, use it
+ itemCheckable = a.getBoolean(R.styleable.MenuItem_android_checkable, false) ? 1 : 0;
+ }
+ boolean itemChecked = a.getBoolean(R.styleable.MenuItem_android_checked, false);
+ boolean itemVisible = a.getBoolean(R.styleable.MenuItem_android_visible, false);
+ boolean itemEnabled = a.getBoolean(R.styleable.MenuItem_android_enabled, false);
+
+ a.recycle();
+ }
+}