152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project#!/usr/bin/env python
252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project##
452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project## chewie.py
552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project## chews browser http log.  draws graph of connections
652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project## Be sure there is only one pageload in the log.
752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project##
852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project## you'll want to
952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project##   sudo apt-get install python-matplotlib
1052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project## before running this
1152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project##
1252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectimport sys, pylab
1452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project# can't just use a dict, because there can be dups
1652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectclass Queue:
1752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    def __init__(self):
1852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        self.queue = []
1952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
2052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    def add(self, url, time):
2152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        self.queue.append([url, time])
2252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
2352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    def get(self, url):
2452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        for x in range(len(self.queue)):
2552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            rec = self.queue[x]
2652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            if rec[0] == url:
2752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                del self.queue[x]
2852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project                return rec[1]
2952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project## pull out request lag -- queue to start to done
3152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef lag():
3252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    font = {'color': '#909090', 'fontsize': 6}
3452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    extractMe = {
3552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'RequestQueue.queueRequest': "Q",
3652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'Connection.openHttpConnection()': "O",
3752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'Request.sendRequest()': "S",
3852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'Request.requestSent()': "T",
3952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'processRequests()': 'R',
4052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'Request.readResponse():': "D",         # done
4152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'clearPipe()': 'U',	                    # unqueue
4252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'Request.readResponse()': 'B',          # read data block
4352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'Request.readResponseStatus():': 'HR',  # read http response line
4452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        'hdr': 'H',                             # http header
4552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
4652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    keys = extractMe.keys()
4752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
4852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    f = open(sys.argv[1], "r")
4952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
5052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    t0 = None
5152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
5252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    # thread, queued, opened, send, sent, reading, read, uri, server, y
5352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    # 0       1       2       3     4     5        6     7    8       9
5452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    vals = []
5552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
5652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    queued = Queue()
5752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    opened = {"http0": None,
5852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http1": None,
5952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http2": None,
6052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http3": None,
6152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http4": None,
6252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http5": None}
6352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    active = {"http0": [],
6452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http1": [],
6552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http2": [],
6652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http3": [],
6752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http4": [],
6852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              "http5": []}
6952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    connectionCount = 0
7052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    byteCount = 0
7152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    killed = [[], []]
7252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    while (True):
7452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        line = f.readline()
7552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if len(line) == 0: break
7652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        splitup = line.split()
7852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        # http only
8052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if splitup[0] != "V/http": continue
8152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        x = splitup[3:]
8352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        # filter to named lines
8552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if x[2] not in keys: continue
8652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        x[2] = extractMe[x[2]]
8752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        # normalize time
8952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if t0 == None: t0 = int(x[0])
9052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        x[0] = int(x[0]) - t0
9152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
9252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        thread, action = x[1], x[2]
9352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if action == "Q":
9452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            time, url = x[0], x[3]
9552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            queued.add(url, time)
9652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "O":
9752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            # save opened time and server for this thread, so we can stuff it in l8r
9852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            time, thread, host = x[0], x[1], x[4]
9952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            opened[thread] = [time, host, connectionCount]
10052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            connectionCount += 1
10152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "S":
10252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            time, thread, url = x[0], x[1], x[3]
10352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            opentime, host, connection = opened[thread]
10452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            qtime = queued.get(url)
10552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record = [thread, qtime, opentime, time, None, None, None, url, host, connection]
10652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            active[thread].append(record)
10752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "T":
10852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            time, thread = x[0], x[1]
10952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record = active[thread][-1]
11052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record[4] = time
11152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "R":
11252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            print x
11352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            if x[3] in ["sleep", "no", "wait"]: continue
11452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            time, thread, = x[0], x[1]
11552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record = active[thread][0]
11652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record[5] = time
11752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == 'U':
11852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            thread = x[1]
11952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record = active[thread][0]
12052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            killed[0].append(record[9])
12152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            killed[1].append(x[0])
12252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            queued.add(record[7], record[1])
12352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            del active[thread][0]
12452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "D":
12552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            time, thread = x[0], x[1]
12652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record = active[thread][0]
12752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            record[6] = time
12852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            vals.append(record)
12952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            del active[thread][0]
13052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            print record
13152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            # print record[3] / 1000, record[6] / 1000, record[7]
13252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "B":
13352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            byteCount += int(x[3])
13452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        elif action == "HR":
13552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            byteCount += int(x[2])
13652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
13752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    f.close()
13852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
13952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    rng = range(connectionCount)
14052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
14152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    opened = []
14252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    drawn = [False for x in rng]
14352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    for val in vals:
14452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        y= val[9]
14552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        if not drawn[y]:
14652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            drawn[y] = True
14752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            opened.append(val[2])
14852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            pylab.text(0, y - 0.25, "%s %s %s" % (val[9], val[0][4], val[8]), font)
14952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    # define limits
15152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    # pylab.plot([vals[-1][6]], rng)
15252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    print opened, rng
15452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    pylab.plot(opened, rng, 'ro')
15552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    pylab.plot(killed[1], killed[0], 'rx')
15652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    for val in vals:
15852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        thread, queued, opened, send, sent, reading, read, uri, server, y = val
15952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        # send arrow
16052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        arrow = pylab.Arrow(send, y, sent - send, 0)
16152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        arrow.set_facecolor("g")
16252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        ax = pylab.gca()
16352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        ax.add_patch(arrow)
16452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        # read arrow
16552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        arrow = pylab.Arrow(reading, y, read - reading, 0)
16652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        arrow.set_facecolor("r")
16752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        ax = pylab.gca()
16852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        ax.add_patch(arrow)
16952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
17052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    caption = \
17152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            "\nrequests: %s\n" % len(vals) + \
17252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            "byteCount: %s\n" % byteCount + \
17352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            "data rate: %s\n" % (1000 * byteCount / vals[-1][6])+ \
17452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            "connections: %s\n" % connectionCount
17552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
17652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    pylab.figtext(0.82, 0.30, caption, bbox=dict(facecolor='lightgrey', alpha=0.5))
17752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
17852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    # print lines, [[x, x] for x in range(len(vals))]
17952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    # pylab.plot(lines, [[x, x] for x in range(len(vals))], 'r-')
18052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
18152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    pylab.grid()
18252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    pylab.show()
18352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
18452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectif __name__ == '__main__': lag()
185