Peano
Loading...
Searching...
No Matches
plot-throughput-fv-rusanov.py
Go to the documentation of this file.
1# This file is part of the ExaHyPE2 project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3import argparse
4import numpy as np
5import matplotlib.pyplot as plt
6from matplotlib.ticker import ScalarFormatter, FuncFormatter
7from matplotlib.backends.backend_pgf import FigureCanvasPgf
8
9# Define the LaTeX preamble for the output file
10preamble = r"\usepackage{amsmath,amssymb}"
11
12# Set the rcParams dictionary to use the pgf backend and include the LaTeX preamble
13plt.rcParams.update(
14 {
15 "font.family": "serif",
16 "pgf.texsystem": "pdflatex",
17 "pgf.preamble": preamble,
18 }
19)
20
21
22Devices = ["host", "device"]
23#CallSemantics = ["functors", "stateless"]
24CallSemantics = ["serial", "omp", "sycl"]
25#DataFlow = ["batched", "patch-wise"]
26DataFlow = ["AoS"]
27Markers = ["o", "s", "<", ">", "^", "v", "D"]
28Colours = [
29 "#ff0000",
30 "#00ff00",
31 "#0000ff",
32 "#abab00",
33 "#ab00ab",
34 "#00abab",
35 "#787878",
36 "#ffab50",
37 "#ff50ab",
38 "#abff50",
39 "#50ffab",
40 "#50abff",
41 "#ab50ff",
42]
43OutputFormats = [
44 "png",
45 "pdf",
46 "pgf",
47]
48output_format = "png"
49
50
51def main():
52 parser = argparse.ArgumentParser(
53 description="ExaHyPE 2 - Finite Volume Riemann Kernel Benchmark Throughput Plotting Script"
54 )
55 parser.add_argument(dest="file", help="File to parse")
56 parser.add_argument(
57 "-l",
58 "--log-log",
59 dest="log_log",
60 action="store_true",
61 help="Scale axes to log-log",
62 )
63 parser.add_argument(
64 "-o",
65 "--format",
66 dest="output_format",
67 choices=OutputFormats,
68 default=output_format,
69 help="|".join(OutputFormats),
70 )
71 args = parser.parse_args()
72 data_lines = parse_file(args)
73
74 print("create plot for {}".format(args.file))
75 plt.clf()
76 marker_counter = 0
77 number_of_patches = "xxx"
78 number_of_launching_threads = "xxx"
79 number_of_compute_threads = "xxx"
80
81 for device in Devices:
82 for call_semantics in CallSemantics:
83 for data_flow in DataFlow:
84 (
85 throughput_kernel,
86 throughput_total,
87 number_of_launching_threads,
88 number_of_compute_threads,
89 number_of_patches,
90 ) = search_for_entries(data_lines, device, call_semantics, data_flow)
91 assert len(throughput_total) == len(
92 throughput_kernel
93 ), "data cardinalities {} vs {}".format(
94 len(throughput_total), len(throughput_kernel)
95 )
96 if len(throughput_total) > 0:
97 print(
98 "data found for {}, {}, {}".format(
99 device, call_semantics, data_flow
100 )
101 )
102
103 # Find the key corresponding to the maximal value
104 max_throughput_kernel_label = max(
105 throughput_kernel, key=lambda k: throughput_kernel[k]
106 )
107 # Get the maximal value
108 max_throughput_kernel_value = throughput_kernel[
109 max_throughput_kernel_label
110 ]
111
112 # Find the key corresponding to the maximal value
113 max_throughput_total_label = max(
114 throughput_total, key=lambda k: throughput_total[k]
115 )
116 # Get the maximal value
117 max_throughput_total_value = throughput_total[
118 max_throughput_total_label
119 ]
120
121 plt.scatter(
122 max_throughput_kernel_value,
123 max_throughput_total_value,
124 c=Colours[marker_counter % len(Colours)],
125 marker=Markers[marker_counter % len(Markers)],
126 label=device
127 + ", "
128 + call_semantics
129 + ", "
130 + data_flow
131 + ", ("
132 + max_throughput_kernel_label
133 + " / "
134 + max_throughput_total_label
135 + ")",
136 )
137 marker_counter += 1
138
139 plt.title("Measured throughput - higher is better; only best case labels are shown")
140 plt.legend(bbox_to_anchor=(1.05, 1), loc="upper left")
141 plt.xlabel("Throughput for one kernel (volume updates/s)")
142 plt.ylabel("Total throughput (volume updates/s)")
143 plt.annotate(
144 f"number of patches: {number_of_patches}",
145 xy=(0.5, 0.95),
146 xycoords="axes fraction",
147 ha="center",
148 )
149 plt.annotate(
150 f"number of launching threads: {number_of_launching_threads}",
151 xy=(0.5, 0.90),
152 xycoords="axes fraction",
153 ha="center",
154 )
155 plt.annotate(
156 f"number of compute threads: {number_of_compute_threads}",
157 xy=(0.5, 0.85),
158 xycoords="axes fraction",
159 ha="center",
160 )
161 plt.grid(color="grey", alpha=0.5, linestyle="dashed", linewidth=0.5)
162
163 if args.log_log:
164 plt.xscale("log")
165 plt.yscale("log")
166
167 if args.output_format == "pgf":
168 fig = plt.gcf()
169 canvas = FigureCanvasPgf(fig)
170 canvas.print_figure(args.file + ".pgf", bbox_inches="tight")
171 else:
172 plt.savefig(args.file + "." + args.output_format, bbox_inches="tight")
173
174
175def parse_file(args):
176 # Initialize an empty list to store the lines
177 data_lines = []
178
179 with open(args.file, "r") as file:
180 current_line = ""
181 for line in file:
182 line = line.strip()
183 if line and line[:8].replace(":", "").isdigit():
184 # Start a new line with the timestamp
185 if current_line:
186 data_lines.append(current_line)
187 current_line = line
188 else:
189 # Append subsequent lines to the current line
190 current_line += " " + line
191 # Add the last line to the list
192 if current_line:
193 data_lines.append(current_line)
194
195 return data_lines
196
197
198def search_for_entries(data_lines, device, call_semantics, data_flow):
199 """
200 Search for entries for particular argument combination
201 We return two lists: The first one gives the throughput for one compute kernel
202 while the second one gives the total throughput per measurement including kernel
203 launch overhead.
204 """
205 throughput_kernel = {}
206 throughput_total = {}
207 number_of_patches = "xxx"
208 number_of_launching_threads = "xxx"
209 number_of_compute_threads = "xxx"
210
211 for line in data_lines:
212 if "number of threads launching compute kernels" in line:
213 number_of_launching_threads = line.split(":")[-1].strip()
214 if "number of compute threads" in line:
215 number_of_compute_threads = line.split(":")[-1].strip()
216 if "number of patches" in line:
217 number_of_patches = line.split(":")[-1].strip()
218 if device in line and call_semantics in line and data_flow in line:
219 memory_layout = line.split(",")[3]
220 parallelisation = line.split(",")[4].split(":")[0]
221 current_throughput_kernel = 1.0 / float(line.split("|")[1])
222 current_throughput_total = 1.0 / float(line.split("|")[4])
223 throughput_kernel[
224 memory_layout + ", " + parallelisation
225 ] = current_throughput_kernel
226 throughput_total[
227 memory_layout + ", " + parallelisation
228 ] = current_throughput_total
229 return (
230 throughput_kernel,
231 throughput_total,
232 number_of_launching_threads,
233 number_of_compute_threads,
234 number_of_patches,
235 )
236
237
238if __name__ == "__main__":
239 main()
search_for_entries(data_lines, device, call_semantics, data_flow)
Search for entries for particular argument combination We return two lists: The first one gives the t...