llvm-project

Форк
0
/
llvm-mca-compare.py 
588 строк · 20.4 Кб
1
#!/usr/bin/env python3
2

3
import argparse
4
import sys
5
import os
6
from json import loads
7
from subprocess import Popen, PIPE
8

9
# Holds code regions statistics.
10
class Summary:
11
    def __init__(
12
        self,
13
        name,
14
        block_rthroughput,
15
        dispatch_width,
16
        ipc,
17
        instructions,
18
        iterations,
19
        total_cycles,
20
        total_uops,
21
        uops_per_cycle,
22
        iteration_resource_pressure,
23
        name_target_info_resources,
24
    ):
25
        self.name = name
26
        self.block_rthroughput = block_rthroughput
27
        self.dispatch_width = dispatch_width
28
        self.ipc = ipc
29
        self.instructions = instructions
30
        self.iterations = iterations
31
        self.total_cycles = total_cycles
32
        self.total_uops = total_uops
33
        self.uops_per_cycle = uops_per_cycle
34
        self.iteration_resource_pressure = iteration_resource_pressure
35
        self.name_target_info_resources = name_target_info_resources
36

37

38
# Parse the program arguments.
39
def parse_program_args(parser):
40
    parser.add_argument(
41
        "file_names",
42
        nargs="+",
43
        type=str,
44
        help="Names of files which llvm-mca tool process.",
45
    )
46
    parser.add_argument(
47
        "--llvm-mca-binary",
48
        nargs=1,
49
        required=True,
50
        type=str,
51
        action="store",
52
        metavar="[=<path to llvm-mca>]",
53
        help="Specified relative path to binary of llvm-mca.",
54
    )
55
    parser.add_argument(
56
        "--args",
57
        nargs=1,
58
        type=str,
59
        action="store",
60
        metavar="[='-option1=<arg> -option2=<arg> ...']",
61
        default=["-"],
62
        help="Forward options to lvm-mca tool.",
63
    )
64
    parser.add_argument(
65
        "-plot",
66
        action="store_true",
67
        default=False,
68
        help="Draw plots of statistics for input files.",
69
    )
70
    parser.add_argument(
71
        "-plot-resource-pressure",
72
        action="store_true",
73
        default=False,
74
        help="Draw plots of resource pressure per iterations for input files.",
75
    )
76
    parser.add_argument(
77
        "--plot-path",
78
        nargs=1,
79
        type=str,
80
        action="store",
81
        metavar="[=<path>]",
82
        default=["-"],
83
        help="Specify relative path where you want to save the plots.",
84
    )
85
    parser.add_argument(
86
        "-v",
87
        action="store_true",
88
        default=False,
89
        help="More details about the running lvm-mca tool.",
90
    )
91
    return parser.parse_args()
92

93

94
# Verify that the program inputs meet the requirements.
95
def verify_program_inputs(opts):
96
    if opts.plot_path[0] != "-" and not opts.plot and not opts.plot_resource_pressure:
97
        print(
98
            "error: Please specify --plot-path only with the -plot or -plot-resource-pressure options."
99
        )
100
        return False
101

102
    return True
103

104

105
# Returns the name of the file to be analyzed from the path it is on.
106
def get_filename_from_path(path):
107
    index_of_slash = path.rfind("/")
108
    return path[(index_of_slash + 1) : len(path)]
109

110

111
# Returns the results of the running llvm-mca tool for the input file.
112
def run_llvm_mca_tool(opts, file_name):
113
    # Get the path of the llvm-mca binary file.
114
    llvm_mca_cmd = opts.llvm_mca_binary[0]
115

116
    # The statistics llvm-mca options.
117
    if opts.args[0] != "-":
118
        llvm_mca_cmd += " " + opts.args[0]
119
    llvm_mca_cmd += " -json"
120

121
    # Set file which llvm-mca tool will process.
122
    llvm_mca_cmd += " " + file_name
123

124
    if opts.v:
125
        print("run: $ " + llvm_mca_cmd + "\n")
126

127
    # Generate the stats with the llvm-mca.
128
    subproc = Popen(
129
        llvm_mca_cmd.split(" "),
130
        stdin=PIPE,
131
        stdout=PIPE,
132
        stderr=PIPE,
133
        universal_newlines=True,
134
    )
135

136
    cmd_stdout, cmd_stderr = subproc.communicate()
137

138
    try:
139
        json_parsed = loads(cmd_stdout)
140
    except:
141
        print("error: No valid llvm-mca statistics found.")
142
        print(cmd_stderr)
143
        sys.exit(1)
144

145
    if opts.v:
146
        print("Simulation Parameters: ")
147
        simulation_parameters = json_parsed["SimulationParameters"]
148
        for key in simulation_parameters:
149
            print(key, ":", simulation_parameters[key])
150
        print("\n")
151

152
    code_regions_len = len(json_parsed["CodeRegions"])
153
    array_of_code_regions = [None] * code_regions_len
154

155
    for i in range(code_regions_len):
156
        code_region_instructions_len = len(
157
            json_parsed["CodeRegions"][i]["Instructions"]
158
        )
159
        target_info_resources_len = len(json_parsed["TargetInfo"]["Resources"])
160
        iteration_resource_pressure = ["-" for k in range(target_info_resources_len)]
161
        resource_pressure_info = json_parsed["CodeRegions"][i]["ResourcePressureView"][
162
            "ResourcePressureInfo"
163
        ]
164

165
        name_target_info_resources = json_parsed["TargetInfo"]["Resources"]
166

167
        for s in range(len(resource_pressure_info)):
168
            obj_of_resource_pressure_info = resource_pressure_info[s]
169
            if (
170
                obj_of_resource_pressure_info["InstructionIndex"]
171
                == code_region_instructions_len
172
            ):
173
                iteration_resource_pressure[
174
                    obj_of_resource_pressure_info["ResourceIndex"]
175
                ] = str(round(obj_of_resource_pressure_info["ResourceUsage"], 2))
176

177
        array_of_code_regions[i] = Summary(
178
            file_name,
179
            json_parsed["CodeRegions"][i]["SummaryView"]["BlockRThroughput"],
180
            json_parsed["CodeRegions"][i]["SummaryView"]["DispatchWidth"],
181
            json_parsed["CodeRegions"][i]["SummaryView"]["IPC"],
182
            json_parsed["CodeRegions"][i]["SummaryView"]["Instructions"],
183
            json_parsed["CodeRegions"][i]["SummaryView"]["Iterations"],
184
            json_parsed["CodeRegions"][i]["SummaryView"]["TotalCycles"],
185
            json_parsed["CodeRegions"][i]["SummaryView"]["TotaluOps"],
186
            json_parsed["CodeRegions"][i]["SummaryView"]["uOpsPerCycle"],
187
            iteration_resource_pressure,
188
            name_target_info_resources,
189
        )
190

191
    return array_of_code_regions
192

193

194
# Print statistics in console for single file or for multiple files.
195
def console_print_results(matrix_of_code_regions, opts):
196
    try:
197
        import termtables as tt
198
    except ImportError:
199
        print("error: termtables not found.")
200
        sys.exit(1)
201

202
    headers_names = [None] * (len(opts.file_names) + 1)
203
    headers_names[0] = " "
204

205
    max_code_regions = 0
206

207
    print("Input files:")
208
    for i in range(len(matrix_of_code_regions)):
209
        if max_code_regions < len(matrix_of_code_regions[i]):
210
            max_code_regions = len(matrix_of_code_regions[i])
211
        print("[f" + str(i + 1) + "]: " + get_filename_from_path(opts.file_names[i]))
212
        headers_names[i + 1] = "[f" + str(i + 1) + "]: "
213

214
    print("\nITERATIONS: " + str(matrix_of_code_regions[0][0].iterations) + "\n")
215

216
    for i in range(max_code_regions):
217

218
        print(
219
            "\n-----------------------------------------\nCode region: "
220
            + str(i + 1)
221
            + "\n"
222
        )
223

224
        table_values = [
225
            [[None] for i in range(len(matrix_of_code_regions) + 1)] for j in range(7)
226
        ]
227

228
        table_values[0][0] = "Instructions: "
229
        table_values[1][0] = "Total Cycles: "
230
        table_values[2][0] = "Total uOps: "
231
        table_values[3][0] = "Dispatch Width: "
232
        table_values[4][0] = "uOps Per Cycle: "
233
        table_values[5][0] = "IPC: "
234
        table_values[6][0] = "Block RThroughput: "
235

236
        for j in range(len(matrix_of_code_regions)):
237
            if len(matrix_of_code_regions[j]) > i:
238
                table_values[0][j + 1] = str(matrix_of_code_regions[j][i].instructions)
239
                table_values[1][j + 1] = str(matrix_of_code_regions[j][i].total_cycles)
240
                table_values[2][j + 1] = str(matrix_of_code_regions[j][i].total_uops)
241
                table_values[3][j + 1] = str(
242
                    matrix_of_code_regions[j][i].dispatch_width
243
                )
244
                table_values[4][j + 1] = str(
245
                    round(matrix_of_code_regions[j][i].uops_per_cycle, 2)
246
                )
247
                table_values[5][j + 1] = str(round(matrix_of_code_regions[j][i].ipc, 2))
248
                table_values[6][j + 1] = str(
249
                    round(matrix_of_code_regions[j][i].block_rthroughput, 2)
250
                )
251
            else:
252
                table_values[0][j + 1] = "-"
253
                table_values[1][j + 1] = "-"
254
                table_values[2][j + 1] = "-"
255
                table_values[3][j + 1] = "-"
256
                table_values[4][j + 1] = "-"
257
                table_values[5][j + 1] = "-"
258
                table_values[6][j + 1] = "-"
259

260
        tt.print(
261
            table_values,
262
            header=headers_names,
263
            style=tt.styles.ascii_thin_double,
264
            padding=(0, 1),
265
        )
266

267
        print("\nResource pressure per iteration: \n")
268

269
        table_values = [
270
            [
271
                [None]
272
                for i in range(
273
                    len(matrix_of_code_regions[0][0].iteration_resource_pressure) + 1
274
                )
275
            ]
276
            for j in range(len(matrix_of_code_regions) + 1)
277
        ]
278

279
        table_values[0] = [" "] + matrix_of_code_regions[0][
280
            0
281
        ].name_target_info_resources
282

283
        for j in range(len(matrix_of_code_regions)):
284
            if len(matrix_of_code_regions[j]) > i:
285
                table_values[j + 1] = [
286
                    "[f" + str(j + 1) + "]: "
287
                ] + matrix_of_code_regions[j][i].iteration_resource_pressure
288
            else:
289
                table_values[j + 1] = ["[f" + str(j + 1) + "]: "] + len(
290
                    matrix_of_code_regions[0][0].iteration_resource_pressure
291
                ) * ["-"]
292

293
        tt.print(
294
            table_values,
295
            style=tt.styles.ascii_thin_double,
296
            padding=(0, 1),
297
        )
298
        print("\n")
299

300

301
# Based on the obtained results (summary view) of llvm-mca tool, draws plots for multiple input files.
302
def draw_plot_files_summary(array_of_summary, opts):
303
    try:
304
        import matplotlib.pyplot as plt
305
    except ImportError:
306
        print("error: matplotlib.pyplot not found.")
307
        sys.exit(1)
308
    try:
309
        from matplotlib.cm import get_cmap
310
    except ImportError:
311
        print("error: get_cmap (matplotlib.cm) not found.")
312
        sys.exit(1)
313

314
    names = [
315
        "Block RThroughput",
316
        "Dispatch Width",
317
        "IPC",
318
        "uOps Per Cycle",
319
        "Instructions",
320
        "Total Cycles",
321
        "Total uOps",
322
    ]
323

324
    rows, cols = (len(opts.file_names), 7)
325

326
    values = [[0 for x in range(cols)] for y in range(rows)]
327

328
    for i in range(len(opts.file_names)):
329
        values[i][0] = array_of_summary[i].block_rthroughput
330
        values[i][1] = array_of_summary[i].dispatch_width
331
        values[i][2] = array_of_summary[i].ipc
332
        values[i][3] = array_of_summary[i].uops_per_cycle
333
        values[i][4] = array_of_summary[i].instructions
334
        values[i][5] = array_of_summary[i].total_cycles
335
        values[i][6] = array_of_summary[i].total_uops
336

337
    fig, axs = plt.subplots(4, 2)
338
    fig.suptitle(
339
        "Machine code statistics", fontsize=20, fontweight="bold", color="black"
340
    )
341
    i = 0
342

343
    for x in range(4):
344
        for y in range(2):
345
            cmap = get_cmap("tab20")
346
            colors = cmap.colors
347
            if not (x == 0 and y == 1) and i < 7:
348
                axs[x][y].grid(True, color="grey", linestyle="--")
349
                maxValue = 0
350
                if i == 0:
351
                    for j in range(len(opts.file_names)):
352
                        if maxValue < values[j][i]:
353
                            maxValue = values[j][i]
354
                        axs[x][y].bar(
355
                            0.3 * j,
356
                            values[j][i],
357
                            width=0.1,
358
                            color=colors[j],
359
                            label=get_filename_from_path(opts.file_names[j]),
360
                        )
361
                else:
362
                    for j in range(len(opts.file_names)):
363
                        if maxValue < values[j][i]:
364
                            maxValue = values[j][i]
365
                        axs[x][y].bar(0.3 * j, values[j][i], width=0.1, color=colors[j])
366
                axs[x][y].set_axisbelow(True)
367
                axs[x][y].set_xlim([-0.3, len(opts.file_names) / 3])
368
                axs[x][y].set_ylim([0, maxValue + (maxValue / 2)])
369
                axs[x][y].set_title(names[i], fontsize=15, fontweight="bold")
370
                axs[x][y].axes.xaxis.set_visible(False)
371
                for j in range(len(opts.file_names)):
372
                    axs[x][y].text(
373
                        0.3 * j,
374
                        values[j][i] + (maxValue / 40),
375
                        s=str(values[j][i]),
376
                        color="black",
377
                        fontweight="bold",
378
                        fontsize=4,
379
                    )
380
                i = i + 1
381

382
    axs[0][1].set_visible(False)
383
    fig.legend(prop={"size": 15})
384
    figg = plt.gcf()
385
    figg.set_size_inches((25, 15), forward=False)
386
    if opts.plot_path[0] == "-":
387
        plt.savefig("llvm-mca-plot.png", dpi=500)
388
        print("The plot was saved within llvm-mca-plot.png")
389
    else:
390
        plt.savefig(
391
            os.path.normpath(os.path.join(opts.plot_path[0], "llvm-mca-plot.png")),
392
            dpi=500,
393
        )
394
        print(
395
            "The plot was saved within {}.".format(
396
                os.path.normpath(os.path.join(opts.plot_path[0], "llvm-mca-plot.png"))
397
            )
398
        )
399

400

401
# Calculates the average value (summary view) per region.
402
def summary_average_code_region(array_of_code_regions, file_name):
403
    summary = Summary(file_name, 0, 0, 0, 0, 0, 0, 0, 0, None, None)
404
    for i in range(len(array_of_code_regions)):
405
        summary.block_rthroughput += array_of_code_regions[i].block_rthroughput
406
        summary.dispatch_width += array_of_code_regions[i].dispatch_width
407
        summary.ipc += array_of_code_regions[i].ipc
408
        summary.instructions += array_of_code_regions[i].instructions
409
        summary.iterations += array_of_code_regions[i].iterations
410
        summary.total_cycles += array_of_code_regions[i].total_cycles
411
        summary.total_uops += array_of_code_regions[i].total_uops
412
        summary.uops_per_cycle += array_of_code_regions[i].uops_per_cycle
413
    summary.block_rthroughput = round(
414
        summary.block_rthroughput / len(array_of_code_regions), 2
415
    )
416
    summary.dispatch_width = round(
417
        summary.dispatch_width / len(array_of_code_regions), 2
418
    )
419
    summary.ipc = round(summary.ipc / len(array_of_code_regions), 2)
420
    summary.instructions = round(summary.instructions / len(array_of_code_regions), 2)
421
    summary.iterations = round(summary.iterations / len(array_of_code_regions), 2)
422
    summary.total_cycles = round(summary.total_cycles / len(array_of_code_regions), 2)
423
    summary.total_uops = round(summary.total_uops / len(array_of_code_regions), 2)
424
    summary.uops_per_cycle = round(
425
        summary.uops_per_cycle / len(array_of_code_regions), 2
426
    )
427
    return summary
428

429

430
# Based on the obtained results (resource pressure per iter) of llvm-mca tool, draws plots for multiple input files.
431
def draw_plot_resource_pressure(
432
    array_average_resource_pressure_per_file, opts, name_target_info_resources
433
):
434
    try:
435
        import matplotlib.pyplot as plt
436
    except ImportError:
437
        print("error: matplotlib.pyplot not found.")
438
        sys.exit(1)
439
    try:
440
        from matplotlib.cm import get_cmap
441
    except ImportError:
442
        print("error: get_cmap (matplotlib.cm) not found.")
443
        sys.exit(1)
444

445
    fig, axs = plt.subplots()
446
    fig.suptitle(
447
        "Resource pressure per iterations",
448
        fontsize=20,
449
        fontweight="bold",
450
        color="black",
451
    )
452

453
    maxValue = 0
454
    for j in range(len(opts.file_names)):
455
        if maxValue < max(array_average_resource_pressure_per_file[j]):
456
            maxValue = max(array_average_resource_pressure_per_file[j])
457

458
    cmap = get_cmap("tab20")
459
    colors = cmap.colors
460

461
    xticklabels = [None] * len(opts.file_names) * len(name_target_info_resources)
462
    index = 0
463

464
    for j in range(len(name_target_info_resources)):
465
        for i in range(len(opts.file_names)):
466
            if i == 0:
467
                axs.bar(
468
                    j * len(opts.file_names) * 10 + i * 10,
469
                    array_average_resource_pressure_per_file[i][j],
470
                    width=1,
471
                    color=colors[j],
472
                    label=name_target_info_resources[j],
473
                )
474
            else:
475
                axs.bar(
476
                    j * len(opts.file_names) * 10 + i * 10,
477
                    array_average_resource_pressure_per_file[i][j],
478
                    width=1,
479
                    color=colors[j],
480
                )
481
            axs.text(
482
                j * len(opts.file_names) * 10 + i * 10,
483
                array_average_resource_pressure_per_file[i][j] + (maxValue / 40),
484
                s=str(array_average_resource_pressure_per_file[i][j]),
485
                color=colors[j],
486
                fontweight="bold",
487
                fontsize=3,
488
            )
489
            xticklabels[index] = opts.file_names[i]
490
            index = index + 1
491

492
    axs.set_xticks(
493
        [
494
            j * len(opts.file_names) * 10 + i * 10
495
            for j in range(len(name_target_info_resources))
496
            for i in range(len(opts.file_names))
497
        ]
498
    )
499
    axs.set_xticklabels(xticklabels, rotation=65)
500

501
    axs.set_axisbelow(True)
502
    axs.set_xlim([-0.5, len(opts.file_names) * len(name_target_info_resources) * 10])
503
    axs.set_ylim([0, maxValue + maxValue / 10])
504

505
    fig.legend(prop={"size": 15})
506
    figg = plt.gcf()
507
    figg.set_size_inches((25, 15), forward=False)
508
    if opts.plot_path[0] == "-":
509
        plt.savefig("llvm-mca-plot-resource-pressure.png", dpi=500)
510
        print("The plot was saved within llvm-mca-plot-resource-pressure.png")
511
    else:
512
        plt.savefig(
513
            os.path.normpath(
514
                os.path.join(opts.plot_path[0], "llvm-mca-plot-resource-pressure.png")
515
            ),
516
            dpi=500,
517
        )
518
        print(
519
            "The plot was saved within {}.".format(
520
                os.path.normpath(
521
                    os.path.join(
522
                        opts.plot_path[0], "llvm-mca-plot-resource-pressure.png"
523
                    )
524
                )
525
            )
526
        )
527

528

529
# Calculates the average value (resource pressure per iter) per region.
530
def average_code_region_resource_pressure(array_of_code_regions, file_name):
531
    resource_pressure_per_iter_one_file = [0] * len(
532
        array_of_code_regions[0].iteration_resource_pressure
533
    )
534
    for i in range(len(array_of_code_regions)):
535
        for j in range(len(array_of_code_regions[i].iteration_resource_pressure)):
536
            if array_of_code_regions[i].iteration_resource_pressure[j] != "-":
537
                resource_pressure_per_iter_one_file[j] += float(
538
                    array_of_code_regions[i].iteration_resource_pressure[j]
539
                )
540
    for i in range(len(resource_pressure_per_iter_one_file)):
541
        resource_pressure_per_iter_one_file[i] = round(
542
            resource_pressure_per_iter_one_file[i] / len(array_of_code_regions), 2
543
        )
544
    return resource_pressure_per_iter_one_file
545

546

547
def Main():
548
    parser = argparse.ArgumentParser()
549
    opts = parse_program_args(parser)
550

551
    if not verify_program_inputs(opts):
552
        parser.print_help()
553
        sys.exit(1)
554

555
    matrix_of_code_regions = [None] * len(opts.file_names)
556

557
    for i in range(len(opts.file_names)):
558
        matrix_of_code_regions[i] = run_llvm_mca_tool(opts, opts.file_names[i])
559
    if not opts.plot and not opts.plot_resource_pressure:
560
        console_print_results(matrix_of_code_regions, opts)
561
    else:
562
        if opts.plot:
563
            array_average_summary_per_file = [None] * len(matrix_of_code_regions)
564
            for j in range(len(matrix_of_code_regions)):
565
                array_average_summary_per_file[j] = summary_average_code_region(
566
                    matrix_of_code_regions[j], opts.file_names[j]
567
                )
568
            draw_plot_files_summary(array_average_summary_per_file, opts)
569
        if opts.plot_resource_pressure:
570
            array_average_resource_pressure_per_file = [None] * len(
571
                matrix_of_code_regions
572
            )
573
            for j in range(len(matrix_of_code_regions)):
574
                array_average_resource_pressure_per_file[
575
                    j
576
                ] = average_code_region_resource_pressure(
577
                    matrix_of_code_regions[j], opts.file_names[j]
578
                )
579
            draw_plot_resource_pressure(
580
                array_average_resource_pressure_per_file,
581
                opts,
582
                matrix_of_code_regions[0][0].name_target_info_resources,
583
            )
584

585

586
if __name__ == "__main__":
587
    Main()
588
    sys.exit(0)
589

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.