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 | # ruff: noqa
import re
import numpy as np
from collections import defaultdict
from datetime import datetime
from ..utils import check_supported, convert_str_to_tuple
from .utils import parse_params_values
from .cli_configs import ShowReconstructionTimingsConfig
try:
import matplotlib.pyplot as plt
__have_matplotlib__ = True
except ImportError:
__have_matplotlib__ = False
steps_to_measure = [
"Reading data",
"Applying flat-field",
"Applying double flat-field",
"Applying CCD corrections",
"Rotating projections",
"Performing phase retrieval",
"Performing unsharp mask",
"Taking logarithm",
"Applying radios movements",
"Normalizing sinograms",
"Building sinograms", # deprecated
"Removing rings on sinograms",
"Reconstruction",
"Computing histogram",
"Saving data",
]
def extract_timings_from_volume_reconstruction_lines(lines):
regexp = re.compile(r"^(?P<timestamp>\d+-\d+-\d+ \d+:\d+:\d+) - .* - \[0\] (?P<step>.*)$")
start_timestamp = None
current_step = None
res = defaultdict(list)
for line in lines:
match = regexp.match(line.strip())
if match is None:
continue
timestamp = datetime.strptime(match["timestamp"], "%d-%m-%Y %H:%M:%S")
step = match["step"]
if step not in steps_to_measure:
continue
if current_step is not None:
res[current_step].append((timestamp - start_timestamp).total_seconds())
start_timestamp = timestamp
current_step = step
res[current_step].append((timestamp - start_timestamp).total_seconds())
return res
def parse_logfile(fname):
"""
Returns
-------
timings: list of dict
List of dictionaries: one dict per reconstruction in the log file.
For each dict, the key is the pipeline step name, and the value is the list of timings for the different chunks.
"""
with open(fname, "r") as f:
lines = f.readlines()
start_text = "Going to reconstruct slices"
end_text = "Reconstruction completed"
start_line = None
rec_log_bounds = []
for i, line in enumerate(lines):
if start_text in line:
start_line = i
if end_text in line:
if start_line is None:
raise ValueError("Could not find reconstruction start string indicator")
rec_log_bounds.append((start_line, i))
results = []
for bounds in rec_log_bounds:
start, end = bounds
timings = {}
res = extract_timings_from_volume_reconstruction_lines(lines[start:end])
for step in steps_to_measure:
if step in res:
timings[step] = res[step]
results.append(timings)
return results
def display_timings_pie(timings, reduce_function=None, cutoffs=None):
reduce_function = reduce_function or np.median
cutoffs = cutoffs or (0, np.inf)
def _format_pie_text(pct, allvals):
# https://matplotlib.org/stable/gallery/pie_and_polar_charts/pie_and_donut_labels.html
absolute = int(np.round(pct / 100.0 * np.sum(allvals)))
return f"{pct:.1f}%\n({absolute:d} s)"
for run in timings:
fig = plt.figure()
pie_labels = []
pie_sizes = []
for step_name, step_timings in run.items():
t = reduce_function(step_timings)
if t > cutoffs[0] and t < cutoffs[1]:
# pie_labels.append(step_name)
pie_labels.append(step_name + "\n(%d s)" % t)
pie_sizes.append(t)
ax = fig.subplots()
# ax.pie(pie_sizes, labels=pie_labels, autopct=lambda pct: _format_pie_text(pct, pie_sizes)) # autopct='%1.1f%%')
ax.pie(pie_sizes, labels=pie_labels, autopct="%1.1f%%")
fig.show()
input("Press any key to continue")
def parse_reclog_cli():
args = parse_params_values(
ShowReconstructionTimingsConfig, parser_description="Display reconstruction performances from a log file"
)
if not (__have_matplotlib__):
print("Need matplotlib to use this utility")
exit(1)
display_functions = {
"pie": display_timings_pie,
}
logfile = args["logfile"]
cutoff = args["cutoff"]
display_type = args["type"]
check_supported(display_type, display_functions.keys(), "Graphics display type")
if cutoff is not None:
cutoff = list(map(float, convert_str_to_tuple(cutoff)))
timings = parse_logfile(logfile)
display_functions[display_type](timings, cutoffs=cutoff)
return 0
if __name__ == "__main__":
parse_reclog_cli()
exit(0)
|