xref: /aosp_15_r20/frameworks/base/tests/JankBench/scripts/collect.py (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker#!/usr/bin/python
2*d57664e9SAndroid Build Coastguard Worker
3*d57664e9SAndroid Build Coastguard Workerimport optparse
4*d57664e9SAndroid Build Coastguard Workerimport sys
5*d57664e9SAndroid Build Coastguard Workerimport sqlite3
6*d57664e9SAndroid Build Coastguard Workerimport scipy.stats
7*d57664e9SAndroid Build Coastguard Workerimport numpy
8*d57664e9SAndroid Build Coastguard Workerfrom math import log10, floor
9*d57664e9SAndroid Build Coastguard Workerimport matplotlib
10*d57664e9SAndroid Build Coastguard Worker
11*d57664e9SAndroid Build Coastguard Workermatplotlib.use("Agg")
12*d57664e9SAndroid Build Coastguard Worker
13*d57664e9SAndroid Build Coastguard Workerimport matplotlib.pyplot as plt
14*d57664e9SAndroid Build Coastguard Workerimport pylab
15*d57664e9SAndroid Build Coastguard Worker
16*d57664e9SAndroid Build Coastguard Workerimport adbutil
17*d57664e9SAndroid Build Coastguard Workerfrom devices import DEVICES
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard WorkerDB_PATH="/data/data/com.android.benchmark/databases/BenchmarkResults"
20*d57664e9SAndroid Build Coastguard WorkerOUT_PATH = "db/"
21*d57664e9SAndroid Build Coastguard Worker
22*d57664e9SAndroid Build Coastguard WorkerQUERY_BAD_FRAME = ("select run_id, name, iteration, total_duration from ui_results "
23*d57664e9SAndroid Build Coastguard Worker                   "where total_duration >= 16 order by run_id, name, iteration")
24*d57664e9SAndroid Build Coastguard WorkerQUERY_PERCENT_JANK = ("select run_id, name, iteration, sum(jank_frame) as jank_count, count (*) as total "
25*d57664e9SAndroid Build Coastguard Worker                      "from ui_results group by run_id, name, iteration")
26*d57664e9SAndroid Build Coastguard Worker
27*d57664e9SAndroid Build Coastguard WorkerSKIP_TESTS = [
28*d57664e9SAndroid Build Coastguard Worker    # "BMUpload",
29*d57664e9SAndroid Build Coastguard Worker    # "Low-hitrate text render",
30*d57664e9SAndroid Build Coastguard Worker    # "High-hitrate text render",
31*d57664e9SAndroid Build Coastguard Worker    # "Edit Text Input",
32*d57664e9SAndroid Build Coastguard Worker    # "List View Fling"
33*d57664e9SAndroid Build Coastguard Worker]
34*d57664e9SAndroid Build Coastguard Worker
35*d57664e9SAndroid Build Coastguard WorkerINCLUDE_TESTS = [
36*d57664e9SAndroid Build Coastguard Worker    #"BMUpload"
37*d57664e9SAndroid Build Coastguard Worker    #"Shadow Grid Fling"
38*d57664e9SAndroid Build Coastguard Worker    #"Image List View Fling"
39*d57664e9SAndroid Build Coastguard Worker    #"Edit Text Input"
40*d57664e9SAndroid Build Coastguard Worker]
41*d57664e9SAndroid Build Coastguard Worker
42*d57664e9SAndroid Build Coastguard Workerclass IterationResult:
43*d57664e9SAndroid Build Coastguard Worker    def __init__(self):
44*d57664e9SAndroid Build Coastguard Worker        self.durations = []
45*d57664e9SAndroid Build Coastguard Worker        self.jank_count = 0
46*d57664e9SAndroid Build Coastguard Worker        self.total_count = 0
47*d57664e9SAndroid Build Coastguard Worker
48*d57664e9SAndroid Build Coastguard Worker
49*d57664e9SAndroid Build Coastguard Workerdef get_scoremap(dbpath):
50*d57664e9SAndroid Build Coastguard Worker    db = sqlite3.connect(dbpath)
51*d57664e9SAndroid Build Coastguard Worker    rows = db.execute(QUERY_BAD_FRAME)
52*d57664e9SAndroid Build Coastguard Worker
53*d57664e9SAndroid Build Coastguard Worker    scoremap = {}
54*d57664e9SAndroid Build Coastguard Worker    for row in rows:
55*d57664e9SAndroid Build Coastguard Worker        run_id = row[0]
56*d57664e9SAndroid Build Coastguard Worker        name = row[1]
57*d57664e9SAndroid Build Coastguard Worker        iteration = row[2]
58*d57664e9SAndroid Build Coastguard Worker        total_duration = row[3]
59*d57664e9SAndroid Build Coastguard Worker
60*d57664e9SAndroid Build Coastguard Worker        if not run_id in scoremap:
61*d57664e9SAndroid Build Coastguard Worker            scoremap[run_id] = {}
62*d57664e9SAndroid Build Coastguard Worker
63*d57664e9SAndroid Build Coastguard Worker        if not name in scoremap[run_id]:
64*d57664e9SAndroid Build Coastguard Worker            scoremap[run_id][name] = {}
65*d57664e9SAndroid Build Coastguard Worker
66*d57664e9SAndroid Build Coastguard Worker        if not iteration in scoremap[run_id][name]:
67*d57664e9SAndroid Build Coastguard Worker            scoremap[run_id][name][iteration] = IterationResult()
68*d57664e9SAndroid Build Coastguard Worker
69*d57664e9SAndroid Build Coastguard Worker        scoremap[run_id][name][iteration].durations.append(float(total_duration))
70*d57664e9SAndroid Build Coastguard Worker
71*d57664e9SAndroid Build Coastguard Worker    for row in db.execute(QUERY_PERCENT_JANK):
72*d57664e9SAndroid Build Coastguard Worker        run_id = row[0]
73*d57664e9SAndroid Build Coastguard Worker        name = row[1]
74*d57664e9SAndroid Build Coastguard Worker        iteration = row[2]
75*d57664e9SAndroid Build Coastguard Worker        jank_count = row[3]
76*d57664e9SAndroid Build Coastguard Worker        total_count = row[4]
77*d57664e9SAndroid Build Coastguard Worker
78*d57664e9SAndroid Build Coastguard Worker        if run_id in scoremap.keys() and name in scoremap[run_id].keys() and iteration in scoremap[run_id][name].keys():
79*d57664e9SAndroid Build Coastguard Worker            scoremap[run_id][name][iteration].jank_count = long(jank_count)
80*d57664e9SAndroid Build Coastguard Worker            scoremap[run_id][name][iteration].total_count = long(total_count)
81*d57664e9SAndroid Build Coastguard Worker
82*d57664e9SAndroid Build Coastguard Worker    db.close()
83*d57664e9SAndroid Build Coastguard Worker    return scoremap
84*d57664e9SAndroid Build Coastguard Worker
85*d57664e9SAndroid Build Coastguard Workerdef round_to_2(val):
86*d57664e9SAndroid Build Coastguard Worker    return val
87*d57664e9SAndroid Build Coastguard Worker    if val == 0:
88*d57664e9SAndroid Build Coastguard Worker        return val
89*d57664e9SAndroid Build Coastguard Worker    return round(val , -int(floor(log10(abs(val)))) + 1)
90*d57664e9SAndroid Build Coastguard Worker
91*d57664e9SAndroid Build Coastguard Workerdef score_device(name, serial, pull = False, verbose = False):
92*d57664e9SAndroid Build Coastguard Worker    dbpath = OUT_PATH + name + ".db"
93*d57664e9SAndroid Build Coastguard Worker
94*d57664e9SAndroid Build Coastguard Worker    if pull:
95*d57664e9SAndroid Build Coastguard Worker        adbutil.root(serial)
96*d57664e9SAndroid Build Coastguard Worker        adbutil.pull(serial, DB_PATH, dbpath)
97*d57664e9SAndroid Build Coastguard Worker
98*d57664e9SAndroid Build Coastguard Worker    scoremap = None
99*d57664e9SAndroid Build Coastguard Worker    try:
100*d57664e9SAndroid Build Coastguard Worker        scoremap = get_scoremap(dbpath)
101*d57664e9SAndroid Build Coastguard Worker    except sqlite3.DatabaseError:
102*d57664e9SAndroid Build Coastguard Worker        print "Database corrupt, fetching..."
103*d57664e9SAndroid Build Coastguard Worker        adbutil.root(serial)
104*d57664e9SAndroid Build Coastguard Worker        adbutil.pull(serial, DB_PATH, dbpath)
105*d57664e9SAndroid Build Coastguard Worker        scoremap = get_scoremap(dbpath)
106*d57664e9SAndroid Build Coastguard Worker
107*d57664e9SAndroid Build Coastguard Worker    per_test_score = {}
108*d57664e9SAndroid Build Coastguard Worker    per_test_sample_count = {}
109*d57664e9SAndroid Build Coastguard Worker    global_overall = {}
110*d57664e9SAndroid Build Coastguard Worker
111*d57664e9SAndroid Build Coastguard Worker    for run_id in iter(scoremap):
112*d57664e9SAndroid Build Coastguard Worker        overall = []
113*d57664e9SAndroid Build Coastguard Worker        if len(scoremap[run_id]) < 1:
114*d57664e9SAndroid Build Coastguard Worker            if verbose:
115*d57664e9SAndroid Build Coastguard Worker                print "Skipping short run %s" % run_id
116*d57664e9SAndroid Build Coastguard Worker            continue
117*d57664e9SAndroid Build Coastguard Worker        print "Run: %s" % run_id
118*d57664e9SAndroid Build Coastguard Worker        for test in iter(scoremap[run_id]):
119*d57664e9SAndroid Build Coastguard Worker            if test in SKIP_TESTS:
120*d57664e9SAndroid Build Coastguard Worker                continue
121*d57664e9SAndroid Build Coastguard Worker            if INCLUDE_TESTS and test not in INCLUDE_TESTS:
122*d57664e9SAndroid Build Coastguard Worker                continue
123*d57664e9SAndroid Build Coastguard Worker            if verbose:
124*d57664e9SAndroid Build Coastguard Worker                print "\t%s" % test
125*d57664e9SAndroid Build Coastguard Worker            scores = []
126*d57664e9SAndroid Build Coastguard Worker            means = []
127*d57664e9SAndroid Build Coastguard Worker            stddevs = []
128*d57664e9SAndroid Build Coastguard Worker            pjs = []
129*d57664e9SAndroid Build Coastguard Worker            sample_count = 0
130*d57664e9SAndroid Build Coastguard Worker            hit_min_count = 0
131*d57664e9SAndroid Build Coastguard Worker            # try pooling together all iterations
132*d57664e9SAndroid Build Coastguard Worker            for iteration in iter(scoremap[run_id][test]):
133*d57664e9SAndroid Build Coastguard Worker                res = scoremap[run_id][test][iteration]
134*d57664e9SAndroid Build Coastguard Worker                stddev = round_to_2(numpy.std(res.durations))
135*d57664e9SAndroid Build Coastguard Worker                mean = round_to_2(numpy.mean(res.durations))
136*d57664e9SAndroid Build Coastguard Worker                sample_count += len(res.durations)
137*d57664e9SAndroid Build Coastguard Worker                pj = round_to_2(100 * res.jank_count / float(res.total_count))
138*d57664e9SAndroid Build Coastguard Worker                score = stddev * mean * pj
139*d57664e9SAndroid Build Coastguard Worker                score = 100 * len(res.durations) / float(res.total_count)
140*d57664e9SAndroid Build Coastguard Worker                if score == 0:
141*d57664e9SAndroid Build Coastguard Worker                    score = 1
142*d57664e9SAndroid Build Coastguard Worker                scores.append(score)
143*d57664e9SAndroid Build Coastguard Worker                means.append(mean)
144*d57664e9SAndroid Build Coastguard Worker                stddevs.append(stddev)
145*d57664e9SAndroid Build Coastguard Worker                pjs.append(pj)
146*d57664e9SAndroid Build Coastguard Worker                if verbose:
147*d57664e9SAndroid Build Coastguard Worker                    print "\t%s: Score = %f x %f x %f = %f (%d samples)" % (iteration, stddev, mean, pj, score, len(res.durations))
148*d57664e9SAndroid Build Coastguard Worker
149*d57664e9SAndroid Build Coastguard Worker            if verbose:
150*d57664e9SAndroid Build Coastguard Worker                print "\tHit min: %d" % hit_min_count
151*d57664e9SAndroid Build Coastguard Worker                print "\tMean Variation: %0.2f%%" % (100 * scipy.stats.variation(means))
152*d57664e9SAndroid Build Coastguard Worker                print "\tStdDev Variation: %0.2f%%" % (100 * scipy.stats.variation(stddevs))
153*d57664e9SAndroid Build Coastguard Worker                print "\tPJ Variation: %0.2f%%" % (100 * scipy.stats.variation(pjs))
154*d57664e9SAndroid Build Coastguard Worker
155*d57664e9SAndroid Build Coastguard Worker            geo_run = numpy.mean(scores)
156*d57664e9SAndroid Build Coastguard Worker            if test not in per_test_score:
157*d57664e9SAndroid Build Coastguard Worker                per_test_score[test] = []
158*d57664e9SAndroid Build Coastguard Worker
159*d57664e9SAndroid Build Coastguard Worker            if test not in per_test_sample_count:
160*d57664e9SAndroid Build Coastguard Worker                per_test_sample_count[test] = []
161*d57664e9SAndroid Build Coastguard Worker
162*d57664e9SAndroid Build Coastguard Worker            sample_count /= len(scoremap[run_id][test])
163*d57664e9SAndroid Build Coastguard Worker
164*d57664e9SAndroid Build Coastguard Worker            per_test_score[test].append(geo_run)
165*d57664e9SAndroid Build Coastguard Worker            per_test_sample_count[test].append(int(sample_count))
166*d57664e9SAndroid Build Coastguard Worker            overall.append(geo_run)
167*d57664e9SAndroid Build Coastguard Worker
168*d57664e9SAndroid Build Coastguard Worker            if not verbose:
169*d57664e9SAndroid Build Coastguard Worker                print "\t%s:\t%0.2f (%0.2f avg. sample count)" % (test, geo_run, sample_count)
170*d57664e9SAndroid Build Coastguard Worker            else:
171*d57664e9SAndroid Build Coastguard Worker                print "\tOverall:\t%0.2f (%0.2f avg. sample count)" % (geo_run, sample_count)
172*d57664e9SAndroid Build Coastguard Worker                print ""
173*d57664e9SAndroid Build Coastguard Worker
174*d57664e9SAndroid Build Coastguard Worker        global_overall[run_id] = scipy.stats.gmean(overall)
175*d57664e9SAndroid Build Coastguard Worker        print "Run Overall: %f" % global_overall[run_id]
176*d57664e9SAndroid Build Coastguard Worker        print ""
177*d57664e9SAndroid Build Coastguard Worker
178*d57664e9SAndroid Build Coastguard Worker    print ""
179*d57664e9SAndroid Build Coastguard Worker    print "Variability (CV) - %s:" % name
180*d57664e9SAndroid Build Coastguard Worker
181*d57664e9SAndroid Build Coastguard Worker    worst_offender_test = None
182*d57664e9SAndroid Build Coastguard Worker    worst_offender_variation = 0
183*d57664e9SAndroid Build Coastguard Worker    for test in per_test_score:
184*d57664e9SAndroid Build Coastguard Worker        variation = 100 * scipy.stats.variation(per_test_score[test])
185*d57664e9SAndroid Build Coastguard Worker        if worst_offender_variation < variation:
186*d57664e9SAndroid Build Coastguard Worker            worst_offender_test = test
187*d57664e9SAndroid Build Coastguard Worker            worst_offender_variation = variation
188*d57664e9SAndroid Build Coastguard Worker        print "\t%s:\t%0.2f%% (%0.2f avg sample count)" % (test, variation, numpy.mean(per_test_sample_count[test]))
189*d57664e9SAndroid Build Coastguard Worker
190*d57664e9SAndroid Build Coastguard Worker    print "\tOverall: %0.2f%%" % (100 * scipy.stats.variation([x for x in global_overall.values()]))
191*d57664e9SAndroid Build Coastguard Worker    print ""
192*d57664e9SAndroid Build Coastguard Worker
193*d57664e9SAndroid Build Coastguard Worker    return {
194*d57664e9SAndroid Build Coastguard Worker            "overall": global_overall.values(),
195*d57664e9SAndroid Build Coastguard Worker            "worst_offender_test": (name, worst_offender_test, worst_offender_variation)
196*d57664e9SAndroid Build Coastguard Worker            }
197*d57664e9SAndroid Build Coastguard Worker
198*d57664e9SAndroid Build Coastguard Workerdef parse_options(argv):
199*d57664e9SAndroid Build Coastguard Worker    usage = 'Usage: %prog [options]'
200*d57664e9SAndroid Build Coastguard Worker    desc = 'Example: %prog'
201*d57664e9SAndroid Build Coastguard Worker    parser = optparse.OptionParser(usage=usage, description=desc)
202*d57664e9SAndroid Build Coastguard Worker    parser.add_option("-p", dest='pull', action="store_true")
203*d57664e9SAndroid Build Coastguard Worker    parser.add_option("-d", dest='device', action="store")
204*d57664e9SAndroid Build Coastguard Worker    parser.add_option("-v", dest='verbose', action="store_true")
205*d57664e9SAndroid Build Coastguard Worker    options, categories = parser.parse_args(argv[1:])
206*d57664e9SAndroid Build Coastguard Worker    return options
207*d57664e9SAndroid Build Coastguard Worker
208*d57664e9SAndroid Build Coastguard Workerdef main():
209*d57664e9SAndroid Build Coastguard Worker    options = parse_options(sys.argv)
210*d57664e9SAndroid Build Coastguard Worker    if options.device != None:
211*d57664e9SAndroid Build Coastguard Worker        score_device(options.device, DEVICES[options.device], options.pull, options.verbose)
212*d57664e9SAndroid Build Coastguard Worker    else:
213*d57664e9SAndroid Build Coastguard Worker        device_scores = []
214*d57664e9SAndroid Build Coastguard Worker        worst_offenders = []
215*d57664e9SAndroid Build Coastguard Worker        for name, serial in DEVICES.iteritems():
216*d57664e9SAndroid Build Coastguard Worker            print "======== %s =========" % name
217*d57664e9SAndroid Build Coastguard Worker            result = score_device(name, serial, options.pull, options.verbose)
218*d57664e9SAndroid Build Coastguard Worker            device_scores.append((name, result["overall"]))
219*d57664e9SAndroid Build Coastguard Worker            worst_offenders.append(result["worst_offender_test"])
220*d57664e9SAndroid Build Coastguard Worker
221*d57664e9SAndroid Build Coastguard Worker
222*d57664e9SAndroid Build Coastguard Worker        device_scores.sort(cmp=(lambda x, y: cmp(x[1], y[1])))
223*d57664e9SAndroid Build Coastguard Worker        print "Ranking by max overall score:"
224*d57664e9SAndroid Build Coastguard Worker        for name, score in device_scores:
225*d57664e9SAndroid Build Coastguard Worker            plt.plot([0, 1, 2, 3, 4, 5], score, label=name)
226*d57664e9SAndroid Build Coastguard Worker            print "\t%s: %s" % (name, score)
227*d57664e9SAndroid Build Coastguard Worker
228*d57664e9SAndroid Build Coastguard Worker        plt.ylabel("Jank %")
229*d57664e9SAndroid Build Coastguard Worker        plt.xlabel("Iteration")
230*d57664e9SAndroid Build Coastguard Worker        plt.title("Jank Percentage")
231*d57664e9SAndroid Build Coastguard Worker        plt.legend()
232*d57664e9SAndroid Build Coastguard Worker        pylab.savefig("holy.png", bbox_inches="tight")
233*d57664e9SAndroid Build Coastguard Worker
234*d57664e9SAndroid Build Coastguard Worker        print "Worst offender tests:"
235*d57664e9SAndroid Build Coastguard Worker        for device, test, variation in worst_offenders:
236*d57664e9SAndroid Build Coastguard Worker            print "\t%s: %s %.2f%%" % (device, test, variation)
237*d57664e9SAndroid Build Coastguard Worker
238*d57664e9SAndroid Build Coastguard Workerif __name__ == "__main__":
239*d57664e9SAndroid Build Coastguard Worker    main()
240*d57664e9SAndroid Build Coastguard Worker
241