FrameworkPerfActivity.java revision 6b57b7e4d568bfa6273f87ef4c9af2fdc0ca1a06
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.frameworkperf;
18
19import android.app.Activity;
20import android.content.ComponentName;
21import android.content.Intent;
22import android.content.ServiceConnection;
23import android.os.Bundle;
24import android.os.Handler;
25import android.os.IBinder;
26import android.os.Message;
27import android.os.Messenger;
28import android.os.PowerManager;
29import android.os.RemoteException;
30import android.util.Log;
31import android.view.View;
32import android.view.WindowManager;
33import android.widget.AdapterView;
34import android.widget.ArrayAdapter;
35import android.widget.Button;
36import android.widget.CheckBox;
37import android.widget.Spinner;
38import android.widget.TextView;
39
40import java.util.ArrayList;
41
42/**
43 * So you thought sync used up your battery life.
44 */
45public class FrameworkPerfActivity extends Activity
46        implements AdapterView.OnItemSelectedListener {
47    static final String TAG = "Perf";
48
49    Spinner mFgSpinner;
50    Spinner mBgSpinner;
51    TextView mTestTime;
52    Button mStartButton;
53    Button mStopButton;
54    CheckBox mLocalCheckBox;
55    TextView mLog;
56    PowerManager.WakeLock mPartialWakeLock;
57
58    long mMaxRunTime = 5000;
59    boolean mStarted;
60
61    final String[] mAvailOpLabels;
62    final String[] mAvailOpDescriptions;
63
64    int mFgTestIndex = -1;
65    int mBgTestIndex = -1;
66    TestService.Op mFgTest;
67    TestService.Op mBgTest;
68    int mCurOpIndex = 0;
69    TestConnection mCurConnection;
70
71    final ArrayList<RunResult> mResults = new ArrayList<RunResult>();
72
73    class TestConnection implements ServiceConnection {
74        Messenger mService;
75
76        @Override public void onServiceConnected(ComponentName name, IBinder service) {
77            mService = new Messenger(service);
78            dispatchCurOp(this);
79        }
80
81        @Override public void onServiceDisconnected(ComponentName name) {
82        }
83    }
84
85    static final int MSG_CONTINUE = 1000;
86
87    final Handler mHandler = new Handler() {
88        @Override public void handleMessage(Message msg) {
89            switch (msg.what) {
90                case TestService.RES_TEST_FINISHED: {
91                    Bundle bundle = (Bundle)msg.obj;
92                    bundle.setClassLoader(getClassLoader());
93                    RunResult res = (RunResult)bundle.getParcelable("res");
94                    completeCurOp(res);
95                } break;
96                case TestService.RES_TERMINATED: {
97                    // Give a little time for things to settle down.
98                    sendMessageDelayed(obtainMessage(MSG_CONTINUE), 500);
99                } break;
100                case MSG_CONTINUE: {
101                    startCurOp();
102                } break;
103            }
104        }
105    };
106
107    final Messenger mMessenger = new Messenger(mHandler);
108
109    public FrameworkPerfActivity() {
110        mAvailOpLabels = new String[TestService.mAvailOps.length];
111        mAvailOpDescriptions = new String[TestService.mAvailOps.length];
112        for (int i=0; i<TestService.mAvailOps.length; i++) {
113            TestService.Op op = TestService.mAvailOps[i];
114            if (op == null) {
115                mAvailOpLabels[i] = "All";
116                mAvailOpDescriptions[i] = "All tests";
117            } else {
118                mAvailOpLabels[i] = op.getName();
119                if (mAvailOpLabels[i] == null) {
120                    mAvailOpLabels[i] = "Nothing";
121                }
122                mAvailOpDescriptions[i] = op.getLongName();
123            }
124        }
125    }
126
127    @Override
128    public void onCreate(Bundle savedInstanceState) {
129        super.onCreate(savedInstanceState);
130
131        // Set the layout for this activity.  You can find it
132        // in res/layout/hello_activity.xml
133        setContentView(R.layout.main);
134
135        mFgSpinner = (Spinner) findViewById(R.id.fgspinner);
136        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
137                android.R.layout.simple_spinner_item, mAvailOpLabels);
138        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
139        mFgSpinner.setAdapter(adapter);
140        mFgSpinner.setOnItemSelectedListener(this);
141        mBgSpinner = (Spinner) findViewById(R.id.bgspinner);
142        adapter = new ArrayAdapter<String>(this,
143                android.R.layout.simple_spinner_item, mAvailOpLabels);
144        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
145        mBgSpinner.setAdapter(adapter);
146        mBgSpinner.setOnItemSelectedListener(this);
147
148        mTestTime = (TextView)findViewById(R.id.testtime);
149
150        mStartButton = (Button)findViewById(R.id.start);
151        mStartButton.setOnClickListener(new View.OnClickListener() {
152            @Override public void onClick(View v) {
153                startRunning();
154            }
155        });
156        mStopButton = (Button)findViewById(R.id.stop);
157        mStopButton.setOnClickListener(new View.OnClickListener() {
158            @Override public void onClick(View v) {
159                stopRunning();
160            }
161        });
162        mStopButton.setEnabled(false);
163        mLocalCheckBox = (CheckBox)findViewById(R.id.local);
164
165        mLog = (TextView)findViewById(R.id.log);
166
167        PowerManager pm = (PowerManager)getSystemService(POWER_SERVICE);
168        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Scheduler");
169        mPartialWakeLock.setReferenceCounted(false);
170    }
171
172    @Override
173    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
174        if (parent == mFgSpinner || parent == mBgSpinner) {
175            TestService.Op op = TestService.mAvailOps[position];
176            if (parent == mFgSpinner) {
177                mFgTestIndex = position;
178                mFgTest = op;
179                ((TextView)findViewById(R.id.fgtext)).setText(mAvailOpDescriptions[position]);
180            } else {
181                mBgTestIndex = position;
182                mBgTest = op;
183                ((TextView)findViewById(R.id.bgtext)).setText(mAvailOpDescriptions[position]);
184            }
185        }
186    }
187
188    @Override
189    public void onNothingSelected(AdapterView<?> parent) {
190    }
191
192    @Override
193    public void onResume() {
194        super.onResume();
195    }
196
197    @Override
198    public void onDestroy() {
199        super.onDestroy();
200        stopRunning();
201        if (mPartialWakeLock.isHeld()) {
202            mPartialWakeLock.release();
203        }
204    }
205
206    void dispatchCurOp(TestConnection conn) {
207        if (mCurConnection != conn) {
208            Log.w(TAG, "Dispatching on invalid connection: " + conn);
209            return;
210        }
211        TestArgs args = new TestArgs();
212        args.maxTime = mMaxRunTime;
213        if (mFgTestIndex == 0 && mBgTestIndex == 0) {
214            args.combOp = mCurOpIndex;
215        } else if (mFgTestIndex != 0 && mBgTestIndex != 0) {
216            args.fgOp = mFgTestIndex;
217            args.bgOp = mBgTestIndex;
218        } else {
219            // Skip null test.
220            if (mCurOpIndex == 0) {
221                mCurOpIndex = 1;
222            }
223            if (mFgTestIndex != 0) {
224                args.fgOp = mFgTestIndex;
225                args.bgOp = mCurOpIndex;
226            } else {
227                args.fgOp = mCurOpIndex;
228                args.bgOp = mFgTestIndex;
229            }
230        }
231        Bundle bundle = new Bundle();
232        bundle.putParcelable("args", args);
233        Message msg = Message.obtain(null, TestService.CMD_START_TEST, bundle);
234        msg.replyTo = mMessenger;
235        try {
236            conn.mService.send(msg);
237        } catch (RemoteException e) {
238            Log.i(TAG, "Failure communicating with service", e);
239        }
240    }
241
242    void completeCurOp(RunResult result) {
243        log(String.format("%s: fg=%d*%gms/op (%dms) / bg=%d*%gms/op (%dms)",
244                result.name, result.fgOps, result.getFgMsPerOp(), result.fgTime,
245                result.bgOps, result.getBgMsPerOp(), result.bgTime));
246        mResults.add(result);
247        if (!mStarted) {
248            log("Stop");
249            stopRunning();
250            return;
251        }
252        if (mFgTest != null && mBgTest != null) {
253            log("Finished");
254            stopRunning();
255            return;
256        }
257        if (mFgTest == null && mBgTest == null) {
258            mCurOpIndex+=2;
259            if (mCurOpIndex >= TestService.mOpPairs.length) {
260                log("Finished");
261                stopRunning();
262                return;
263            }
264        } else {
265            mCurOpIndex++;
266            if (mCurOpIndex >= TestService.mAvailOps.length) {
267                log("Finished");
268                stopRunning();
269                return;
270            }
271        }
272        startCurOp();
273    }
274
275    void disconnect() {
276        if (mCurConnection != null) {
277            unbindService(mCurConnection);
278            if (mCurConnection.mService != null) {
279                Message msg = Message.obtain(null, TestService.CMD_TERMINATE);
280                msg.replyTo = mMessenger;
281                try {
282                    mCurConnection.mService.send(msg);
283                } catch (RemoteException e) {
284                    Log.i(TAG, "Failure communicating with service", e);
285                }
286            }
287            mCurConnection = null;
288        }
289    }
290
291    void startCurOp() {
292        if (mCurConnection != null) {
293            disconnect();
294        }
295        if (mStarted) {
296            mHandler.removeMessages(TestService.RES_TEST_FINISHED);
297            mHandler.removeMessages(TestService.RES_TERMINATED);
298            mHandler.removeMessages(MSG_CONTINUE);
299            mCurConnection = new TestConnection();
300            Intent intent;
301            if (mLocalCheckBox.isChecked()) {
302                intent = new Intent(this, LocalTestService.class);
303            } else {
304                intent = new Intent(this, TestService.class);
305            }
306            bindService(intent, mCurConnection, BIND_AUTO_CREATE|BIND_IMPORTANT);
307        }
308    }
309
310    void startRunning() {
311        if (!mStarted) {
312            log("Start");
313            mStarted = true;
314            mStartButton.setEnabled(false);
315            mStopButton.setEnabled(true);
316            mLocalCheckBox.setEnabled(false);
317            mTestTime.setEnabled(false);
318            mFgSpinner.setEnabled(false);
319            mBgSpinner.setEnabled(false);
320            updateWakeLock();
321            startService(new Intent(this, SchedulerService.class));
322            mCurOpIndex = 0;
323            mMaxRunTime = Integer.parseInt(mTestTime.getText().toString());
324            mResults.clear();
325            startCurOp();
326        }
327    }
328
329    void stopRunning() {
330        if (mStarted) {
331            disconnect();
332            mStarted = false;
333            mStartButton.setEnabled(true);
334            mStopButton.setEnabled(false);
335            mLocalCheckBox.setEnabled(true);
336            mTestTime.setEnabled(true);
337            mFgSpinner.setEnabled(true);
338            mBgSpinner.setEnabled(true);
339            updateWakeLock();
340            stopService(new Intent(this, SchedulerService.class));
341            for (int i=0; i<mResults.size(); i++) {
342                RunResult result = mResults.get(i);
343                float fgMsPerOp = result.getFgMsPerOp();
344                float bgMsPerOp = result.getBgMsPerOp();
345                String fgMsPerOpStr = fgMsPerOp != 0 ? Float.toString(fgMsPerOp) : "";
346                String bgMsPerOpStr = bgMsPerOp != 0 ? Float.toString(bgMsPerOp) : "";
347                Log.i("PerfRes", "\t" + result.name + "\t" + result.fgOps
348                        + "\t" + result.getFgMsPerOp() + "\t" + result.fgTime
349                        + "\t" + result.fgLongName + "\t" + result.bgOps
350                        + "\t" + result.getBgMsPerOp() + "\t" + result.bgTime
351                        + "\t" + result.bgLongName);
352            }
353        }
354    }
355
356    void updateWakeLock() {
357        if (mStarted) {
358            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
359            if (!mPartialWakeLock.isHeld()) {
360                mPartialWakeLock.acquire();
361            }
362        } else {
363            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
364            if (mPartialWakeLock.isHeld()) {
365                mPartialWakeLock.release();
366            }
367        }
368    }
369
370    void log(String s) {
371        mLog.setText(mLog.getText() + "\n" + s);
372        Log.i(TAG, s);
373    }
374}
375