1/*
2 * Copyright (C) 2008 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.google.coretests;
18
19import dalvik.system.VMDebug;
20
21import junit.framework.AssertionFailedError;
22import junit.framework.Test;
23import junit.framework.TestListener;
24
25import java.io.PrintStream;
26import java.util.ArrayList;
27import java.util.Iterator;
28
29public class PerfStatCollector implements TestListener {
30
31    public boolean listAll = false;
32    public boolean listBad = false;
33    public long thresholdDuration = 3600 * 1000; // in milliseconds
34    public boolean twoLines = true;
35    public boolean bigMarking = true;
36
37    private static boolean havePreciseTime =
38        VMDebug.threadCpuTimeNanos() != -1;
39
40    public class Item {
41        Test test;
42        long startTime, duration;
43        int res;
44        public boolean existsInStore;
45        public int id;
46        public int bestRes;
47        public long lastBestAt;
48        public int lastRes;
49        public long lastDuration;
50        public int statCount;
51        public double statAvgDuration;
52        public long statMinDuration;
53        public long statMaxDuration;
54        int adhocRelevance;
55        public int histRelevance;
56        public boolean isTransition;
57        boolean printed = false;
58
59        void update(boolean rBad, long rthDurat) {
60            // AdHoc Evaluation:
61            if (rBad && (res != 0)) {
62                // no success:
63                adhocRelevance = 2;
64            }
65            else if (duration >= rthDurat) {
66                // long duration:
67                adhocRelevance = 1;
68            }
69            else {
70                adhocRelevance = 0;
71            }
72
73            StatsStore.use1(this);
74        }
75
76        void print1(PrintStream out, boolean bigMarking) {
77            switch (histRelevance) {
78            case -4:
79                if (bigMarking) {
80                    out.println();
81                    out.println("*** *** *** *** *** ATTENTION *** *** *** *** ***");
82                    out.println("*** *** *** *** *** ATTENTION *** *** *** *** ***");
83                    out.println("*** *** *** *** *** ATTENTION *** *** *** *** ***");
84                    out.println("Test ran SUCCESSFULLY once, but NOT this time!!!!");
85                    out.println("*** *** *** *** *** ATTENTION *** *** *** *** ***");
86                    out.println("*** *** *** *** *** ATTENTION *** *** *** *** ***");
87                    out.println("*** *** *** *** *** ATTENTION *** *** *** *** ***");
88                }
89                out.print("-4 VBAD"); break;
90            case 4: out.print(" 4 Good"); break;
91            case 3: out.print(" 3 good"); break;
92            case -2: out.print("-2 SLOW"); break;
93            case 2: out.print(" 2 Fast"); break;
94            case 1: out.print(" 1 fast"); break;
95            case -3:
96                if (res == -2) out.print("-3 FAIL");
97                else out.print("-3 ERR ");
98                break;
99            default:
100                if (res == 0) out.print("       ");
101                else if (res == -2) out.print("   fail");
102                else out.print("   err ");
103            }
104            if (isTransition) out.print("! ");
105            else out.print("  ");
106            out.print(test.toString());
107            out.format(": %d# %d(%d) [%d..%d] %.1f ms",
108                    statCount, duration, lastDuration,
109                    statMinDuration, statMaxDuration, statAvgDuration);
110            out.println();
111            printed = true;
112        }
113
114        void print2(PrintStream out, boolean bigMarking) {
115            out.format("%5d. ", id);
116
117            out.println(test.toString());
118            out.print("       ");
119
120            switch (histRelevance) {
121                case -4: out.print("FAIL"); break;
122                case 4: out.print("PASS"); break;
123                case 3: out.print("PASS"); break;
124                case -2: out.print("SLOW"); break;
125                case 2: out.print("FAST"); break;
126                case 1: out.print("PASS"); break;
127                case -3:
128                    if (res == -2) out.print("FAIL");
129                    else out.print("ERR ");
130                    break;
131                default:
132                    if (res == 0) out.print("PASS");
133                    else if (res == -2) out.print("FAIL");
134                    else out.print("XCPT");
135            }
136
137            out.format(" %d ms (min %d ms, max %d ms, avg %#.1f ms, %d runs)",
138                    duration,
139                    statMinDuration, statMaxDuration, statAvgDuration,
140                    statCount);
141            out.println();
142
143            printed = true;
144        }
145
146        void print(PrintStream out, boolean bigMarking) {
147            if (twoLines) print2(out, bigMarking);
148            else print1(out, bigMarking);
149        }
150
151        boolean checkPrint(PrintStream out) {
152            if (printed) return false;
153            print(out, false);
154            return true;
155        }
156    }
157
158    ArrayList<Item> items;
159    Item current;
160
161    PrintStream fWriter;
162    int fColumn= 0;
163
164    public PerfStatCollector(PrintStream writer)  {
165        fWriter= writer;
166        items = new ArrayList();
167    }
168
169    synchronized void digest() {
170        int totalCnt = 0;
171        int adhocRelevantCnt = 0;
172        int histRelevantCnt = 0;
173        long evalStartTime = System.currentTimeMillis();
174        PrintStream out = fWriter;
175        out.println("Failure and Performance Statistics:");
176        Iterator<Item> r = items.iterator();
177        while (r.hasNext()) {
178            Item item = r.next();
179            item.update(listBad, thresholdDuration);
180            if (item.histRelevance != 0) {
181                item.print(out, bigMarking);
182                histRelevantCnt++;
183            }
184            if (item.adhocRelevance != 0) {
185                if (item.checkPrint(out))
186                    adhocRelevantCnt++;
187            }
188            if (listAll) item.checkPrint(out);
189            totalCnt++;
190        }
191        long evalDuration = System.currentTimeMillis() - evalStartTime;
192        out.println();
193        out.print(totalCnt); out.println(" tests run totally.");
194        out.print(histRelevantCnt);
195                out.println(" tests listed due to historical relevance.");
196//        out.print(adhocRelevantCnt);
197//                out.println(" tests listed due to ad-hoc-relevance.");
198//        out.print(totalCnt - histRelevantCnt - adhocRelevantCnt);
199//                out.println(" tests NOT listed due to relevance.");
200        out.println();
201        out.print("Time used in Statistics Acquisition: ");
202        out.print(evalDuration);
203        out.print("ms");
204        out.println();
205    }
206
207
208    public PrintStream getWriter() {
209        return fWriter;
210    }
211
212    /**
213     * @see junit.framework.TestListener#addError(Test, Throwable)
214     */
215    public void addError(Test test, Throwable t) {
216        current.res = -1;
217    }
218
219    /**
220     * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
221     */
222    public void addFailure(Test test, AssertionFailedError t) {
223        current.res = -2;
224    }
225
226    /**
227     * @see junit.framework.TestListener#startTest(Test)
228     */
229    public void startTest(Test test) {
230        System.gc();
231        current = new Item();
232        current.test = test;
233        current.startTime = currentTimeMillis();
234        items.add(current);
235    }
236
237    /**
238     * @see junit.framework.TestListener#endTest(Test)
239     */
240    public void endTest(Test test) {
241        current.duration = currentTimeMillis() - current.startTime;
242    }
243
244    /*
245     * Returns a "current time" in ms. Depending on the environment, this is
246     * either the actual CPU time out current thread has used so far, or the
247     * wall clock time of the system.
248     */
249    private long currentTimeMillis() {
250        if (havePreciseTime) {
251            return VMDebug.threadCpuTimeNanos() / 1000;
252        } else {
253            return System.currentTimeMillis();
254        }
255    }
256
257}
258