]>
Commit | Line | Data |
---|---|---|
f39133ac LP |
1 | #!/usr/bin/python |
2 | ||
3 | import dbus, sys | |
4 | ||
5 | def acquire_time_data(): | |
f39133ac LP |
6 | |
7 | manager = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.systemd1.Manager') | |
f39133ac LP |
8 | units = manager.ListUnits() |
9 | ||
10 | l = [] | |
11 | ||
12 | for i in units: | |
fe8954ab LP |
13 | if i[5] != "": |
14 | continue | |
15 | ||
f39133ac LP |
16 | properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', i[6]), 'org.freedesktop.DBus.Properties') |
17 | ||
b21a0ef8 LP |
18 | ixt = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveExitTimestampMonotonic')) |
19 | aet = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveEnterTimestampMonotonic')) | |
20 | axt = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveExitTimestampMonotonic')) | |
21 | iet = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveEnterTimestampMonotonic')) | |
f39133ac LP |
22 | |
23 | l.append((str(i[0]), ixt, aet, axt, iet)) | |
24 | ||
25 | return l | |
26 | ||
8e028bb1 LP |
27 | def acquire_start_time(): |
28 | properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.DBus.Properties') | |
29 | ||
b21a0ef8 LP |
30 | initrd_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'InitRDTimestampMonotonic')) |
31 | startup_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'StartupTimestampMonotonic')) | |
32 | finish_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'FinishTimestampMonotonic')) | |
8e028bb1 | 33 | |
b21a0ef8 | 34 | assert initrd_time <= startup_time |
8e028bb1 LP |
35 | assert startup_time <= finish_time |
36 | ||
b21a0ef8 | 37 | return initrd_time, startup_time, finish_time |
8e028bb1 LP |
38 | |
39 | def draw_box(context, j, k, l, m, r = 0, g = 0, b = 0): | |
40 | context.save() | |
41 | context.set_source_rgb(r, g, b) | |
42 | context.rectangle(j, k, l, m) | |
43 | context.fill() | |
44 | context.restore() | |
45 | ||
fe8954ab | 46 | def draw_text(context, x, y, text, size = 12, r = 0, g = 0, b = 0, vcenter = 0.5, hcenter = 0.5): |
8e028bb1 LP |
47 | context.save() |
48 | ||
49 | context.set_source_rgb(r, g, b) | |
50 | context.select_font_face("Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) | |
51 | context.set_font_size(size) | |
52 | ||
fe8954ab | 53 | if vcenter or hcenter: |
8e028bb1 | 54 | x_bearing, y_bearing, width, height = context.text_extents(text)[:4] |
fe8954ab LP |
55 | |
56 | if hcenter: | |
57 | x = x - width*hcenter - x_bearing | |
58 | ||
59 | if vcenter: | |
60 | y = y - height*vcenter - y_bearing | |
61 | ||
62 | context.move_to(x, y) | |
8e028bb1 LP |
63 | context.show_text(text) |
64 | ||
65 | context.restore() | |
66 | ||
fe8954ab | 67 | def help(): |
b21a0ef8 LP |
68 | sys.stdout.write("""systemd-analyze time |
69 | systemd-analyze blame | |
fe8954ab LP |
70 | systemd-analyze plot |
71 | ||
72 | Process systemd profiling information | |
73 | ||
74 | -h --help Show this help | |
75 | """) | |
76 | ||
77 | ||
8e028bb1 LP |
78 | bus = dbus.SystemBus() |
79 | ||
b21a0ef8 LP |
80 | if len(sys.argv) <= 1 or sys.argv[1] == 'time': |
81 | ||
82 | initrd_time, start_time, finish_time = acquire_start_time() | |
83 | ||
84 | if initrd_time > 0: | |
85 | print "Startup finished in %lums (kernel) + %lums (initrd) + %lums (userspace) = %lums" % ( \ | |
86 | initrd_time/1000, \ | |
87 | (start_time - initrd_time)/1000, \ | |
88 | (finish_time - start_time)/1000, \ | |
89 | finish_time/1000) | |
90 | else: | |
91 | print "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \ | |
c59c76ca | 92 | start_time/1000, \ |
b21a0ef8 LP |
93 | (finish_time - start_time)/1000, \ |
94 | finish_time/1000) | |
95 | ||
96 | ||
97 | elif sys.argv[1] == 'blame': | |
f39133ac | 98 | |
fac9f8df | 99 | data = acquire_time_data() |
f39133ac LP |
100 | s = sorted(data, key = lambda i: i[2] - i[1], reverse = True) |
101 | ||
8e028bb1 | 102 | for name, ixt, aet, axt, iet in s: |
f39133ac | 103 | |
8e028bb1 | 104 | if ixt <= 0 or aet <= 0: |
f39133ac LP |
105 | continue |
106 | ||
8e028bb1 | 107 | if aet <= ixt: |
f39133ac LP |
108 | continue |
109 | ||
8e028bb1 LP |
110 | sys.stdout.write("%6lums %s\n" % ((aet - ixt) / 1000, name)) |
111 | ||
112 | elif sys.argv[1] == 'plot': | |
113 | import cairo | |
114 | ||
b21a0ef8 | 115 | initrd_time, start_time, finish_time = acquire_start_time() |
8e028bb1 LP |
116 | data = acquire_time_data() |
117 | s = sorted(data, key = lambda i: i[1]) | |
118 | ||
fe8954ab LP |
119 | count = 0 |
120 | ||
121 | for name, ixt, aet, axt, iet in s: | |
122 | ||
123 | if (ixt >= start_time and ixt <= finish_time) or \ | |
124 | (aet >= start_time and aet <= finish_time) or \ | |
125 | (axt >= start_time and axt <= finish_time): | |
126 | count += 1 | |
8e028bb1 | 127 | |
fe8954ab | 128 | border = 100 |
8e028bb1 LP |
129 | bar_height = 20 |
130 | bar_space = bar_height * 0.1 | |
131 | ||
fe8954ab LP |
132 | # 1000px = 10s, 1px = 10ms |
133 | width = (finish_time - start_time)/10000 + border*2 | |
134 | height = count * (bar_height + bar_space) + border * 2 | |
135 | ||
136 | if width < 1000: | |
137 | width = 1000 | |
138 | ||
8e028bb1 LP |
139 | surface = cairo.SVGSurface(sys.stdout, width, height) |
140 | context = cairo.Context(surface) | |
141 | ||
142 | draw_box(context, 0, 0, width, height, 1, 1, 1) | |
143 | ||
144 | context.translate(border + 0.5, border + 0.5) | |
145 | ||
146 | context.save() | |
147 | context.set_line_width(1) | |
148 | context.set_source_rgb(0.7, 0.7, 0.7) | |
149 | ||
150 | for x in range(0, (finish_time - start_time)/10000, 100): | |
151 | context.move_to(x, 0) | |
152 | context.line_to(x, height-border*2) | |
153 | ||
154 | context.move_to(0, 0) | |
155 | context.line_to(width-border*2, 0) | |
156 | ||
157 | context.move_to(0, height-border*2) | |
158 | context.line_to(width-border*2, height-border*2) | |
159 | ||
160 | context.stroke() | |
161 | context.restore() | |
162 | ||
163 | for x in range(0, (finish_time - start_time)/10000, 100): | |
fe8954ab | 164 | draw_text(context, x, -5, "%lus" % (x/100), vcenter = 0, hcenter = 0) |
8e028bb1 LP |
165 | |
166 | y = 0 | |
167 | ||
168 | for name, ixt, aet, axt, iet in s: | |
169 | ||
170 | drawn = False | |
171 | left = -1 | |
172 | ||
fe8954ab | 173 | if ixt >= start_time and ixt <= finish_time: |
8e028bb1 LP |
174 | |
175 | # Activating | |
176 | a = ixt - start_time | |
fe8954ab LP |
177 | b = min(filter(lambda x: x >= ixt, (aet, axt, iet, finish_time))) - ixt |
178 | ||
8e028bb1 LP |
179 | draw_box(context, a/10000, y, b/10000, bar_height, 1, 0, 0) |
180 | drawn = True | |
181 | ||
182 | if left < 0: | |
183 | left = a | |
184 | ||
fe8954ab | 185 | if aet >= start_time and aet <= finish_time: |
8e028bb1 LP |
186 | |
187 | # Active | |
188 | a = aet - start_time | |
fe8954ab LP |
189 | b = min(filter(lambda x: x >= aet, (axt, iet, finish_time))) - aet |
190 | ||
191 | draw_box(context, a/10000, y, b/10000, bar_height, .8, .6, .6) | |
8e028bb1 LP |
192 | drawn = True |
193 | ||
194 | if left < 0: | |
195 | left = a | |
196 | ||
fe8954ab | 197 | if axt >= start_time and axt <= finish_time: |
8e028bb1 LP |
198 | |
199 | # Deactivating | |
200 | a = axt - start_time | |
fe8954ab LP |
201 | b = min(filter(lambda x: x >= axt, (iet, finish_time))) - axt |
202 | ||
8e028bb1 LP |
203 | draw_box(context, a/10000, y, b/10000, bar_height, .6, .4, .4) |
204 | drawn = True | |
205 | ||
206 | if left < 0: | |
207 | left = a | |
208 | ||
209 | if drawn: | |
fe8954ab LP |
210 | x = left/10000 |
211 | ||
212 | if x < width/2-border: | |
213 | draw_text(context, x + 10, y + bar_height/2, name, hcenter = 0) | |
214 | else: | |
215 | draw_text(context, x - 10, y + bar_height/2, name, hcenter = 1) | |
8e028bb1 LP |
216 | |
217 | y += bar_height + bar_space | |
218 | ||
fe8954ab | 219 | draw_text(context, 0, height-border*2, "Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", hcenter = 0, vcenter = -1) |
8e028bb1 | 220 | |
fe8954ab LP |
221 | surface.finish() |
222 | elif sys.argv[1] in ("help", "--help", "-h"): | |
223 | help() | |
fac9f8df LP |
224 | else: |
225 | sys.stderr.write("Unknown verb '%s'.\n" % sys.argv[1]) | |
fe8954ab | 226 | sys.exit(1) |