]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/analyze/systemd-analyze
3 import getopt
, dbus
, sys
, os
9 def acquire_time_data():
11 manager
= dbus
.Interface(bus
.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.systemd1.Manager')
12 units
= manager
.ListUnits()
20 properties
= dbus
.Interface(bus
.get_object('org.freedesktop.systemd1', i
[6]), 'org.freedesktop.DBus.Properties')
22 ixt
= int(properties
.Get('org.freedesktop.systemd1.Unit', 'InactiveExitTimestampMonotonic'))
23 aet
= int(properties
.Get('org.freedesktop.systemd1.Unit', 'ActiveEnterTimestampMonotonic'))
24 axt
= int(properties
.Get('org.freedesktop.systemd1.Unit', 'ActiveExitTimestampMonotonic'))
25 iet
= int(properties
.Get('org.freedesktop.systemd1.Unit', 'InactiveEnterTimestampMonotonic'))
27 l
.append((str(i
[0]), ixt
, aet
, axt
, iet
))
31 def acquire_start_time():
32 properties
= dbus
.Interface(bus
.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.DBus.Properties')
34 initrd_time
= int(properties
.Get('org.freedesktop.systemd1.Manager', 'InitRDTimestampMonotonic'))
35 userspace_time
= int(properties
.Get('org.freedesktop.systemd1.Manager', 'UserspaceTimestampMonotonic'))
36 finish_time
= int(properties
.Get('org.freedesktop.systemd1.Manager', 'FinishTimestampMonotonic'))
39 sys
.stderr
.write("Bootup is not yet finished. Please try again later.\n")
42 assert initrd_time
<= userspace_time
43 assert userspace_time
<= finish_time
45 return initrd_time
, userspace_time
, finish_time
47 def draw_box(context
, j
, k
, l
, m
, r
= 0, g
= 0, b
= 0):
49 context
.set_source_rgb(r
, g
, b
)
50 context
.rectangle(j
, k
, l
, m
)
54 def draw_text(context
, x
, y
, text
, size
= 12, r
= 0, g
= 0, b
= 0, vcenter
= 0.5, hcenter
= 0.5):
57 context
.set_source_rgb(r
, g
, b
)
58 context
.select_font_face("Sans", cairo
.FONT_SLANT_NORMAL
, cairo
.FONT_WEIGHT_NORMAL
)
59 context
.set_font_size(size
)
61 if vcenter
or hcenter
:
62 x_bearing
, y_bearing
, width
, height
= context
.text_extents(text
)[:4]
65 x
= x
- width
*hcenter
- x_bearing
68 y
= y
- height
*vcenter
- y_bearing
71 context
.show_text(text
)
76 sys
.stdout
.write("""systemd-analyze [--user] time
77 systemd-analyze [--user] blame
78 systemd-analyze [--user] plot
80 Process systemd profiling information
82 -h --help Show this help
91 initrd_time
, start_time
, finish_time
= acquire_start_time()
94 sys
.stdout
.write("Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums\n" % ( \
96 (start_time
- initrd_time
)/1000, \
97 (finish_time
- start_time
)/1000, \
100 sys
.stdout
.write("Startup finished in %lums (kernel) + %lums (userspace) = %lums\n" % ( \
102 (finish_time
- start_time
)/1000, \
108 data
= acquire_time_data()
109 s
= sorted(data
, key
= lambda i
: i
[2] - i
[1], reverse
= True)
111 for name
, ixt
, aet
, axt
, iet
in s
:
113 if ixt
<= 0 or aet
<= 0:
119 sys
.stdout
.write("%6lums %s\n" % ((aet
- ixt
) / 1000, name
))
123 sys
.stderr
.write("Failed to initilize python-cairo required for 'plot' verb.\n")
125 initrd_time
, start_time
, finish_time
= acquire_start_time()
126 data
= acquire_time_data()
127 s
= sorted(data
, key
= lambda i
: i
[1])
129 # Account for kernel and initramfs bars if they exist
135 for name
, ixt
, aet
, axt
, iet
in s
:
137 if (ixt
>= start_time
and ixt
<= finish_time
) or \
138 (aet
>= start_time
and aet
<= finish_time
) or \
139 (axt
>= start_time
and axt
<= finish_time
):
144 bar_space
= bar_height
* 0.1
146 # 1000px = 10s, 1px = 10ms
147 width
= finish_time
/10000 + border
*2
148 height
= count
* (bar_height
+ bar_space
) + border
* 2
153 surface
= cairo
.SVGSurface(sys
.stdout
, width
, height
)
154 context
= cairo
.Context(surface
)
156 draw_box(context
, 0, 0, width
, height
, 1, 1, 1)
158 context
.translate(border
+ 0.5, border
+ 0.5)
161 context
.set_line_width(1)
162 context
.set_source_rgb(0.7, 0.7, 0.7)
164 for x
in range(0, int(finish_time
/10000) + 100, 100):
165 context
.move_to(x
, 0)
166 context
.line_to(x
, height
-border
*2)
168 context
.move_to(0, 0)
169 context
.line_to(width
-border
*2, 0)
171 context
.move_to(0, height
-border
*2)
172 context
.line_to(width
-border
*2, height
-border
*2)
178 if os
.path
.exists("/etc/os-release"):
179 for line
in open("/etc/os-release"):
180 if line
.startswith('PRETTY_NAME='):
182 osrel
= osrel
.strip('\"\n')
185 banner
= "{} {} ({} {}) {}".format(osrel
, *(os
.uname()[1:5]))
186 draw_text(context
, 0, -15, banner
, hcenter
= 0, vcenter
= 1)
188 for x
in range(0, int(finish_time
/10000) + 100, 100):
189 draw_text(context
, x
, -5, "%lus" % (x
/100), vcenter
= 0, hcenter
= 0)
193 # draw boxes for kernel and initramfs boot time
195 draw_box(context
, 0, y
, initrd_time
/10000, bar_height
, 0.7, 0.7, 0.7)
196 draw_text(context
, 10, y
+ bar_height
/2, "kernel", hcenter
= 0)
197 y
+= bar_height
+ bar_space
199 draw_box(context
, initrd_time
/10000, y
, start_time
/10000-initrd_time
/10000, bar_height
, 0.7, 0.7, 0.7)
200 draw_text(context
, initrd_time
/10000 + 10, y
+ bar_height
/2, "initramfs", hcenter
= 0)
201 y
+= bar_height
+ bar_space
204 draw_box(context
, 0, y
, start_time
/10000, bar_height
, 0.6, 0.6, 0.6)
205 draw_text(context
, 10, y
+ bar_height
/2, "kernel", hcenter
= 0)
206 y
+= bar_height
+ bar_space
208 draw_box(context
, start_time
/10000, y
, finish_time
/10000-start_time
/10000, bar_height
, 0.7, 0.7, 0.7)
209 draw_text(context
, start_time
/10000 + 10, y
+ bar_height
/2, "userspace", hcenter
= 0)
210 y
+= bar_height
+ bar_space
212 for name
, ixt
, aet
, axt
, iet
in s
:
217 if ixt
>= start_time
and ixt
<= finish_time
:
221 b
= min(filter(lambda x
: x
>= ixt
, (aet
, axt
, iet
, finish_time
))) - ixt
223 draw_box(context
, a
/10000, y
, b
/10000, bar_height
, 1, 0, 0)
229 if aet
>= start_time
and aet
<= finish_time
:
233 b
= min(filter(lambda x
: x
>= aet
, (axt
, iet
, finish_time
))) - aet
235 draw_box(context
, a
/10000, y
, b
/10000, bar_height
, .8, .6, .6)
241 if axt
>= start_time
and axt
<= finish_time
:
245 b
= min(filter(lambda x
: x
>= axt
, (iet
, finish_time
))) - axt
247 draw_box(context
, a
/10000, y
, b
/10000, bar_height
, .6, .4, .4)
256 if x
< width
/2-border
:
257 draw_text(context
, x
+ 10, y
+ bar_height
/2, name
, hcenter
= 0)
259 draw_text(context
, x
- 10, y
+ bar_height
/2, name
, hcenter
= 1)
261 y
+= bar_height
+ bar_space
263 draw_text(context
, 0, height
-border
*2, "Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", hcenter
= 0, vcenter
= -1)
266 draw_text(context
, 0, height
-border
*2 + bar_height
, "Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums" % ( \
268 (start_time
- initrd_time
)/1000, \
269 (finish_time
- start_time
)/1000, \
270 finish_time
/1000), hcenter
= 0, vcenter
= -1)
272 draw_text(context
, 0, height
-border
*2 + bar_height
, "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \
274 (finish_time
- start_time
)/1000, \
275 finish_time
/1000), hcenter
= 0, vcenter
= -1)
280 sys
.stderr
.write("Unknown verb '%s'.\n" % args
[0])
284 bus
= dbus
.SystemBus()
287 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:], "h", ["help", "user"])
288 except getopt
.GetoptError
as err
:
289 sys
.stdout
.write(str(err
) + "\n")
293 if o
in ("-h", "--help"):
296 bus
= dbus
.SessionBus()
298 assert False, "unhandled option"
300 verb
= {'time' : time
,
309 verb
.get(args
[0], unknown_verb
)()