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 java.io.File;
20import java.io.FileNotFoundException;
21import java.io.FileOutputStream;
22import java.io.IOException;
23import java.io.RandomAccessFile;
24import java.lang.String;
25import java.util.HashMap;
26import java.util.Random;
27
28import android.util.ArrayMap;
29import org.xmlpull.v1.XmlPullParser;
30import org.xmlpull.v1.XmlPullParserException;
31
32import android.app.Service;
33import android.content.Context;
34import android.content.Intent;
35import android.content.pm.PackageManager;
36import android.content.res.TypedArray;
37import android.content.res.XmlResourceParser;
38import android.graphics.Bitmap;
39import android.graphics.BitmapFactory;
40import android.graphics.Paint;
41import android.os.Bundle;
42import android.os.FileUtils;
43import android.os.Handler;
44import android.os.IBinder;
45import android.os.Looper;
46import android.os.Message;
47import android.os.Messenger;
48import android.os.Process;
49import android.os.RemoteException;
50import android.os.SystemClock;
51import android.util.AttributeSet;
52import android.util.DisplayMetrics;
53import android.util.Log;
54import android.util.Xml;
55import android.view.LayoutInflater;
56
57public class TestService extends Service {
58    static final String TAG = "Perf";
59
60    final static Op[] mOpPairs = new Op[] {
61            new MethodCallOp(), new NoOp(),
62            new MethodCallOp(), new CpuOp(),
63            new MethodCallOp(), new SchedulerOp(),
64            new MethodCallOp(), new GcOp(),
65            new MethodCallOp(), new CreateFileOp(),
66            new MethodCallOp(), new CreateWriteFileOp(),
67            new MethodCallOp(), new CreateWriteSyncFileOp(),
68            new MethodCallOp(), new WriteFileOp(),
69            new MethodCallOp(), new ReadFileOp(),
70            new SchedulerOp(), new SchedulerOp(),
71            new GcOp(), new NoOp(),
72            new ObjectGcOp(), new NoOp(),
73            new FinalizingGcOp(), new NoOp(),
74            new PaintGcOp(), new NoOp(),
75            new IpcOp(), new NoOp(),
76            new IpcOp(), new CpuOp(),
77            new IpcOp(), new SchedulerOp(),
78            new IpcOp(), new GcOp(),
79            new IpcOp(), new CreateFileOp(),
80            new IpcOp(), new CreateWriteFileOp(),
81            new IpcOp(), new CreateWriteSyncFileOp(),
82            new IpcOp(), new WriteFileOp(),
83            new IpcOp(), new ReadFileOp(),
84            new CreateFileOp(), new NoOp(),
85            new CreateWriteFileOp(), new NoOp(),
86            new CreateWriteSyncFileOp(), new NoOp(),
87            new WriteFileOp(), new NoOp(),
88            new ReadFileOp(), new NoOp(),
89            new WriteFileOp(), new CreateWriteFileOp(),
90            new ReadFileOp(), new CreateWriteFileOp(),
91            new WriteFileOp(), new CreateWriteSyncFileOp(),
92            new ReadFileOp(), new CreateWriteSyncFileOp(),
93            new WriteFileOp(), new WriteFileOp(),
94            new WriteFileOp(), new ReadFileOp(),
95            new ReadFileOp(), new WriteFileOp(),
96            new ReadFileOp(), new ReadFileOp(),
97            new OpenXmlResOp(), new NoOp(),
98            new ReadXmlAttrsOp(), new NoOp(),
99            new ParseXmlResOp(), new NoOp(),
100            new ParseLargeXmlResOp(), new NoOp(),
101            new LayoutInflaterOp(), new NoOp(),
102            new LayoutInflaterLargeOp(), new NoOp(),
103            new LayoutInflaterViewOp(), new NoOp(),
104            new LayoutInflaterButtonOp(), new NoOp(),
105            new LayoutInflaterImageButtonOp(), new NoOp(),
106            new CreateBitmapOp(), new NoOp(),
107            new CreateRecycleBitmapOp(), new NoOp(),
108            new LoadSmallBitmapOp(), new NoOp(),
109            new LoadRecycleSmallBitmapOp(), new NoOp(),
110            new LoadLargeBitmapOp(), new NoOp(),
111            new LoadRecycleLargeBitmapOp(), new NoOp(),
112            new LoadSmallScaledBitmapOp(), new NoOp(),
113            new LoadLargeScaledBitmapOp(), new NoOp(),
114    };
115
116    final static Op[] mAvailOps = new Op[] {
117            null,
118            new NoOp(),
119            new CpuOp(),
120            new SchedulerOp(),
121            new MethodCallOp(),
122            new GcOp(),
123            new ObjectGcOp(),
124            new FinalizingGcOp(),
125            new PaintGcOp(),
126            new IpcOp(),
127            new CreateFileOp(),
128            new CreateWriteFileOp(),
129            new CreateWriteSyncFileOp(),
130            new WriteFileOp(),
131            new ReadFileOp(),
132            new OpenXmlResOp(),
133            new ReadXmlAttrsOp(),
134            new ParseXmlResOp(),
135            new ParseLargeXmlResOp(),
136            new LayoutInflaterOp(),
137            new LayoutInflaterLargeOp(),
138            new LayoutInflaterViewOp(),
139            new LayoutInflaterButtonOp(),
140            new LayoutInflaterImageButtonOp(),
141            new CreateBitmapOp(),
142            new CreateRecycleBitmapOp(),
143            new LoadSmallBitmapOp(),
144            new LoadRecycleSmallBitmapOp(),
145            new LoadLargeBitmapOp(),
146            new LoadRecycleLargeBitmapOp(),
147            new LoadSmallScaledBitmapOp(),
148            new LoadLargeScaledBitmapOp(),
149            new GrowTinyHashMapOp(),
150            new GrowTinyArrayMapOp(),
151            new GrowSmallHashMapOp(),
152            new GrowSmallArrayMapOp(),
153            new GrowLargeHashMapOp(),
154            new GrowLargeArrayMapOp(),
155            new LookupTinyHashMapOp(),
156            new LookupTinyArrayMapOp(),
157            new LookupSmallHashMapOp(),
158            new LookupSmallArrayMapOp(),
159            new LookupLargeHashMapOp(),
160            new LookupLargeArrayMapOp(),
161    };
162
163    static final int CMD_START_TEST = 1;
164    static final int CMD_TERMINATE = 2;
165
166    static final int MSG_REALLY_START = 1000;
167    static final int MSG_REALLY_TERMINATE = 1001;
168
169    static final int RES_TEST_FINISHED = 1;
170    static final int RES_TERMINATED = 2;
171
172    final Handler mHandler = new Handler() {
173        @Override public void handleMessage(Message msg) {
174            switch (msg.what) {
175                case CMD_START_TEST: {
176                    // Give a little time for things to settle down.
177                    Message newMsg = Message.obtain(null, MSG_REALLY_START);
178                    newMsg.obj = msg.obj;
179                    newMsg.replyTo = msg.replyTo;
180                    sendMessageDelayed(newMsg, 500);
181                } break;
182                case MSG_REALLY_START: {
183                    Bundle bundle = (Bundle)msg.obj;
184                    bundle.setClassLoader(getClassLoader());
185                    final TestArgs args = (TestArgs)bundle.getParcelable("args");
186                    final Messenger replyTo = msg.replyTo;
187                    mRunner.run(this, args, new Runnable() {
188                        @Override public void run() {
189                            if (replyTo != null) {
190                                Message msg = Message.obtain(null, RES_TEST_FINISHED);
191                                Bundle bundle = new Bundle();
192                                bundle.putParcelable("res", new RunResult(mRunner));
193                                msg.obj = bundle;
194                                try {
195                                    replyTo.send(msg);
196                                } catch (RemoteException e) {
197                                }
198                            }
199                        }
200                    });
201                } break;
202                case CMD_TERMINATE: {
203                    // Give a little time for things to settle down.
204                    Message newMsg = Message.obtain(null, MSG_REALLY_TERMINATE);
205                    newMsg.obj = msg.obj;
206                    newMsg.replyTo = msg.replyTo;
207                    sendMessageDelayed(newMsg, 50);
208                } break;
209                case MSG_REALLY_TERMINATE: {
210                    if (msg.replyTo != null) {
211                        Message reply = Message.obtain(null, RES_TERMINATED);
212                        try {
213                            msg.replyTo.send(reply);
214                        } catch (RemoteException e) {
215                        }
216                    }
217                    terminate();
218                } break;
219            }
220        }
221    };
222
223    final TestRunner mRunner = new TestRunner();
224
225    @Override
226    public IBinder onBind(Intent intent) {
227        return (new Messenger(mHandler)).getBinder();
228    }
229
230    void terminate() {
231        Runtime.getRuntime().exit(0);
232    }
233
234    enum BackgroundMode {
235        NOTHING,
236        CPU,
237        SCHEDULER
238    };
239
240    public class TestRunner {
241        Handler mHandler;
242        long mMaxRunTime;
243        long mMaxOps;
244        Op mForegroundOp;
245        Op mBackgroundOp;
246        Runnable mDoneCallback;
247
248        RunnerThread mBackgroundThread;
249        RunnerThread mForegroundThread;
250        long mStartTime;
251
252        boolean mBackgroundRunning;
253        boolean mForegroundRunning;
254
255        long mBackgroundEndTime;
256        long mBackgroundOps;
257        long mForegroundEndTime;
258        long mForegroundOps;
259
260        public TestRunner() {
261        }
262
263        public String getForegroundName() {
264            return mForegroundOp.getName();
265        }
266
267        public String getBackgroundName() {
268            return mBackgroundOp.getName();
269        }
270
271        public String getName() {
272            String fgName = mForegroundOp.getName();
273            String bgName = mBackgroundOp.getName();
274            StringBuilder res = new StringBuilder();
275            if (fgName != null) {
276                res.append(fgName);
277                res.append("Fg");
278            }
279            if (bgName != null) {
280                res.append(bgName);
281                res.append("Bg");
282            }
283            return res.toString();
284        }
285
286        public String getForegroundLongName() {
287            return mForegroundOp.getLongName();
288        }
289
290        public String getBackgroundLongName() {
291            return mBackgroundOp.getLongName();
292        }
293
294        public void run(Handler handler, TestArgs args, Runnable doneCallback) {
295            mHandler = handler;
296            mMaxRunTime = args.maxTime;
297            mMaxOps = args.maxOps;
298            if (args.combOp >= 0) {
299                mForegroundOp = mOpPairs[args.combOp];
300                mBackgroundOp = mOpPairs[args.combOp+1];
301            } else {
302                mForegroundOp = mAvailOps[args.fgOp];
303                mBackgroundOp = mAvailOps[args.bgOp];
304            }
305            mDoneCallback = doneCallback;
306            mBackgroundThread = new RunnerThread("background", new Runnable() {
307                @Override public void run() {
308                    boolean running;
309                    int ops = 0;
310                    do {
311                        running = mBackgroundOp.onRun();
312                        ops++;
313                    } while (evalRepeat(running, true) && running);
314                    mBackgroundEndTime = SystemClock.uptimeMillis();
315                    mBackgroundOps = ops * mBackgroundOp.getOpsPerRun();
316                    threadFinished(false);
317                }
318            }, Process.THREAD_PRIORITY_BACKGROUND);
319            mForegroundThread = new RunnerThread("foreground", new Runnable() {
320                @Override public void run() {
321                    boolean running;
322                    int ops = 0;
323                    do {
324                        running = mForegroundOp.onRun();
325                        ops++;
326                    } while (evalRepeat(true, running) && running);
327                    mForegroundEndTime = SystemClock.uptimeMillis();
328                    mForegroundOps = ops * mForegroundOp.getOpsPerRun();
329                    threadFinished(true);
330                }
331            }, Process.THREAD_PRIORITY_FOREGROUND);
332
333            mForegroundOp.onInit(TestService.this, true);
334            mBackgroundOp.onInit(TestService.this, false);
335
336            synchronized (this) {
337                mStartTime = SystemClock.uptimeMillis();
338                mBackgroundRunning = true;
339                mForegroundRunning = true;
340            }
341
342            mBackgroundThread.start();
343            mForegroundThread.start();
344        }
345
346        public long getForegroundTime() {
347            return mForegroundEndTime-mStartTime;
348        }
349
350        public long getForegroundOps() {
351            return mForegroundOps;
352        }
353
354        public long getBackgroundTime() {
355            return mBackgroundEndTime-mStartTime;
356        }
357
358        public long getBackgroundOps() {
359            return mBackgroundOps;
360        }
361
362        private boolean evalRepeat(boolean bgRunning, boolean fgRunning) {
363            synchronized (this) {
364                if (!bgRunning) {
365                    mBackgroundRunning = false;
366                }
367                if (!fgRunning) {
368                    mForegroundRunning = false;
369                }
370                if (!mBackgroundRunning && !mForegroundRunning) {
371                    return false;
372                }
373                if (mMaxOps > 0) {
374                    // iteration-limited case
375                    if (mForegroundOps >= mMaxOps) {
376                        return false;
377                    }
378                    mForegroundOps++;
379                } else {
380                    // time-limited case
381                    long now = SystemClock.uptimeMillis();
382                    if (now > (mStartTime+mMaxRunTime)) {
383                        return false;
384                    }
385                }
386                return true;
387            }
388        }
389
390        private void threadFinished(boolean foreground) {
391            synchronized (this) {
392                if (foreground) {
393                    mForegroundRunning = false;
394                } else {
395                    mBackgroundRunning = false;
396                }
397                if (!mBackgroundRunning && !mForegroundRunning) {
398                    mHandler.post(new Runnable() {
399                        @Override public void run() {
400                            mForegroundOp.onTerm(TestService.this);
401                            mBackgroundOp.onTerm(TestService.this);
402                            if (mDoneCallback != null) {
403                                mDoneCallback.run();
404                            }
405                        }
406                    });
407                }
408            }
409        }
410    }
411
412    class RunnerThread extends Thread {
413        private final Runnable mOp;
414        private final int mPriority;
415
416        RunnerThread(String name, Runnable op, int priority) {
417            super(name);
418            mOp = op;
419            mPriority = priority;
420        }
421
422        public void run() {
423            Process.setThreadPriority(mPriority);
424            mOp.run();
425        }
426    }
427
428    static public abstract class Op {
429        final String mName;
430        final String mLongName;
431
432        public Op(String name, String longName) {
433            mName = name;
434            mLongName = longName;
435        }
436
437        public String getName() {
438            return mName;
439        }
440
441        public String getLongName() {
442            return mLongName;
443        }
444
445        void onInit(Context context, boolean foreground) {
446        }
447
448        abstract boolean onRun();
449
450        void onTerm(Context context) {
451        }
452
453        int getOpsPerRun() {
454            return 1;
455        }
456    }
457
458    static class NoOp extends Op {
459        NoOp() {
460            super(null, "Nothing");
461        }
462
463        boolean onRun() {
464            return false;
465        }
466
467        int getOpsPerRun() {
468            return 0;
469        }
470    }
471
472    static class CpuOp extends Op {
473        CpuOp() {
474            super("CPU", "Consume CPU");
475        }
476
477        boolean onRun() {
478            return true;
479        }
480    }
481
482    static class SchedulerOp extends Op {
483        SchedulerOp() {
484            super("Sched", "Change scheduler group");
485        }
486
487        boolean onRun() {
488            Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
489            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
490            return true;
491        }
492    }
493
494    static class GcOp extends Op {
495        GcOp() {
496            super("Gc", "Run garbage collector");
497        }
498
499        boolean onRun() {
500            byte[] stuff = new byte[1024*1024];
501            return true;
502        }
503    }
504
505    static class ObjectGcOp extends Op {
506        ObjectGcOp() {
507            super("ObjectGc", "Run garbage collector with simple objects");
508        }
509
510        boolean onRun() {
511            Object obj = new Object();
512            return true;
513        }
514    }
515
516    static class FinalizingGcOp extends Op {
517        class Finalizable {
518            Finalizable() {}
519            @Override
520            protected void finalize() throws Throwable {
521                super.finalize();
522            }
523        }
524
525        FinalizingGcOp() {
526            super("FinalizingGc", "Run garbage collector with finalizable objects");
527        }
528
529        boolean onRun() {
530            Finalizable obj = new Finalizable();
531            return true;
532        }
533    }
534
535    static class PaintGcOp extends Op {
536        PaintGcOp() {
537            super("PaintGc", "Run garbage collector with Paint objects");
538        }
539
540        boolean onRun() {
541            Paint p = new Paint();
542            return true;
543        }
544    }
545
546    static class MethodCallOp extends Op {
547        MethodCallOp() {
548            super("MethodCall", "Method call");
549        }
550
551        boolean onRun() {
552            final int N = getOpsPerRun();
553            for (int i=0; i<N; i++) {
554                someFunc(i);
555            }
556            return true;
557        }
558
559        int someFunc(int foo) {
560            return 0;
561        }
562
563        int getOpsPerRun() {
564            return 500;
565        }
566    }
567
568    static class IpcOp extends Op {
569        PackageManager mPm;
570        String mProcessName;
571
572        IpcOp() {
573            super("Ipc", "IPC to system process");
574        }
575
576        void onInit(Context context, boolean foreground) {
577            mPm = context.getPackageManager();
578            mProcessName = context.getApplicationInfo().processName;
579        }
580
581        boolean onRun() {
582            final int N = getOpsPerRun();
583            for (int i=0; i<N; i++) {
584                mPm.queryContentProviders(mProcessName, Process.myUid(), 0);
585            }
586            return true;
587        }
588
589        int getOpsPerRun() {
590            return 100;
591        }
592    }
593
594    static class OpenXmlResOp extends Op {
595        Context mContext;
596
597        OpenXmlResOp() {
598            super("OpenXmlRes", "Open (and close) an XML resource");
599        }
600
601        void onInit(Context context, boolean foreground) {
602            mContext = context;
603        }
604
605        boolean onRun() {
606            XmlResourceParser parser = mContext.getResources().getLayout(R.xml.simple);
607            parser.close();
608            return true;
609        }
610    }
611
612    static class ReadXmlAttrsOp extends Op {
613        Context mContext;
614        XmlResourceParser mParser;
615        AttributeSet mAttrs;
616
617        ReadXmlAttrsOp() {
618            super("ReadXmlAttrs", "Read attributes from an XML tag");
619        }
620
621        void onInit(Context context, boolean foreground) {
622            mContext = context;
623            mParser = mContext.getResources().getLayout(R.xml.simple);
624            mAttrs = Xml.asAttributeSet(mParser);
625
626            int eventType;
627            try {
628                // Find the first <item> tag.
629                eventType = mParser.getEventType();
630                String tagName;
631                do {
632                    if (eventType == XmlPullParser.START_TAG) {
633                        tagName = mParser.getName();
634                        if (tagName.equals("item")) {
635                            break;
636                        }
637                    }
638                    eventType = mParser.next();
639                } while (eventType != XmlPullParser.END_DOCUMENT);
640            } catch (XmlPullParserException e) {
641                throw new RuntimeException("I died", e);
642            } catch (IOException e) {
643                throw new RuntimeException("I died", e);
644            }
645        }
646
647        void onTerm(Context context) {
648            mParser.close();
649        }
650
651        boolean onRun() {
652            TypedArray a = mContext.obtainStyledAttributes(mAttrs,
653                    com.android.internal.R.styleable.MenuItem);
654            a.recycle();
655            return true;
656        }
657    }
658
659    static class ParseXmlResOp extends Op {
660        Context mContext;
661
662        ParseXmlResOp() {
663            super("ParseXmlRes", "Parse compiled XML resource");
664        }
665
666        void onInit(Context context, boolean foreground) {
667            mContext = context;
668        }
669
670        boolean onRun() {
671            SimpleInflater inf = new SimpleInflater(mContext);
672            inf.inflate(R.xml.simple);
673            return true;
674        }
675    }
676
677    static class ParseLargeXmlResOp extends Op {
678        Context mContext;
679
680        ParseLargeXmlResOp() {
681            super("ParseLargeXmlRes", "Parse large XML resource");
682        }
683
684        void onInit(Context context, boolean foreground) {
685            mContext = context;
686        }
687
688        boolean onRun() {
689            SimpleInflater inf = new SimpleInflater(mContext);
690            inf.inflate(R.xml.simple_large);
691            return true;
692        }
693    }
694
695    static class LayoutInflaterOp extends Op {
696        Context mContext;
697
698        LayoutInflaterOp() {
699            super("LayoutInflater", "Inflate layout resource");
700        }
701
702        void onInit(Context context, boolean foreground) {
703            mContext = context;
704        }
705
706        boolean onRun() {
707            if (Looper.myLooper() == null) {
708                Looper.prepare();
709            }
710            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
711                    Context.LAYOUT_INFLATER_SERVICE);
712            inf.inflate(R.layout.small_layout, null);
713            return true;
714        }
715    }
716
717    static class LayoutInflaterLargeOp extends Op {
718        Context mContext;
719
720        LayoutInflaterLargeOp() {
721            super("LayoutInflaterLarge", "Inflate large layout resource");
722        }
723
724        void onInit(Context context, boolean foreground) {
725            mContext = context;
726        }
727
728        boolean onRun() {
729            if (Looper.myLooper() == null) {
730                Looper.prepare();
731            }
732            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
733                    Context.LAYOUT_INFLATER_SERVICE);
734            inf.inflate(R.layout.large_layout, null);
735            return true;
736        }
737    }
738
739    static class LayoutInflaterViewOp extends Op {
740        Context mContext;
741
742        LayoutInflaterViewOp() {
743            super("LayoutInflaterView", "Inflate layout with 50 View objects");
744        }
745
746        void onInit(Context context, boolean foreground) {
747            mContext = context;
748        }
749
750        boolean onRun() {
751            if (Looper.myLooper() == null) {
752                Looper.prepare();
753            }
754            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
755                    Context.LAYOUT_INFLATER_SERVICE);
756            inf.inflate(R.layout.view_layout, null);
757            return true;
758        }
759    }
760
761    static class LayoutInflaterButtonOp extends Op {
762        Context mContext;
763
764        LayoutInflaterButtonOp() {
765            super("LayoutInflaterButton", "Inflate layout with 50 Button objects");
766        }
767
768        void onInit(Context context, boolean foreground) {
769            mContext = context;
770        }
771
772        boolean onRun() {
773            if (Looper.myLooper() == null) {
774                Looper.prepare();
775            }
776            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
777                    Context.LAYOUT_INFLATER_SERVICE);
778            inf.inflate(R.layout.button_layout, null);
779            return true;
780        }
781    }
782
783    static class LayoutInflaterImageButtonOp extends Op {
784        Context mContext;
785
786        LayoutInflaterImageButtonOp() {
787            super("LayoutInflaterImageButton", "Inflate layout with 50 ImageButton objects");
788        }
789
790        void onInit(Context context, boolean foreground) {
791            mContext = context;
792        }
793
794        boolean onRun() {
795            if (Looper.myLooper() == null) {
796                Looper.prepare();
797            }
798            LayoutInflater inf = (LayoutInflater)mContext.getSystemService(
799                    Context.LAYOUT_INFLATER_SERVICE);
800            inf.inflate(R.layout.image_button_layout, null);
801            return true;
802        }
803    }
804
805    static class CreateBitmapOp extends Op {
806        Context mContext;
807
808        CreateBitmapOp() {
809            super("CreateBitmap", "Create a Bitmap");
810        }
811
812        void onInit(Context context, boolean foreground) {
813            mContext = context;
814        }
815
816        boolean onRun() {
817            BitmapFactory.Options opts = new BitmapFactory.Options();
818            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
819            Bitmap bm = Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888);
820            return true;
821        }
822    }
823
824    static class CreateRecycleBitmapOp extends Op {
825        Context mContext;
826
827        CreateRecycleBitmapOp() {
828            super("CreateRecycleBitmap", "Create and recycle a Bitmap");
829        }
830
831        void onInit(Context context, boolean foreground) {
832            mContext = context;
833        }
834
835        boolean onRun() {
836            BitmapFactory.Options opts = new BitmapFactory.Options();
837            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
838            Bitmap bm = Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888);
839            bm.recycle();
840            return true;
841        }
842    }
843
844    static class LoadSmallBitmapOp extends Op {
845        Context mContext;
846
847        LoadSmallBitmapOp() {
848            super("LoadSmallBitmap", "Load small raw bitmap");
849        }
850
851        void onInit(Context context, boolean foreground) {
852            mContext = context;
853        }
854
855        boolean onRun() {
856            BitmapFactory.Options opts = new BitmapFactory.Options();
857            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
858            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
859                    R.drawable.stat_sample, opts);
860            return true;
861        }
862    }
863
864    static class LoadRecycleSmallBitmapOp extends Op {
865        Context mContext;
866
867        LoadRecycleSmallBitmapOp() {
868            super("LoadRecycleSmallBitmap", "Load and recycle small raw bitmap");
869        }
870
871        void onInit(Context context, boolean foreground) {
872            mContext = context;
873        }
874
875        boolean onRun() {
876            BitmapFactory.Options opts = new BitmapFactory.Options();
877            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
878            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
879                    R.drawable.stat_sample, opts);
880            bm.recycle();
881            return true;
882        }
883    }
884
885    static class LoadLargeBitmapOp extends Op {
886        Context mContext;
887
888        LoadLargeBitmapOp() {
889            super("LoadLargeBitmap", "Load large raw bitmap");
890        }
891
892        void onInit(Context context, boolean foreground) {
893            mContext = context;
894        }
895
896        boolean onRun() {
897            BitmapFactory.Options opts = new BitmapFactory.Options();
898            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
899            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
900                    R.drawable.wallpaper_goldengate, opts);
901            return true;
902        }
903    }
904
905    static class LoadRecycleLargeBitmapOp extends Op {
906        Context mContext;
907
908        LoadRecycleLargeBitmapOp() {
909            super("LoadRecycleLargeBitmap", "Load and recycle large raw bitmap");
910        }
911
912        void onInit(Context context, boolean foreground) {
913            mContext = context;
914        }
915
916        boolean onRun() {
917            BitmapFactory.Options opts = new BitmapFactory.Options();
918            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
919            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
920                    R.drawable.wallpaper_goldengate, opts);
921            bm.recycle();
922            return true;
923        }
924    }
925
926    static class LoadSmallScaledBitmapOp extends Op {
927        Context mContext;
928
929        LoadSmallScaledBitmapOp() {
930            super("LoadSmallScaledBitmap", "Load small raw bitmap that is scaled for density");
931        }
932
933        void onInit(Context context, boolean foreground) {
934            mContext = context;
935        }
936
937        boolean onRun() {
938            BitmapFactory.Options opts = new BitmapFactory.Options();
939            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
940            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
941                    R.drawable.stat_sample_scale, opts);
942            return true;
943        }
944    }
945
946    static class LoadLargeScaledBitmapOp extends Op {
947        Context mContext;
948
949        LoadLargeScaledBitmapOp() {
950            super("LoadLargeScaledBitmap", "Load large raw bitmap that is scaled for density");
951        }
952
953        void onInit(Context context, boolean foreground) {
954            mContext = context;
955        }
956
957        boolean onRun() {
958            BitmapFactory.Options opts = new BitmapFactory.Options();
959            opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
960            Bitmap bm = BitmapFactory.decodeResource(mContext.getResources(),
961                    R.drawable.wallpaper_goldengate_scale, opts);
962            return true;
963        }
964    }
965
966    static class CreateFileOp extends Op {
967        File mFile;
968
969        CreateFileOp() {
970            super("CreateFile", "Create and delete a file");
971        }
972
973        void onInit(Context context, boolean foreground) {
974            mFile = context.getFileStreamPath(foreground ? "test-fg.file" : "test-bg.file");
975            mFile.delete();
976        }
977
978        boolean onRun() {
979            try {
980                mFile.createNewFile();
981            } catch (IOException e) {
982                Log.w(TAG, "Failure creating " + mFile, e);
983            }
984            mFile.delete();
985            return true;
986        }
987    }
988
989    static class CreateWriteFileOp extends Op {
990        File mFile;
991
992        CreateWriteFileOp() {
993            super("CreateWriteFile", "Create, write, and delete a file");
994        }
995
996        void onInit(Context context, boolean foreground) {
997            mFile = context.getFileStreamPath(foreground ? "test-fg.file" : "test-bg.file");
998            mFile.delete();
999        }
1000
1001        boolean onRun() {
1002            try {
1003                FileOutputStream fos = new FileOutputStream(mFile);
1004                fos.write(1);
1005                fos.close();
1006            } catch (IOException e) {
1007                Log.w(TAG, "Failure creating " + mFile, e);
1008            }
1009            mFile.delete();
1010            return true;
1011        }
1012    }
1013
1014    static class CreateWriteSyncFileOp extends Op {
1015        File mFile;
1016
1017        CreateWriteSyncFileOp() {
1018            super("CreateWriteSyncFile", "Create, write, sync, and delete a file");
1019        }
1020
1021        void onInit(Context context, boolean foreground) {
1022            mFile = context.getFileStreamPath(foreground ? "test-fg.file" : "test-bg.file");
1023            mFile.delete();
1024        }
1025
1026        boolean onRun() {
1027            try {
1028                FileOutputStream fos = new FileOutputStream(mFile);
1029                fos.write(1);
1030                fos.flush();
1031                FileUtils.sync(fos);
1032                fos.close();
1033            } catch (IOException e) {
1034                Log.w(TAG, "Failure creating " + mFile, e);
1035            }
1036            mFile.delete();
1037            return true;
1038        }
1039    }
1040
1041    static class WriteFileOp extends Op {
1042        File mFile;
1043        RandomAccessFile mRAF;
1044        byte[] mBuffer;
1045
1046        WriteFileOp() {
1047            super("WriteFile", "Truncate and write a 64k file");
1048        }
1049
1050        void onInit(Context context, boolean foreground) {
1051            mBuffer = new byte[1024*64];
1052            for (int i=0; i<mBuffer.length; i++) {
1053                mBuffer[i] = (byte)i;
1054            }
1055            mFile = context.getFileStreamPath(foreground ? "test-fg.file" : "test-bg.file");
1056            mFile.delete();
1057            try {
1058                mRAF = new RandomAccessFile(mFile, "rw");
1059            } catch (FileNotFoundException e) {
1060                Log.w(TAG, "Failure creating " + mFile, e);
1061            }
1062        }
1063
1064        boolean onRun() {
1065            try {
1066                mRAF.seek(0);
1067                mRAF.setLength(0);
1068                mRAF.write(mBuffer);
1069            } catch (IOException e) {
1070                Log.w(TAG, "Failure writing " + mFile, e);
1071            }
1072            return true;
1073        }
1074
1075        void onTerm(Context context) {
1076            try {
1077                mRAF.close();
1078            } catch (IOException e) {
1079                Log.w(TAG, "Failure closing " + mFile, e);
1080            }
1081            mFile.delete();
1082        }
1083    }
1084
1085    static class ReadFileOp extends Op {
1086        File mFile;
1087        RandomAccessFile mRAF;
1088        byte[] mBuffer;
1089
1090        ReadFileOp() {
1091            super("ReadFile", "Seek and read a 64k file");
1092        }
1093
1094        void onInit(Context context, boolean foreground) {
1095            mBuffer = new byte[1024*64];
1096            for (int i=0; i<mBuffer.length; i++) {
1097                mBuffer[i] = (byte)i;
1098            }
1099            mFile = context.getFileStreamPath(foreground ? "test-fg.file" : "test-bg.file");
1100            mFile.delete();
1101            try {
1102                mRAF = new RandomAccessFile(mFile, "rw");
1103                mRAF.seek(0);
1104                mRAF.setLength(0);
1105                mRAF.write(mBuffer);
1106            } catch (IOException e) {
1107                Log.w(TAG, "Failure creating " + mFile, e);
1108            }
1109        }
1110
1111        boolean onRun() {
1112            try {
1113                mRAF.seek(0);
1114                mRAF.read(mBuffer);
1115            } catch (IOException e) {
1116                Log.w(TAG, "Failure reading " + mFile, e);
1117            }
1118            return true;
1119        }
1120
1121        void onTerm(Context context) {
1122            try {
1123                mRAF.close();
1124            } catch (IOException e) {
1125                Log.w(TAG, "Failure closing " + mFile, e);
1126            }
1127            mFile.delete();
1128        }
1129    }
1130
1131    static abstract class GenericMapOp extends Op {
1132        final int mSize;
1133        String[] mKeys;
1134        String[] mValues;
1135
1136        GenericMapOp(String name, String longName, int size) {
1137            super(name, longName);
1138            mSize = size;
1139        }
1140
1141        void onInit(Context context, boolean foreground) {
1142            mKeys = new String[mSize];
1143            mValues = new String[mSize];
1144            Random random = new Random(0);
1145            for (int i=0; i<mSize; i++) {
1146                int chars = random.nextInt(10);
1147                StringBuilder builder = new StringBuilder(chars);
1148                for (int j=0; j<chars; j++) {
1149                    builder.append('a' + random.nextInt(100));
1150                }
1151                mKeys[i] = builder.toString();
1152                mValues[i] = Integer.toString(i);
1153            }
1154        }
1155
1156        int getOpsPerRun() {
1157            return mSize;
1158        }
1159    }
1160
1161    static class GrowTinyHashMapOp extends GenericMapOp {
1162        GrowTinyHashMapOp() {
1163            super("GrowTinyHashMap", "Add 5 items to a HashMap", 5);
1164        }
1165
1166        boolean onRun() {
1167            HashMap<String, String> map = new HashMap<String, String>();
1168            for (int i=0; i<mSize; i++) {
1169                map.put(mKeys[i], mValues[i]);
1170            }
1171            return true;
1172        }
1173    }
1174
1175    static class GrowTinyArrayMapOp extends GenericMapOp {
1176        GrowTinyArrayMapOp() {
1177            super("GrowTinyArrayMap", "Add 5 items to a ArrayMap", 5);
1178        }
1179
1180        boolean onRun() {
1181            ArrayMap<String, String> map = new ArrayMap<String, String>();
1182            for (int i=0; i<mSize; i++) {
1183                map.put(mKeys[i], mValues[i]);
1184            }
1185            return true;
1186        }
1187    }
1188
1189    static class GrowSmallHashMapOp extends GenericMapOp {
1190        GrowSmallHashMapOp() {
1191            super("GrowSmallHashMap", "Add 100 items to a HashMap", 100);
1192        }
1193
1194        boolean onRun() {
1195            HashMap<String, String> map = new HashMap<String, String>();
1196            for (int i=0; i<mSize; i++) {
1197                map.put(mKeys[i], mValues[i]);
1198            }
1199            return true;
1200        }
1201    }
1202
1203    static class GrowSmallArrayMapOp extends GenericMapOp {
1204        GrowSmallArrayMapOp() {
1205            super("GrowSmallArrayMap", "Add 100 items to a ArrayMap", 100);
1206        }
1207
1208        boolean onRun() {
1209            ArrayMap<String, String> map = new ArrayMap<String, String>();
1210            for (int i=0; i<mSize; i++) {
1211                map.put(mKeys[i], mValues[i]);
1212            }
1213            return true;
1214        }
1215    }
1216
1217    static class GrowLargeHashMapOp extends GenericMapOp {
1218        GrowLargeHashMapOp() {
1219            super("GrowLargeHashMap", "Add 10000 items to a HashMap", 10000);
1220        }
1221
1222        boolean onRun() {
1223            HashMap<String, String> map = new HashMap<String, String>();
1224            for (int i=0; i<mSize; i++) {
1225                map.put(mKeys[i], mValues[i]);
1226            }
1227            return true;
1228        }
1229    }
1230
1231    static class GrowLargeArrayMapOp extends GenericMapOp {
1232        GrowLargeArrayMapOp() {
1233            super("GrowLargeArrayMap", "Add 10000 items to a ArrayMap", 10000);
1234        }
1235
1236        boolean onRun() {
1237            ArrayMap<String, String> map = new ArrayMap<String, String>();
1238            for (int i=0; i<mSize; i++) {
1239                map.put(mKeys[i], mValues[i]);
1240            }
1241            return true;
1242        }
1243    }
1244
1245    static class LookupTinyHashMapOp extends LookupSmallHashMapOp {
1246        LookupTinyHashMapOp() {
1247            super("LookupTinyHashMap", "Lookup items in 5 entry HashMap", 5);
1248        }
1249    }
1250
1251    static class LookupTinyArrayMapOp extends LookupSmallArrayMapOp {
1252        LookupTinyArrayMapOp() {
1253            super("LookupTinyArrayMap", "Lookup items in 5 entry ArrayMap", 5);
1254        }
1255    }
1256
1257    static class LookupSmallHashMapOp extends GenericMapOp {
1258        HashMap<String, String> mHashMap;
1259
1260        LookupSmallHashMapOp() {
1261            super("LookupSmallHashMap", "Lookup items in 100 entry HashMap", 100);
1262        }
1263
1264        LookupSmallHashMapOp(String name, String longname, int size) {
1265            super(name, longname, size);
1266        }
1267
1268        void onInit(Context context, boolean foreground) {
1269            super.onInit(context, foreground);
1270            mHashMap = new HashMap<String, String>();
1271            for (int i=0; i<mSize; i++) {
1272                mHashMap.put(mKeys[i], mValues[i]);
1273            }
1274        }
1275
1276        boolean onRun() {
1277            for (int i=0; i<mSize; i++) {
1278                mHashMap.get(mKeys[i]);
1279            }
1280            return true;
1281        }
1282    }
1283
1284    static class LookupSmallArrayMapOp extends GenericMapOp {
1285        ArrayMap<String, String> mArrayMap;
1286
1287        LookupSmallArrayMapOp() {
1288            super("LookupSmallArrayMap", "Lookup items in 100 entry ArrayMap", 100);
1289        }
1290
1291        LookupSmallArrayMapOp(String name, String longname, int size) {
1292            super(name, longname, size);
1293        }
1294
1295        void onInit(Context context, boolean foreground) {
1296            super.onInit(context, foreground);
1297            mArrayMap = new ArrayMap<String, String>();
1298            for (int i=0; i<mSize; i++) {
1299                mArrayMap.put(mKeys[i], mValues[i]);
1300            }
1301        }
1302
1303        boolean onRun() {
1304            for (int i=0; i<mSize; i++) {
1305                mArrayMap.get(mKeys[i]);
1306            }
1307            return true;
1308        }
1309    }
1310
1311    static class LookupLargeHashMapOp extends LookupSmallHashMapOp {
1312        LookupLargeHashMapOp() {
1313            super("LookupLargeHashMap", "Lookup items in 10000 entry HashMap", 10000);
1314        }
1315    }
1316
1317    static class LookupLargeArrayMapOp extends LookupSmallArrayMapOp {
1318        LookupLargeArrayMapOp() {
1319            super("LookupLargeArrayMap", "Lookup items in 10000 entry ArrayMap", 10000);
1320        }
1321    }
1322}
1323