aboutsummaryrefslogtreecommitdiff
path: root/tools/dbusmenu-bench
blob: 4b58da824f54950f8db7cece1a9fb6f99b451801 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env python
# encoding: utf-8
"""
A library to communicate a menu object set accross DBus and
track updates and maintain consistency.

Copyright 2010 Canonical Ltd.

Authors:
    Aurélien Gâteau <aurelien.gateau@canonical.com>

This program is free software: you can redistribute it and/or modify it 
under the terms of either or both of the following licenses:

1) the GNU Lesser General Public License version 3, as published by the 
Free Software Foundation; and/or
2) the GNU Lesser General Public License version 2.1, as published by 
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but 
WITHOUT ANY WARRANTY; without even the implied warranties of 
MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR 
PURPOSE.  See the applicable version of the GNU Lesser General Public 
License for more details.

You should have received a copy of both the GNU Lesser General Public 
License version 3 and version 2.1 along with this program.  If not, see 
<http://www.gnu.org/licenses/>
"""
import itertools
import time
import sys
from optparse import OptionParser
from xml.etree import ElementTree as ET

import dbus

DBUS_INTERFACE = "org.ayatana.dbusmenu"
DBUS_SERVICE = "org.dbusmenu.test"
DBUS_PATH = "/MenuBar"

PROBE_GET_LAYOUT     = "GetLayout"
PROBE_GET_PROPERTIES = "GetProperties"
PROBE_GET_CHILDREN   = "GetChildren"
PROBES = PROBE_GET_LAYOUT, PROBE_GET_PROPERTIES, PROBE_GET_CHILDREN

class Chrono(object):
    def __init__(self):
        self._time = 0
        self.restart()

    def restart(self):
        new_time = time.time()
        delta = new_time - self._time
        self._time = new_time
        return delta

    def elapsed(self):
        return time.time() - self._time


def dump_properties(properties, prepend=""):
    for key, value in properties.items():
        print "%s- %s: %s" % (prepend, key, value)


def run_test_sequence(menu, dump=False):
    """
    Runs the test sequence and returns a dict of method_name: seconds
    """
    property_names = ["type", "label", "enabled", "icon-name"]
    times = dict()
    chrono = Chrono()
    revision, layout = menu.GetLayout(dbus.Int32(0))
    times["GetLayout"] = chrono.elapsed()
    if dump:
        print "revision:", revision
        print "layout:"
        print layout

    # Get ids
    tree = ET.fromstring(layout)
    root_id = int(tree.attrib["id"])
    child_element = tree.find("menu")
    assert child_element is not None
    child_id = int(child_element.attrib["id"])

    chrono.restart()
    children = menu.GetChildren(dbus.Int32(root_id), property_names)
    times["GetChildren"] = chrono.elapsed()
    if dump:
        print "children:"
        for child in children:
            id, properties = child
            print "- %d:" % id
            dump_properties(properties, prepend=" ")

    chrono.restart()
    properties = menu.GetProperties(dbus.Int32(child_id), property_names)
    times["GetProperties"] = chrono.elapsed()
    if dump:
        print "properties:"
        dump_properties(properties)

    return times

def create_timing_dict():
    return dict(zip(PROBES, itertools.repeat(0)))

def print_probe(prefix, name, value, timestamp):
    value = int(value * 1000000)
    print "%(prefix)s.%(name)s:%(value)d@%(timestamp)d" % locals()

def main():
    parser = OptionParser(usage = "%prog [options]")

    parser.add_option("-c", "--count", dest="count", type=int, default=1,
                      help="repeat calls COUNT times", metavar="COUNT")
    parser.add_option("-d", "--dump", dest="dump", action="store_true", default=False,
                      help="dump call output to stdout")

    (options, args) = parser.parse_args()

    bus = dbus.SessionBus()
    proxy = bus.get_object(DBUS_SERVICE, DBUS_PATH)
    menu = dbus.Interface(proxy, dbus_interface=DBUS_INTERFACE)

    if options.dump:
        run_test_sequence(menu, dump=True)
        return

    cumulated_timings = create_timing_dict()
    min_timings = create_timing_dict()
    max_timings = create_timing_dict()
    for x in range(options.count):
        timings = run_test_sequence(menu)
        for name, timing in timings.items():
            cumulated_timings[name] += timing
            if min_timings[name] == 0 or min_timings[name] > timing:
                min_timings[name] = timing
            if max_timings[name] < timing:
                max_timings[name] = timing

    timestamp = int(time.time())
    for name, timing in cumulated_timings.items():
        print_probe("average", name, timing / options.count, timestamp)
    for name, timing in min_timings.items():
        print_probe("min", name, timing, timestamp)
    for name, timing in max_timings.items():
        print_probe("max", name, timing, timestamp)

    return 0


if __name__=="__main__":
    sys.exit(main())
# vi: ts=4 sw=4 et tw=0