1cc1dc7a3Sopenharmony_ci#!/usr/bin/env python3
2cc1dc7a3Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0
3cc1dc7a3Sopenharmony_ci# -----------------------------------------------------------------------------
4cc1dc7a3Sopenharmony_ci# Copyright 2020-2022 Arm Limited
5cc1dc7a3Sopenharmony_ci#
6cc1dc7a3Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); you may not
7cc1dc7a3Sopenharmony_ci# use this file except in compliance with the License. You may obtain a copy
8cc1dc7a3Sopenharmony_ci# of the License at:
9cc1dc7a3Sopenharmony_ci#
10cc1dc7a3Sopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
11cc1dc7a3Sopenharmony_ci#
12cc1dc7a3Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
13cc1dc7a3Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14cc1dc7a3Sopenharmony_ci# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15cc1dc7a3Sopenharmony_ci# License for the specific language governing permissions and limitations
16cc1dc7a3Sopenharmony_ci# under the License.
17cc1dc7a3Sopenharmony_ci# -----------------------------------------------------------------------------
18cc1dc7a3Sopenharmony_ci"""
19cc1dc7a3Sopenharmony_ciThe ``astc_test_result_plot.py`` script consolidates all current sets of
20cc1dc7a3Sopenharmony_cireference results into a single graphical plot.
21cc1dc7a3Sopenharmony_ci"""
22cc1dc7a3Sopenharmony_ci
23cc1dc7a3Sopenharmony_ciimport re
24cc1dc7a3Sopenharmony_ciimport os
25cc1dc7a3Sopenharmony_ciimport sys
26cc1dc7a3Sopenharmony_ci
27cc1dc7a3Sopenharmony_ciimport numpy as np
28cc1dc7a3Sopenharmony_ciimport matplotlib.pyplot as plt
29cc1dc7a3Sopenharmony_ci
30cc1dc7a3Sopenharmony_ciimport testlib.resultset as trs
31cc1dc7a3Sopenharmony_cifrom collections import defaultdict as ddict
32cc1dc7a3Sopenharmony_ci
33cc1dc7a3Sopenharmony_ci
34cc1dc7a3Sopenharmony_cidef find_reference_results():
35cc1dc7a3Sopenharmony_ci    """
36cc1dc7a3Sopenharmony_ci    Scrape the Test/Images directory for result CSV files and return an
37cc1dc7a3Sopenharmony_ci    mapping of the result sets.
38cc1dc7a3Sopenharmony_ci
39cc1dc7a3Sopenharmony_ci    Returns:
40cc1dc7a3Sopenharmony_ci        Returns a three deep tree of dictionaries, with the final dict
41cc1dc7a3Sopenharmony_ci        pointing at a `ResultSet` object. The hierarchy is:
42cc1dc7a3Sopenharmony_ci
43cc1dc7a3Sopenharmony_ci            imageSet => quality => encoder => result
44cc1dc7a3Sopenharmony_ci    """
45cc1dc7a3Sopenharmony_ci    scriptDir = os.path.dirname(__file__)
46cc1dc7a3Sopenharmony_ci    imageDir = os.path.join(scriptDir, "Images")
47cc1dc7a3Sopenharmony_ci
48cc1dc7a3Sopenharmony_ci    # Pattern for extracting useful data from the CSV file name
49cc1dc7a3Sopenharmony_ci    filePat = re.compile(r"astc_reference-(.+)_(.+)_results\.csv")
50cc1dc7a3Sopenharmony_ci
51cc1dc7a3Sopenharmony_ci    # Build a three level dictionary we can write into
52cc1dc7a3Sopenharmony_ci    results = ddict(lambda: ddict(lambda: ddict()))
53cc1dc7a3Sopenharmony_ci
54cc1dc7a3Sopenharmony_ci    # Final all CSVs, load them and store them in the dict tree
55cc1dc7a3Sopenharmony_ci    for root, dirs, files in os.walk(imageDir):
56cc1dc7a3Sopenharmony_ci        for name in files:
57cc1dc7a3Sopenharmony_ci            match = filePat.match(name)
58cc1dc7a3Sopenharmony_ci            if match:
59cc1dc7a3Sopenharmony_ci                fullPath = os.path.join(root, name)
60cc1dc7a3Sopenharmony_ci
61cc1dc7a3Sopenharmony_ci                encoder = match.group(1)
62cc1dc7a3Sopenharmony_ci                quality = match.group(2)
63cc1dc7a3Sopenharmony_ci                imageSet = os.path.basename(root)
64cc1dc7a3Sopenharmony_ci
65cc1dc7a3Sopenharmony_ci                if imageSet not in ["Kodak", "Khronos", "HDRIHaven", "KodakSim"]:
66cc1dc7a3Sopenharmony_ci                    continue
67cc1dc7a3Sopenharmony_ci
68cc1dc7a3Sopenharmony_ci                testRef = trs.ResultSet(imageSet)
69cc1dc7a3Sopenharmony_ci                testRef.load_from_file(fullPath)
70cc1dc7a3Sopenharmony_ci
71cc1dc7a3Sopenharmony_ci                results[imageSet][quality]["ref-%s" % encoder] = testRef
72cc1dc7a3Sopenharmony_ci
73cc1dc7a3Sopenharmony_ci    return results
74cc1dc7a3Sopenharmony_ci
75cc1dc7a3Sopenharmony_ci
76cc1dc7a3Sopenharmony_cidef get_series(results, tgtEncoder, tgtQuality, resFilter=lambda x: True):
77cc1dc7a3Sopenharmony_ci    psnrData = []
78cc1dc7a3Sopenharmony_ci    mtsData = []
79cc1dc7a3Sopenharmony_ci    marker = []
80cc1dc7a3Sopenharmony_ci    records = []
81cc1dc7a3Sopenharmony_ci
82cc1dc7a3Sopenharmony_ci    for imageSet, iResults in results.items():
83cc1dc7a3Sopenharmony_ci
84cc1dc7a3Sopenharmony_ci        for quality, qResults in iResults.items():
85cc1dc7a3Sopenharmony_ci            if quality != tgtQuality:
86cc1dc7a3Sopenharmony_ci                continue
87cc1dc7a3Sopenharmony_ci
88cc1dc7a3Sopenharmony_ci            for encoder, eResults in qResults.items():
89cc1dc7a3Sopenharmony_ci                if encoder != tgtEncoder:
90cc1dc7a3Sopenharmony_ci                    continue
91cc1dc7a3Sopenharmony_ci
92cc1dc7a3Sopenharmony_ci                for record in eResults.records:
93cc1dc7a3Sopenharmony_ci                    if resFilter(record):
94cc1dc7a3Sopenharmony_ci                        records.append(record)
95cc1dc7a3Sopenharmony_ci                        psnrData.append(record.psnr)
96cc1dc7a3Sopenharmony_ci                        mtsData.append(record.cRate)
97cc1dc7a3Sopenharmony_ci
98cc1dc7a3Sopenharmony_ci                        if "ldr-xy" in record.name:
99cc1dc7a3Sopenharmony_ci                            marker.append('$N$')
100cc1dc7a3Sopenharmony_ci                        elif "ldr-l" in record.name:
101cc1dc7a3Sopenharmony_ci                            marker.append('$G$')
102cc1dc7a3Sopenharmony_ci                        elif "ldr" in record.name:
103cc1dc7a3Sopenharmony_ci                            marker.append('$L$')
104cc1dc7a3Sopenharmony_ci                        elif "hdr" in record.name:
105cc1dc7a3Sopenharmony_ci                            marker.append('$H$')
106cc1dc7a3Sopenharmony_ci                        else:
107cc1dc7a3Sopenharmony_ci                            marker.append('$?$')
108cc1dc7a3Sopenharmony_ci
109cc1dc7a3Sopenharmony_ci
110cc1dc7a3Sopenharmony_ci    return mtsData, psnrData, marker, records
111cc1dc7a3Sopenharmony_ci
112cc1dc7a3Sopenharmony_ci
113cc1dc7a3Sopenharmony_cidef get_series_rel(results, refEncoder, refQuality, tgtEncoder, tgtQuality, resFilter=lambda x: True):
114cc1dc7a3Sopenharmony_ci
115cc1dc7a3Sopenharmony_ci    mts1, psnr1, marker1, rec1 = get_series(results, tgtEncoder, tgtQuality, resFilter)
116cc1dc7a3Sopenharmony_ci
117cc1dc7a3Sopenharmony_ci    if refEncoder is None:
118cc1dc7a3Sopenharmony_ci        refEncoder = tgtEncoder
119cc1dc7a3Sopenharmony_ci
120cc1dc7a3Sopenharmony_ci    if refQuality is None:
121cc1dc7a3Sopenharmony_ci        refQuality = tgtQuality
122cc1dc7a3Sopenharmony_ci
123cc1dc7a3Sopenharmony_ci    mts2, psnr2, marker2, rec2 = get_series(results, refEncoder, refQuality, resFilter)
124cc1dc7a3Sopenharmony_ci
125cc1dc7a3Sopenharmony_ci    mtsm  = [x/mts2[i] for i, x in enumerate(mts1)]
126cc1dc7a3Sopenharmony_ci    psnrm = [x - psnr2[i] for i, x in enumerate(psnr1)]
127cc1dc7a3Sopenharmony_ci
128cc1dc7a3Sopenharmony_ci    return mtsm, psnrm, marker1, rec1
129cc1dc7a3Sopenharmony_ci
130cc1dc7a3Sopenharmony_ci
131cc1dc7a3Sopenharmony_cidef get_human_eq_name(encoder, quality):
132cc1dc7a3Sopenharmony_ci    parts = encoder.split("-")
133cc1dc7a3Sopenharmony_ci    if len(parts) == 2:
134cc1dc7a3Sopenharmony_ci        return "astcenc %s -%s" % (parts[1], quality)
135cc1dc7a3Sopenharmony_ci    else:
136cc1dc7a3Sopenharmony_ci        return "astcenc-%s %s -%s" % (parts[2], parts[1], quality)
137cc1dc7a3Sopenharmony_ci
138cc1dc7a3Sopenharmony_ci
139cc1dc7a3Sopenharmony_cidef get_human_e_name(encoder):
140cc1dc7a3Sopenharmony_ci    parts = encoder.split("-")
141cc1dc7a3Sopenharmony_ci    if len(parts) == 2:
142cc1dc7a3Sopenharmony_ci        return "astcenc %s" % parts[1]
143cc1dc7a3Sopenharmony_ci    else:
144cc1dc7a3Sopenharmony_ci        return "astcenc-%s %s" % (parts[2], parts[1])
145cc1dc7a3Sopenharmony_ci
146cc1dc7a3Sopenharmony_ci
147cc1dc7a3Sopenharmony_cidef get_human_q_name(quality):
148cc1dc7a3Sopenharmony_ci    return "-%s" % quality
149cc1dc7a3Sopenharmony_ci
150cc1dc7a3Sopenharmony_ci
151cc1dc7a3Sopenharmony_cidef plot(results, chartRows, chartCols, blockSizes,
152cc1dc7a3Sopenharmony_ci         relative, pivotEncoder, pivotQuality, fileName, limits):
153cc1dc7a3Sopenharmony_ci
154cc1dc7a3Sopenharmony_ci    fig, axs = plt.subplots(nrows=len(chartRows), ncols=len(chartCols),
155cc1dc7a3Sopenharmony_ci                            sharex=True, sharey=True, figsize=(15, 8.43))
156cc1dc7a3Sopenharmony_ci
157cc1dc7a3Sopenharmony_ci    for a in fig.axes:
158cc1dc7a3Sopenharmony_ci        a.tick_params(
159cc1dc7a3Sopenharmony_ci            axis="x", which="both",
160cc1dc7a3Sopenharmony_ci            bottom=True, top=False, labelbottom=True)
161cc1dc7a3Sopenharmony_ci
162cc1dc7a3Sopenharmony_ci        a.tick_params(
163cc1dc7a3Sopenharmony_ci            axis="y", which="both",
164cc1dc7a3Sopenharmony_ci            left=True, right=False, labelleft=True)
165cc1dc7a3Sopenharmony_ci
166cc1dc7a3Sopenharmony_ci    for i, row in enumerate(chartRows):
167cc1dc7a3Sopenharmony_ci        for j, col in enumerate(chartCols):
168cc1dc7a3Sopenharmony_ci            if row == "fastest" and (("1.7" in col) or ("2.0" in col)):
169cc1dc7a3Sopenharmony_ci                if len(chartCols) == 1:
170cc1dc7a3Sopenharmony_ci                    fig.delaxes(axs[i])
171cc1dc7a3Sopenharmony_ci                else:
172cc1dc7a3Sopenharmony_ci                    fig.delaxes(axs[i][j])
173cc1dc7a3Sopenharmony_ci                continue
174cc1dc7a3Sopenharmony_ci
175cc1dc7a3Sopenharmony_ci            if len(chartRows) == 1 and len(chartCols) == 1:
176cc1dc7a3Sopenharmony_ci                ax = axs
177cc1dc7a3Sopenharmony_ci            elif len(chartCols) == 1:
178cc1dc7a3Sopenharmony_ci                ax = axs[i]
179cc1dc7a3Sopenharmony_ci            else:
180cc1dc7a3Sopenharmony_ci                ax = axs[i, j]
181cc1dc7a3Sopenharmony_ci
182cc1dc7a3Sopenharmony_ci            title = get_human_eq_name(col, row)
183cc1dc7a3Sopenharmony_ci
184cc1dc7a3Sopenharmony_ci            if not relative:
185cc1dc7a3Sopenharmony_ci                ax.set_title(title, y=0.97, backgroundcolor="white")
186cc1dc7a3Sopenharmony_ci                ax.set_xlabel('Coding performance (MTex/s)')
187cc1dc7a3Sopenharmony_ci                ax.set_ylabel('PSNR (dB)')
188cc1dc7a3Sopenharmony_ci            else:
189cc1dc7a3Sopenharmony_ci                if pivotEncoder and pivotQuality:
190cc1dc7a3Sopenharmony_ci                    tag = get_human_eq_name(pivotEncoder, pivotQuality)
191cc1dc7a3Sopenharmony_ci                elif pivotEncoder:
192cc1dc7a3Sopenharmony_ci                    tag = get_human_e_name(pivotEncoder)
193cc1dc7a3Sopenharmony_ci                else:
194cc1dc7a3Sopenharmony_ci                    assert(pivotQuality)
195cc1dc7a3Sopenharmony_ci                    tag = get_human_q_name(pivotQuality)
196cc1dc7a3Sopenharmony_ci
197cc1dc7a3Sopenharmony_ci                ax.set_title("%s vs. %s" % (title, tag), y=0.97, backgroundcolor="white")
198cc1dc7a3Sopenharmony_ci                ax.set_xlabel('Performance scaling')
199cc1dc7a3Sopenharmony_ci                ax.set_ylabel('PSNR delta (dB)')
200cc1dc7a3Sopenharmony_ci
201cc1dc7a3Sopenharmony_ci            for k, series in enumerate(blockSizes):
202cc1dc7a3Sopenharmony_ci                fn = lambda x: x.blkSz == series
203cc1dc7a3Sopenharmony_ci
204cc1dc7a3Sopenharmony_ci                if not relative:
205cc1dc7a3Sopenharmony_ci                    x, y, m, r = get_series(results, col, row, fn)
206cc1dc7a3Sopenharmony_ci                else:
207cc1dc7a3Sopenharmony_ci                    x, y, m, r = get_series_rel(results, pivotEncoder, pivotQuality,
208cc1dc7a3Sopenharmony_ci                                                col, row, fn)
209cc1dc7a3Sopenharmony_ci
210cc1dc7a3Sopenharmony_ci                color = None
211cc1dc7a3Sopenharmony_ci                label = "%s blocks" % series
212cc1dc7a3Sopenharmony_ci                for xp, yp, mp in zip(x, y, m):
213cc1dc7a3Sopenharmony_ci                    ax.scatter([xp],[yp], s=16, marker=mp,
214cc1dc7a3Sopenharmony_ci                               color="C%u" % k, label=label)
215cc1dc7a3Sopenharmony_ci                    label = None
216cc1dc7a3Sopenharmony_ci
217cc1dc7a3Sopenharmony_ci            if i == 0 and j == 0:
218cc1dc7a3Sopenharmony_ci                ax.legend(loc="lower right")
219cc1dc7a3Sopenharmony_ci
220cc1dc7a3Sopenharmony_ci    for i, row in enumerate(chartRows):
221cc1dc7a3Sopenharmony_ci        for j, col in enumerate(chartCols):
222cc1dc7a3Sopenharmony_ci
223cc1dc7a3Sopenharmony_ci            if len(chartRows) == 1 and len(chartCols) == 1:
224cc1dc7a3Sopenharmony_ci                ax = axs
225cc1dc7a3Sopenharmony_ci            elif len(chartCols) == 1:
226cc1dc7a3Sopenharmony_ci                ax = axs[i]
227cc1dc7a3Sopenharmony_ci            else:
228cc1dc7a3Sopenharmony_ci                ax = axs[i, j]
229cc1dc7a3Sopenharmony_ci
230cc1dc7a3Sopenharmony_ci            ax.grid(ls=':')
231cc1dc7a3Sopenharmony_ci
232cc1dc7a3Sopenharmony_ci            if limits and limits[0]:
233cc1dc7a3Sopenharmony_ci                ax.set_xlim(left=limits[0][0], right=limits[0][1])
234cc1dc7a3Sopenharmony_ci            if limits and limits[1]:
235cc1dc7a3Sopenharmony_ci                ax.set_ylim(bottom=limits[1][0], top=limits[1][1])
236cc1dc7a3Sopenharmony_ci
237cc1dc7a3Sopenharmony_ci    fig.tight_layout()
238cc1dc7a3Sopenharmony_ci    fig.savefig(fileName)
239cc1dc7a3Sopenharmony_ci
240cc1dc7a3Sopenharmony_ci
241cc1dc7a3Sopenharmony_cidef main():
242cc1dc7a3Sopenharmony_ci    """
243cc1dc7a3Sopenharmony_ci    The main function.
244cc1dc7a3Sopenharmony_ci
245cc1dc7a3Sopenharmony_ci    Returns:
246cc1dc7a3Sopenharmony_ci        int: The process return code.
247cc1dc7a3Sopenharmony_ci    """
248cc1dc7a3Sopenharmony_ci    absXMin = 0
249cc1dc7a3Sopenharmony_ci    absXMax = 80
250cc1dc7a3Sopenharmony_ci    absXLimits = (absXMin, absXMax)
251cc1dc7a3Sopenharmony_ci
252cc1dc7a3Sopenharmony_ci    relXMin = 0.8
253cc1dc7a3Sopenharmony_ci    relXMax = None
254cc1dc7a3Sopenharmony_ci    relXLimits = (relXMin, relXMax)
255cc1dc7a3Sopenharmony_ci
256cc1dc7a3Sopenharmony_ci    last1x = "1.7"
257cc1dc7a3Sopenharmony_ci    last2x = "2.5"
258cc1dc7a3Sopenharmony_ci    last3x = "3.7"
259cc1dc7a3Sopenharmony_ci    prev4x = "4.3"
260cc1dc7a3Sopenharmony_ci    last4x = "4.4"
261cc1dc7a3Sopenharmony_ci    lastMain = "main"
262cc1dc7a3Sopenharmony_ci
263cc1dc7a3Sopenharmony_ci    charts = [
264cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
265cc1dc7a3Sopenharmony_ci        # Latest in stable series charts
266cc1dc7a3Sopenharmony_ci        [
267cc1dc7a3Sopenharmony_ci            # Relative scores
268cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast"],
269cc1dc7a3Sopenharmony_ci            [f"ref-{last2x}-avx2", f"ref-{last3x}-avx2", f"ref-{last4x}-avx2"],
270cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
271cc1dc7a3Sopenharmony_ci            True,
272cc1dc7a3Sopenharmony_ci            f"ref-{last1x}",
273cc1dc7a3Sopenharmony_ci            None,
274cc1dc7a3Sopenharmony_ci            "results-relative-stable-series.png",
275cc1dc7a3Sopenharmony_ci            (None, None)
276cc1dc7a3Sopenharmony_ci        ], [
277cc1dc7a3Sopenharmony_ci            # Absolute scores
278cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast"],
279cc1dc7a3Sopenharmony_ci            [f"ref-{last1x}", f"ref-{last2x}-avx2", f"ref-{last3x}-avx2", f"ref-{last4x}-avx2"],
280cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
281cc1dc7a3Sopenharmony_ci            False,
282cc1dc7a3Sopenharmony_ci            None,
283cc1dc7a3Sopenharmony_ci            None,
284cc1dc7a3Sopenharmony_ci            "results-absolute-stable-series.png",
285cc1dc7a3Sopenharmony_ci            (absXLimits, None)
286cc1dc7a3Sopenharmony_ci        ],
287cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
288cc1dc7a3Sopenharmony_ci        # Latest 2.x vs 1.x release charts
289cc1dc7a3Sopenharmony_ci        [
290cc1dc7a3Sopenharmony_ci            # Relative scores
291cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast"],
292cc1dc7a3Sopenharmony_ci            [f"ref-{last2x}-avx2"],
293cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
294cc1dc7a3Sopenharmony_ci            True,
295cc1dc7a3Sopenharmony_ci            f"ref-{last1x}",
296cc1dc7a3Sopenharmony_ci            None,
297cc1dc7a3Sopenharmony_ci            "results-relative-2.x-vs-1.x.png",
298cc1dc7a3Sopenharmony_ci            (None, None)
299cc1dc7a3Sopenharmony_ci        ],
300cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
301cc1dc7a3Sopenharmony_ci        # Latest 3.x vs 1.x release charts
302cc1dc7a3Sopenharmony_ci        [
303cc1dc7a3Sopenharmony_ci            # Relative scores
304cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast"],
305cc1dc7a3Sopenharmony_ci            [f"ref-{last3x}-avx2"],
306cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
307cc1dc7a3Sopenharmony_ci            True,
308cc1dc7a3Sopenharmony_ci            f"ref-{last1x}",
309cc1dc7a3Sopenharmony_ci            None,
310cc1dc7a3Sopenharmony_ci            "results-relative-3.x-vs-1.x.png",
311cc1dc7a3Sopenharmony_ci            (None, None)
312cc1dc7a3Sopenharmony_ci        ],
313cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
314cc1dc7a3Sopenharmony_ci        # Latest 4.x vs 1.x release charts
315cc1dc7a3Sopenharmony_ci        [
316cc1dc7a3Sopenharmony_ci            # Relative scores
317cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast"],
318cc1dc7a3Sopenharmony_ci            [f"ref-{last4x}-avx2"],
319cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
320cc1dc7a3Sopenharmony_ci            True,
321cc1dc7a3Sopenharmony_ci            f"ref-{last1x}",
322cc1dc7a3Sopenharmony_ci            None,
323cc1dc7a3Sopenharmony_ci            "results-relative-4.x-vs-1.x.png",
324cc1dc7a3Sopenharmony_ci            (None, None)
325cc1dc7a3Sopenharmony_ci        ],
326cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
327cc1dc7a3Sopenharmony_ci        # Latest 3.x vs 2.x release charts
328cc1dc7a3Sopenharmony_ci        [
329cc1dc7a3Sopenharmony_ci            # Relative scores
330cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast", "fastest"],
331cc1dc7a3Sopenharmony_ci            [f"ref-{last3x}-avx2"],
332cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
333cc1dc7a3Sopenharmony_ci            True,
334cc1dc7a3Sopenharmony_ci            f"ref-{last2x}-avx2",
335cc1dc7a3Sopenharmony_ci            None,
336cc1dc7a3Sopenharmony_ci            "results-relative-3.x-vs-2.x.png",
337cc1dc7a3Sopenharmony_ci            (None, None)
338cc1dc7a3Sopenharmony_ci        ],
339cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
340cc1dc7a3Sopenharmony_ci        # Latest 4.x vs 3.x release charts
341cc1dc7a3Sopenharmony_ci        [
342cc1dc7a3Sopenharmony_ci            # Relative scores
343cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast", "fastest"],
344cc1dc7a3Sopenharmony_ci            [f"ref-{last4x}-avx2"],
345cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
346cc1dc7a3Sopenharmony_ci            True,
347cc1dc7a3Sopenharmony_ci            f"ref-{last3x}-avx2",
348cc1dc7a3Sopenharmony_ci            None,
349cc1dc7a3Sopenharmony_ci            "results-relative-4.x-vs-3.x.png",
350cc1dc7a3Sopenharmony_ci            (relXLimits, None),
351cc1dc7a3Sopenharmony_ci        ], [
352cc1dc7a3Sopenharmony_ci            # Relative ISAs of latest
353cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast", "fastest"],
354cc1dc7a3Sopenharmony_ci            [f"ref-{last4x}-sse4.1", f"ref-{last4x}-avx2"],
355cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
356cc1dc7a3Sopenharmony_ci            True,
357cc1dc7a3Sopenharmony_ci            f"ref-{last4x}-sse2",
358cc1dc7a3Sopenharmony_ci            None,
359cc1dc7a3Sopenharmony_ci            "results-relative-4.x-isa.png",
360cc1dc7a3Sopenharmony_ci            (None, None)
361cc1dc7a3Sopenharmony_ci        ], [
362cc1dc7a3Sopenharmony_ci            # Relative quality of latest
363cc1dc7a3Sopenharmony_ci            ["medium", "fast", "fastest"],
364cc1dc7a3Sopenharmony_ci            [f"ref-{last4x}-avx2"],
365cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
366cc1dc7a3Sopenharmony_ci            True,
367cc1dc7a3Sopenharmony_ci            None,
368cc1dc7a3Sopenharmony_ci            "thorough",
369cc1dc7a3Sopenharmony_ci            "results-relative-4.x-quality.png",
370cc1dc7a3Sopenharmony_ci            (None, None)
371cc1dc7a3Sopenharmony_ci        ],
372cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
373cc1dc7a3Sopenharmony_ci        # Latest 4.x vs previous 4.x release charts
374cc1dc7a3Sopenharmony_ci        [
375cc1dc7a3Sopenharmony_ci            # Relative scores
376cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast", "fastest"],
377cc1dc7a3Sopenharmony_ci            [f"ref-{last4x}-avx2"],
378cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
379cc1dc7a3Sopenharmony_ci            True,
380cc1dc7a3Sopenharmony_ci            f"ref-{prev4x}-avx2",
381cc1dc7a3Sopenharmony_ci            None,
382cc1dc7a3Sopenharmony_ci            "results-relative-4.x-vs-4.x.png",
383cc1dc7a3Sopenharmony_ci            (relXLimits, None)
384cc1dc7a3Sopenharmony_ci        ],
385cc1dc7a3Sopenharmony_ci        # --------------------------------------------------------
386cc1dc7a3Sopenharmony_ci        # Latest 4.x vs previous 4.x release charts
387cc1dc7a3Sopenharmony_ci        [
388cc1dc7a3Sopenharmony_ci            # Relative scores
389cc1dc7a3Sopenharmony_ci            ["thorough", "medium", "fast", "fastest"],
390cc1dc7a3Sopenharmony_ci            [f"ref-{lastMain}-avx2"],
391cc1dc7a3Sopenharmony_ci            ["4x4", "6x6", "8x8"],
392cc1dc7a3Sopenharmony_ci            True,
393cc1dc7a3Sopenharmony_ci            f"ref-{last4x}-avx2",
394cc1dc7a3Sopenharmony_ci            None,
395cc1dc7a3Sopenharmony_ci            "results-relative-main-vs-4.x.png",
396cc1dc7a3Sopenharmony_ci            (relXLimits, None)
397cc1dc7a3Sopenharmony_ci        ]
398cc1dc7a3Sopenharmony_ci    ]
399cc1dc7a3Sopenharmony_ci
400cc1dc7a3Sopenharmony_ci    results = find_reference_results()
401cc1dc7a3Sopenharmony_ci
402cc1dc7a3Sopenharmony_ci    # Force select is triggered by adding a trailing entry to the argument list
403cc1dc7a3Sopenharmony_ci    # of the charts that you want rendered; designed for debugging use cases
404cc1dc7a3Sopenharmony_ci    maxIndex = 0
405cc1dc7a3Sopenharmony_ci    expectedLength = 8
406cc1dc7a3Sopenharmony_ci    for chart in charts:
407cc1dc7a3Sopenharmony_ci        maxIndex = max(maxIndex, len(chart))
408cc1dc7a3Sopenharmony_ci
409cc1dc7a3Sopenharmony_ci    for chart in charts:
410cc1dc7a3Sopenharmony_ci        # If force select is enabled then only keep the forced ones
411cc1dc7a3Sopenharmony_ci        if len(chart) != maxIndex:
412cc1dc7a3Sopenharmony_ci            print("Skipping %s" % chart[6])
413cc1dc7a3Sopenharmony_ci            continue
414cc1dc7a3Sopenharmony_ci        else:
415cc1dc7a3Sopenharmony_ci            print("Generating %s" % chart[6])
416cc1dc7a3Sopenharmony_ci
417cc1dc7a3Sopenharmony_ci        # If force select is enabled then strip the dummy force option
418cc1dc7a3Sopenharmony_ci        if maxIndex != expectedLength:
419cc1dc7a3Sopenharmony_ci            chart = chart[:expectedLength]
420cc1dc7a3Sopenharmony_ci
421cc1dc7a3Sopenharmony_ci        plot(results, *chart)
422cc1dc7a3Sopenharmony_ci
423cc1dc7a3Sopenharmony_ci    return 0
424cc1dc7a3Sopenharmony_ci
425cc1dc7a3Sopenharmony_ci
426cc1dc7a3Sopenharmony_ciif __name__ == "__main__":
427cc1dc7a3Sopenharmony_ci    sys.exit(main())
428