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