1cc1dc7a3Sopenharmony_ci#!/usr/bin/env python3
2cc1dc7a3Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0
3cc1dc7a3Sopenharmony_ci# -----------------------------------------------------------------------------
4cc1dc7a3Sopenharmony_ci# Copyright 2021 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_trace_analysis`` utility provides a tool to analyze trace files.
20cc1dc7a3Sopenharmony_ci
21cc1dc7a3Sopenharmony_ciWARNING: Trace files are an engineering tool, and not part of the standard
22cc1dc7a3Sopenharmony_ciproduct, so traces and their associated tools are volatile and may change
23cc1dc7a3Sopenharmony_cisignificantly without notice.
24cc1dc7a3Sopenharmony_ci"""
25cc1dc7a3Sopenharmony_ci
26cc1dc7a3Sopenharmony_ciimport argparse
27cc1dc7a3Sopenharmony_cifrom collections import defaultdict as ddict
28cc1dc7a3Sopenharmony_ciimport json
29cc1dc7a3Sopenharmony_ciimport numpy as np
30cc1dc7a3Sopenharmony_ciimport sys
31cc1dc7a3Sopenharmony_ci
32cc1dc7a3Sopenharmony_ciQUANT_TABLE = {
33cc1dc7a3Sopenharmony_ci	 0:   2,
34cc1dc7a3Sopenharmony_ci	 1:   3,
35cc1dc7a3Sopenharmony_ci	 2:   4,
36cc1dc7a3Sopenharmony_ci	 3:   5,
37cc1dc7a3Sopenharmony_ci	 4:   6,
38cc1dc7a3Sopenharmony_ci	 5:   8,
39cc1dc7a3Sopenharmony_ci	 6:  10,
40cc1dc7a3Sopenharmony_ci	 7:  12,
41cc1dc7a3Sopenharmony_ci	 8:  16,
42cc1dc7a3Sopenharmony_ci	 9:  20,
43cc1dc7a3Sopenharmony_ci	10:  24,
44cc1dc7a3Sopenharmony_ci	11:  32
45cc1dc7a3Sopenharmony_ci}
46cc1dc7a3Sopenharmony_ci
47cc1dc7a3Sopenharmony_ciCHANNEL_TABLE = {
48cc1dc7a3Sopenharmony_ci	 0: "R",
49cc1dc7a3Sopenharmony_ci	 1: "G",
50cc1dc7a3Sopenharmony_ci	 2: "B",
51cc1dc7a3Sopenharmony_ci	 3: "A"
52cc1dc7a3Sopenharmony_ci}
53cc1dc7a3Sopenharmony_ci
54cc1dc7a3Sopenharmony_ciclass Trace:
55cc1dc7a3Sopenharmony_ci
56cc1dc7a3Sopenharmony_ci    def __init__(self, block_x, block_y, block_z):
57cc1dc7a3Sopenharmony_ci        self.block_x = block_x
58cc1dc7a3Sopenharmony_ci        self.block_y = block_y
59cc1dc7a3Sopenharmony_ci        self.block_z = block_z
60cc1dc7a3Sopenharmony_ci        self.blocks = []
61cc1dc7a3Sopenharmony_ci
62cc1dc7a3Sopenharmony_ci    def add_block(self, block):
63cc1dc7a3Sopenharmony_ci        self.blocks.append(block)
64cc1dc7a3Sopenharmony_ci
65cc1dc7a3Sopenharmony_ci    def __getitem__(self, i):
66cc1dc7a3Sopenharmony_ci       return self.blocks[i]
67cc1dc7a3Sopenharmony_ci
68cc1dc7a3Sopenharmony_ci    def __delitem__(self, i):
69cc1dc7a3Sopenharmony_ci       del self.blocks[i]
70cc1dc7a3Sopenharmony_ci
71cc1dc7a3Sopenharmony_ci    def __len__(self):
72cc1dc7a3Sopenharmony_ci       return len(self.blocks)
73cc1dc7a3Sopenharmony_ci
74cc1dc7a3Sopenharmony_ciclass Block:
75cc1dc7a3Sopenharmony_ci
76cc1dc7a3Sopenharmony_ci    def __init__(self, pos_x, pos_y, pos_z, error_target):
77cc1dc7a3Sopenharmony_ci        self.pos_x = pos_x
78cc1dc7a3Sopenharmony_ci        self.pos_y = pos_y
79cc1dc7a3Sopenharmony_ci        self.pos_z = pos_z
80cc1dc7a3Sopenharmony_ci
81cc1dc7a3Sopenharmony_ci        self.raw_min = None
82cc1dc7a3Sopenharmony_ci        self.raw_max = None
83cc1dc7a3Sopenharmony_ci
84cc1dc7a3Sopenharmony_ci        self.ldr_min = None
85cc1dc7a3Sopenharmony_ci        self.ldr_max = None
86cc1dc7a3Sopenharmony_ci
87cc1dc7a3Sopenharmony_ci        self.error_target = error_target
88cc1dc7a3Sopenharmony_ci        self.passes = []
89cc1dc7a3Sopenharmony_ci        self.qualityHit = None
90cc1dc7a3Sopenharmony_ci
91cc1dc7a3Sopenharmony_ci    def add_minimums(self, r, g, b, a):
92cc1dc7a3Sopenharmony_ci        self.raw_min = (r, g, b, a)
93cc1dc7a3Sopenharmony_ci
94cc1dc7a3Sopenharmony_ci        def ldr(x):
95cc1dc7a3Sopenharmony_ci            cmax = 65535.0
96cc1dc7a3Sopenharmony_ci            return int((r / cmax) * 255.0)
97cc1dc7a3Sopenharmony_ci
98cc1dc7a3Sopenharmony_ci        self.ldr_min = (ldr(r), ldr(g), ldr(b), ldr(a))
99cc1dc7a3Sopenharmony_ci
100cc1dc7a3Sopenharmony_ci    def add_maximums(self, r, g, b, a):
101cc1dc7a3Sopenharmony_ci        self.raw_max = (r, g, b, a)
102cc1dc7a3Sopenharmony_ci
103cc1dc7a3Sopenharmony_ci        def ldr(x):
104cc1dc7a3Sopenharmony_ci            cmax = 65535.0
105cc1dc7a3Sopenharmony_ci            return int((r / cmax) * 255.0)
106cc1dc7a3Sopenharmony_ci
107cc1dc7a3Sopenharmony_ci        self.ldr_max = (ldr(r), ldr(g), ldr(b), ldr(a))
108cc1dc7a3Sopenharmony_ci
109cc1dc7a3Sopenharmony_ci    def add_pass(self, pas):
110cc1dc7a3Sopenharmony_ci        self.passes.append(pas)
111cc1dc7a3Sopenharmony_ci
112cc1dc7a3Sopenharmony_ci    def __getitem__(self, i):
113cc1dc7a3Sopenharmony_ci       return self.passes[i]
114cc1dc7a3Sopenharmony_ci
115cc1dc7a3Sopenharmony_ci    def __delitem__(self, i):
116cc1dc7a3Sopenharmony_ci       del self.passes[i]
117cc1dc7a3Sopenharmony_ci
118cc1dc7a3Sopenharmony_ci    def __len__(self):
119cc1dc7a3Sopenharmony_ci       return len(self.passes)
120cc1dc7a3Sopenharmony_ci
121cc1dc7a3Sopenharmony_ci
122cc1dc7a3Sopenharmony_ciclass Pass:
123cc1dc7a3Sopenharmony_ci
124cc1dc7a3Sopenharmony_ci    def __init__(self, partitions, partition, planes, target_hit, mode, component):
125cc1dc7a3Sopenharmony_ci        self.partitions = partitions
126cc1dc7a3Sopenharmony_ci        self.partition_index = 0 if partition is None else partition
127cc1dc7a3Sopenharmony_ci        self.planes = planes
128cc1dc7a3Sopenharmony_ci        self.plane2_component = component
129cc1dc7a3Sopenharmony_ci        self.target_hit = target_hit
130cc1dc7a3Sopenharmony_ci        self.search_mode = mode
131cc1dc7a3Sopenharmony_ci        self.candidates = []
132cc1dc7a3Sopenharmony_ci
133cc1dc7a3Sopenharmony_ci    def add_candidate(self, candidate):
134cc1dc7a3Sopenharmony_ci        self.candidates.append(candidate)
135cc1dc7a3Sopenharmony_ci
136cc1dc7a3Sopenharmony_ci    def __getitem__(self, i):
137cc1dc7a3Sopenharmony_ci       return self.candidates[i]
138cc1dc7a3Sopenharmony_ci
139cc1dc7a3Sopenharmony_ci    def __delitem__(self, i):
140cc1dc7a3Sopenharmony_ci       del self.candidates[i]
141cc1dc7a3Sopenharmony_ci
142cc1dc7a3Sopenharmony_ci    def __len__(self):
143cc1dc7a3Sopenharmony_ci       return len(self.candidates)
144cc1dc7a3Sopenharmony_ci
145cc1dc7a3Sopenharmony_ci
146cc1dc7a3Sopenharmony_ciclass Candidate:
147cc1dc7a3Sopenharmony_ci
148cc1dc7a3Sopenharmony_ci    def __init__(self, weight_x, weight_y, weight_z, weight_quant):
149cc1dc7a3Sopenharmony_ci        self.weight_x = weight_x
150cc1dc7a3Sopenharmony_ci        self.weight_y = weight_y
151cc1dc7a3Sopenharmony_ci        self.weight_z = weight_z
152cc1dc7a3Sopenharmony_ci        self.weight_quant = weight_quant
153cc1dc7a3Sopenharmony_ci        self.refinement_errors = []
154cc1dc7a3Sopenharmony_ci
155cc1dc7a3Sopenharmony_ci    def add_refinement(self, errorval):
156cc1dc7a3Sopenharmony_ci        self.refinement_errors.append(errorval)
157cc1dc7a3Sopenharmony_ci
158cc1dc7a3Sopenharmony_ci
159cc1dc7a3Sopenharmony_cidef get_attrib(data, name, multiple=False, hard_fail=True):
160cc1dc7a3Sopenharmony_ci    results = []
161cc1dc7a3Sopenharmony_ci    for attrib in data:
162cc1dc7a3Sopenharmony_ci        if len(attrib) == 2 and attrib[0] == name:
163cc1dc7a3Sopenharmony_ci            results.append(attrib[1])
164cc1dc7a3Sopenharmony_ci
165cc1dc7a3Sopenharmony_ci    if not results:
166cc1dc7a3Sopenharmony_ci        if hard_fail:
167cc1dc7a3Sopenharmony_ci            print(json.dumps(data, indent=2))
168cc1dc7a3Sopenharmony_ci            assert False, "Attribute %s not found" % name
169cc1dc7a3Sopenharmony_ci        if multiple:
170cc1dc7a3Sopenharmony_ci            return list()
171cc1dc7a3Sopenharmony_ci        return None
172cc1dc7a3Sopenharmony_ci
173cc1dc7a3Sopenharmony_ci    if not multiple:
174cc1dc7a3Sopenharmony_ci        if len(results) > 1:
175cc1dc7a3Sopenharmony_ci            print(json.dumps(data, indent=2))
176cc1dc7a3Sopenharmony_ci            assert False, "Attribute %s found %u times" % (name, len(results))
177cc1dc7a3Sopenharmony_ci        return results[0]
178cc1dc7a3Sopenharmony_ci
179cc1dc7a3Sopenharmony_ci    return results
180cc1dc7a3Sopenharmony_ci
181cc1dc7a3Sopenharmony_ci
182cc1dc7a3Sopenharmony_cidef rev_enumerate(seq):
183cc1dc7a3Sopenharmony_ci    return zip(reversed(range(len(seq))), reversed(seq))
184cc1dc7a3Sopenharmony_ci
185cc1dc7a3Sopenharmony_cidef foreach_block(data):
186cc1dc7a3Sopenharmony_ci
187cc1dc7a3Sopenharmony_ci    for block in data:
188cc1dc7a3Sopenharmony_ci        yield block
189cc1dc7a3Sopenharmony_ci
190cc1dc7a3Sopenharmony_cidef foreach_pass(data):
191cc1dc7a3Sopenharmony_ci
192cc1dc7a3Sopenharmony_ci    for block in data:
193cc1dc7a3Sopenharmony_ci        for pas in block:
194cc1dc7a3Sopenharmony_ci            yield (block, pas)
195cc1dc7a3Sopenharmony_ci
196cc1dc7a3Sopenharmony_cidef foreach_candidate(data):
197cc1dc7a3Sopenharmony_ci
198cc1dc7a3Sopenharmony_ci    for block in data:
199cc1dc7a3Sopenharmony_ci        for pas in block:
200cc1dc7a3Sopenharmony_ci            # Special case - None candidates for 0 partition
201cc1dc7a3Sopenharmony_ci            if not len(pas):
202cc1dc7a3Sopenharmony_ci                yield (block, pas, None)
203cc1dc7a3Sopenharmony_ci
204cc1dc7a3Sopenharmony_ci            for candidate in pas:
205cc1dc7a3Sopenharmony_ci                yield (block, pas, candidate)
206cc1dc7a3Sopenharmony_ci
207cc1dc7a3Sopenharmony_cidef get_node(data, name, multiple=False, hard_fail=True):
208cc1dc7a3Sopenharmony_ci    results = []
209cc1dc7a3Sopenharmony_ci    for attrib in data:
210cc1dc7a3Sopenharmony_ci        if len(attrib) == 3 and attrib[0] == "node" and attrib[1] == name:
211cc1dc7a3Sopenharmony_ci            results.append(attrib[2])
212cc1dc7a3Sopenharmony_ci
213cc1dc7a3Sopenharmony_ci    if not results:
214cc1dc7a3Sopenharmony_ci        if hard_fail:
215cc1dc7a3Sopenharmony_ci            print(json.dumps(data, indent=2))
216cc1dc7a3Sopenharmony_ci            assert False, "Node %s not found" % name
217cc1dc7a3Sopenharmony_ci        return None
218cc1dc7a3Sopenharmony_ci
219cc1dc7a3Sopenharmony_ci    if not multiple:
220cc1dc7a3Sopenharmony_ci        if len(results) > 1:
221cc1dc7a3Sopenharmony_ci            print(json.dumps(data, indent=2))
222cc1dc7a3Sopenharmony_ci            assert False, "Node %s found %u times" % (name, len(results))
223cc1dc7a3Sopenharmony_ci        return results[0]
224cc1dc7a3Sopenharmony_ci
225cc1dc7a3Sopenharmony_ci    return results
226cc1dc7a3Sopenharmony_ci
227cc1dc7a3Sopenharmony_ci
228cc1dc7a3Sopenharmony_cidef find_best_pass_and_candidate(block):
229cc1dc7a3Sopenharmony_ci    explicit_pass = None
230cc1dc7a3Sopenharmony_ci
231cc1dc7a3Sopenharmony_ci    best_error = 1e30
232cc1dc7a3Sopenharmony_ci    best_pass = None
233cc1dc7a3Sopenharmony_ci    best_candidate = None
234cc1dc7a3Sopenharmony_ci
235cc1dc7a3Sopenharmony_ci    for pas in block:
236cc1dc7a3Sopenharmony_ci        # Special case for constant color blocks - no trial candidates
237cc1dc7a3Sopenharmony_ci        if pas.target_hit and pas.partitions == 0:
238cc1dc7a3Sopenharmony_ci            return (pas, None)
239cc1dc7a3Sopenharmony_ci
240cc1dc7a3Sopenharmony_ci        for candidate in pas:
241cc1dc7a3Sopenharmony_ci            errorval = candidate.refinement_errors[-1]
242cc1dc7a3Sopenharmony_ci            if errorval <= best_error:
243cc1dc7a3Sopenharmony_ci                best_error = errorval
244cc1dc7a3Sopenharmony_ci                best_pass = pas
245cc1dc7a3Sopenharmony_ci                best_candidate = candidate
246cc1dc7a3Sopenharmony_ci
247cc1dc7a3Sopenharmony_ci    # Every other return type must have both best pass and best candidate
248cc1dc7a3Sopenharmony_ci    assert (best_pass and best_candidate)
249cc1dc7a3Sopenharmony_ci    return (best_pass, best_candidate)
250cc1dc7a3Sopenharmony_ci
251cc1dc7a3Sopenharmony_ci
252cc1dc7a3Sopenharmony_cidef generate_database(data):
253cc1dc7a3Sopenharmony_ci    # Skip header
254cc1dc7a3Sopenharmony_ci    assert(data[0] == "node")
255cc1dc7a3Sopenharmony_ci    assert(data[1] == "root")
256cc1dc7a3Sopenharmony_ci    data = data[2]
257cc1dc7a3Sopenharmony_ci
258cc1dc7a3Sopenharmony_ci    bx = get_attrib(data, "block_x")
259cc1dc7a3Sopenharmony_ci    by = get_attrib(data, "block_y")
260cc1dc7a3Sopenharmony_ci    bz = get_attrib(data, "block_z")
261cc1dc7a3Sopenharmony_ci    dbStruct = Trace(bx, by, bz)
262cc1dc7a3Sopenharmony_ci
263cc1dc7a3Sopenharmony_ci    for block in get_node(data, "block", True):
264cc1dc7a3Sopenharmony_ci        px = get_attrib(block, "pos_x")
265cc1dc7a3Sopenharmony_ci        py = get_attrib(block, "pos_y")
266cc1dc7a3Sopenharmony_ci        pz = get_attrib(block, "pos_z")
267cc1dc7a3Sopenharmony_ci
268cc1dc7a3Sopenharmony_ci        minr = get_attrib(block, "min_r")
269cc1dc7a3Sopenharmony_ci        ming = get_attrib(block, "min_g")
270cc1dc7a3Sopenharmony_ci        minb = get_attrib(block, "min_b")
271cc1dc7a3Sopenharmony_ci        mina = get_attrib(block, "min_a")
272cc1dc7a3Sopenharmony_ci
273cc1dc7a3Sopenharmony_ci        maxr = get_attrib(block, "max_r")
274cc1dc7a3Sopenharmony_ci        maxg = get_attrib(block, "max_g")
275cc1dc7a3Sopenharmony_ci        maxb = get_attrib(block, "max_b")
276cc1dc7a3Sopenharmony_ci        maxa = get_attrib(block, "max_a")
277cc1dc7a3Sopenharmony_ci
278cc1dc7a3Sopenharmony_ci        et = get_attrib(block, "tune_error_threshold")
279cc1dc7a3Sopenharmony_ci
280cc1dc7a3Sopenharmony_ci        blockStruct = Block(px, py, pz, et)
281cc1dc7a3Sopenharmony_ci        blockStruct.add_minimums(minr, ming, minb, mina)
282cc1dc7a3Sopenharmony_ci        blockStruct.add_maximums(maxr, maxg, maxb, maxa)
283cc1dc7a3Sopenharmony_ci        dbStruct.add_block(blockStruct)
284cc1dc7a3Sopenharmony_ci
285cc1dc7a3Sopenharmony_ci        for pas in get_node(block, "pass", True):
286cc1dc7a3Sopenharmony_ci            # Don't copy across passes we skipped due to heuristics
287cc1dc7a3Sopenharmony_ci            skipped = get_attrib(pas, "skip", False, False)
288cc1dc7a3Sopenharmony_ci            if skipped:
289cc1dc7a3Sopenharmony_ci                continue
290cc1dc7a3Sopenharmony_ci
291cc1dc7a3Sopenharmony_ci            prts = get_attrib(pas, "partition_count")
292cc1dc7a3Sopenharmony_ci            prti = get_attrib(pas, "partition_index", False, False)
293cc1dc7a3Sopenharmony_ci            plns = get_attrib(pas, "plane_count")
294cc1dc7a3Sopenharmony_ci            chan = get_attrib(pas, "plane_component", False, plns > 2)
295cc1dc7a3Sopenharmony_ci            mode = get_attrib(pas, "search_mode", False, False)
296cc1dc7a3Sopenharmony_ci            ehit = get_attrib(pas, "exit", False, False) == "quality hit"
297cc1dc7a3Sopenharmony_ci
298cc1dc7a3Sopenharmony_ci            passStruct = Pass(prts, prti, plns, ehit, mode, chan)
299cc1dc7a3Sopenharmony_ci            blockStruct.add_pass(passStruct)
300cc1dc7a3Sopenharmony_ci
301cc1dc7a3Sopenharmony_ci            # Constant color blocks don't have any candidates
302cc1dc7a3Sopenharmony_ci            if prts == 0:
303cc1dc7a3Sopenharmony_ci                continue
304cc1dc7a3Sopenharmony_ci
305cc1dc7a3Sopenharmony_ci            for candidate in get_node(pas, "candidate", True):
306cc1dc7a3Sopenharmony_ci                # Don't copy across candidates we couldn't encode
307cc1dc7a3Sopenharmony_ci                failed = get_attrib(candidate, "failed", False, False)
308cc1dc7a3Sopenharmony_ci                if failed:
309cc1dc7a3Sopenharmony_ci                    continue
310cc1dc7a3Sopenharmony_ci
311cc1dc7a3Sopenharmony_ci                wx = get_attrib(candidate, "weight_x")
312cc1dc7a3Sopenharmony_ci                wy = get_attrib(candidate, "weight_y")
313cc1dc7a3Sopenharmony_ci                wz = get_attrib(candidate, "weight_z")
314cc1dc7a3Sopenharmony_ci                wq = QUANT_TABLE[get_attrib(candidate, "weight_quant")]
315cc1dc7a3Sopenharmony_ci                epre = get_attrib(candidate, "error_prerealign", True, False)
316cc1dc7a3Sopenharmony_ci                epst = get_attrib(candidate, "error_postrealign", True, False)
317cc1dc7a3Sopenharmony_ci
318cc1dc7a3Sopenharmony_ci                candStruct = Candidate(wx, wy, wz, wq)
319cc1dc7a3Sopenharmony_ci                passStruct.add_candidate(candStruct)
320cc1dc7a3Sopenharmony_ci                for value in epre:
321cc1dc7a3Sopenharmony_ci                    candStruct.add_refinement(value)
322cc1dc7a3Sopenharmony_ci                for value in epst:
323cc1dc7a3Sopenharmony_ci                    candStruct.add_refinement(value)
324cc1dc7a3Sopenharmony_ci
325cc1dc7a3Sopenharmony_ci    return dbStruct
326cc1dc7a3Sopenharmony_ci
327cc1dc7a3Sopenharmony_ci
328cc1dc7a3Sopenharmony_cidef filter_database(data):
329cc1dc7a3Sopenharmony_ci
330cc1dc7a3Sopenharmony_ci    for block in data:
331cc1dc7a3Sopenharmony_ci        best_pass, best_candidate = find_best_pass_and_candidate(block)
332cc1dc7a3Sopenharmony_ci
333cc1dc7a3Sopenharmony_ci        for i, pas in rev_enumerate(block):
334cc1dc7a3Sopenharmony_ci            if pas != best_pass:
335cc1dc7a3Sopenharmony_ci                del block[i]
336cc1dc7a3Sopenharmony_ci                continue
337cc1dc7a3Sopenharmony_ci
338cc1dc7a3Sopenharmony_ci            if best_candidate is None:
339cc1dc7a3Sopenharmony_ci                continue
340cc1dc7a3Sopenharmony_ci
341cc1dc7a3Sopenharmony_ci            for j, candidate in rev_enumerate(pas):
342cc1dc7a3Sopenharmony_ci                if candidate != best_candidate:
343cc1dc7a3Sopenharmony_ci                    del pas[j]
344cc1dc7a3Sopenharmony_ci
345cc1dc7a3Sopenharmony_ci
346cc1dc7a3Sopenharmony_cidef generate_pass_statistics(data):
347cc1dc7a3Sopenharmony_ci    pass
348cc1dc7a3Sopenharmony_ci
349cc1dc7a3Sopenharmony_ci
350cc1dc7a3Sopenharmony_cidef generate_feature_statistics(data):
351cc1dc7a3Sopenharmony_ci    # -------------------------------------------------------------------------
352cc1dc7a3Sopenharmony_ci    # Config
353cc1dc7a3Sopenharmony_ci    print("Compressor Config")
354cc1dc7a3Sopenharmony_ci    print("=================")
355cc1dc7a3Sopenharmony_ci
356cc1dc7a3Sopenharmony_ci    if data.block_z > 1:
357cc1dc7a3Sopenharmony_ci        dat = (data.block_x, data.block_y, data.block_z)
358cc1dc7a3Sopenharmony_ci        print("  - Block size: %ux%ux%u" % dat)
359cc1dc7a3Sopenharmony_ci    else:
360cc1dc7a3Sopenharmony_ci        dat = (data.block_x, data.block_y)
361cc1dc7a3Sopenharmony_ci        print("  - Block size: %ux%u" % dat)
362cc1dc7a3Sopenharmony_ci
363cc1dc7a3Sopenharmony_ci    print("")
364cc1dc7a3Sopenharmony_ci
365cc1dc7a3Sopenharmony_ci    # -------------------------------------------------------------------------
366cc1dc7a3Sopenharmony_ci    # Block metrics
367cc1dc7a3Sopenharmony_ci    result = ddict(int)
368cc1dc7a3Sopenharmony_ci
369cc1dc7a3Sopenharmony_ci    RANGE_QUANT = 16
370cc1dc7a3Sopenharmony_ci
371cc1dc7a3Sopenharmony_ci    for block in foreach_block(data):
372cc1dc7a3Sopenharmony_ci        ranges = []
373cc1dc7a3Sopenharmony_ci        for i in range(0, 4):
374cc1dc7a3Sopenharmony_ci            ranges.append(block.ldr_max[i] - block.ldr_min[i])
375cc1dc7a3Sopenharmony_ci
376cc1dc7a3Sopenharmony_ci        max_range = max(ranges)
377cc1dc7a3Sopenharmony_ci        max_range = int(max_range / RANGE_QUANT) * RANGE_QUANT
378cc1dc7a3Sopenharmony_ci
379cc1dc7a3Sopenharmony_ci        result[max_range] += 1
380cc1dc7a3Sopenharmony_ci
381cc1dc7a3Sopenharmony_ci    print("Channel Range")
382cc1dc7a3Sopenharmony_ci    print("=============")
383cc1dc7a3Sopenharmony_ci    keys = sorted(result.keys())
384cc1dc7a3Sopenharmony_ci    for key in keys:
385cc1dc7a3Sopenharmony_ci        dat = (key, key + RANGE_QUANT - 1, result[key])
386cc1dc7a3Sopenharmony_ci        print("  - %3u-%3u dynamic range = %6u blocks" % dat)
387cc1dc7a3Sopenharmony_ci
388cc1dc7a3Sopenharmony_ci    print("")
389cc1dc7a3Sopenharmony_ci
390cc1dc7a3Sopenharmony_ci    # -------------------------------------------------------------------------
391cc1dc7a3Sopenharmony_ci    # Partition usage
392cc1dc7a3Sopenharmony_ci    result_totals = ddict(int)
393cc1dc7a3Sopenharmony_ci    results = ddict(lambda: ddict(int))
394cc1dc7a3Sopenharmony_ci
395cc1dc7a3Sopenharmony_ci    for _, pas in foreach_pass(data):
396cc1dc7a3Sopenharmony_ci        result_totals[pas.partitions] += 1
397cc1dc7a3Sopenharmony_ci        results[pas.partitions][pas.partition_index] += 1
398cc1dc7a3Sopenharmony_ci
399cc1dc7a3Sopenharmony_ci    print("Partition Count")
400cc1dc7a3Sopenharmony_ci    print("===============")
401cc1dc7a3Sopenharmony_ci    keys = sorted(result_totals.keys())
402cc1dc7a3Sopenharmony_ci    for key in keys:
403cc1dc7a3Sopenharmony_ci        dat = (key, result_totals[key], len(results[key]))
404cc1dc7a3Sopenharmony_ci        print("  - %u partition(s) = %6u blocks / %4u indicies" % dat)
405cc1dc7a3Sopenharmony_ci
406cc1dc7a3Sopenharmony_ci    print("")
407cc1dc7a3Sopenharmony_ci
408cc1dc7a3Sopenharmony_ci    # -------------------------------------------------------------------------
409cc1dc7a3Sopenharmony_ci    # Plane usage
410cc1dc7a3Sopenharmony_ci    result_count = ddict(lambda: ddict(int))
411cc1dc7a3Sopenharmony_ci    result_channel = ddict(lambda: ddict(int))
412cc1dc7a3Sopenharmony_ci
413cc1dc7a3Sopenharmony_ci    for _, pas in foreach_pass(data):
414cc1dc7a3Sopenharmony_ci        result_count[pas.partitions][pas.planes] += 1
415cc1dc7a3Sopenharmony_ci        if (pas.planes > 1):
416cc1dc7a3Sopenharmony_ci            result_channel[pas.partitions][pas.plane2_component] += 1
417cc1dc7a3Sopenharmony_ci
418cc1dc7a3Sopenharmony_ci    print("Plane Usage")
419cc1dc7a3Sopenharmony_ci    print("===========")
420cc1dc7a3Sopenharmony_ci    keys = sorted(result_count.keys())
421cc1dc7a3Sopenharmony_ci    for key in keys:
422cc1dc7a3Sopenharmony_ci        keys2 = sorted(result_count[key])
423cc1dc7a3Sopenharmony_ci        for key2 in keys2:
424cc1dc7a3Sopenharmony_ci            val2 = result_count[key][key2]
425cc1dc7a3Sopenharmony_ci            dat = (key, key2, val2)
426cc1dc7a3Sopenharmony_ci            print("  - %u partition(s) %u plane(s) = %6u blocks" % dat)
427cc1dc7a3Sopenharmony_ci            if key2 == 2:
428cc1dc7a3Sopenharmony_ci                keys3 = sorted(result_channel[key])
429cc1dc7a3Sopenharmony_ci                for key3 in keys3:
430cc1dc7a3Sopenharmony_ci                    dat = (CHANNEL_TABLE[key3], result_channel[key][key3])
431cc1dc7a3Sopenharmony_ci                    print("    - %s plane                 = %6u blocks" % dat)
432cc1dc7a3Sopenharmony_ci
433cc1dc7a3Sopenharmony_ci    print("")
434cc1dc7a3Sopenharmony_ci
435cc1dc7a3Sopenharmony_ci    # -------------------------------------------------------------------------
436cc1dc7a3Sopenharmony_ci    # Decimation usage
437cc1dc7a3Sopenharmony_ci    decim_count = ddict(lambda: ddict(int))
438cc1dc7a3Sopenharmony_ci    quant_count = ddict(lambda: ddict(lambda: ddict(int)))
439cc1dc7a3Sopenharmony_ci
440cc1dc7a3Sopenharmony_ci
441cc1dc7a3Sopenharmony_ci    MERGE_ROTATIONS = True
442cc1dc7a3Sopenharmony_ci
443cc1dc7a3Sopenharmony_ci    for _, pas, can in foreach_candidate(data):
444cc1dc7a3Sopenharmony_ci        # Skip constant color blocks
445cc1dc7a3Sopenharmony_ci        if can is None:
446cc1dc7a3Sopenharmony_ci            continue
447cc1dc7a3Sopenharmony_ci
448cc1dc7a3Sopenharmony_ci        wx = can.weight_x
449cc1dc7a3Sopenharmony_ci        wy = can.weight_y
450cc1dc7a3Sopenharmony_ci
451cc1dc7a3Sopenharmony_ci        if MERGE_ROTATIONS and wx < wy:
452cc1dc7a3Sopenharmony_ci            wx, wy = wy, wx
453cc1dc7a3Sopenharmony_ci
454cc1dc7a3Sopenharmony_ci        decim_count[wx][wy] += 1
455cc1dc7a3Sopenharmony_ci        quant_count[wx][wy][can.weight_quant] += 1
456cc1dc7a3Sopenharmony_ci
457cc1dc7a3Sopenharmony_ci    print("Decimation Usage")
458cc1dc7a3Sopenharmony_ci    print("================")
459cc1dc7a3Sopenharmony_ci
460cc1dc7a3Sopenharmony_ci    if MERGE_ROTATIONS:
461cc1dc7a3Sopenharmony_ci        print("  - Note: data merging grid rotations")
462cc1dc7a3Sopenharmony_ci
463cc1dc7a3Sopenharmony_ci    x_keys = sorted(decim_count.keys())
464cc1dc7a3Sopenharmony_ci    for x_key in x_keys:
465cc1dc7a3Sopenharmony_ci        y_keys = sorted(decim_count[x_key])
466cc1dc7a3Sopenharmony_ci
467cc1dc7a3Sopenharmony_ci        for y_key in y_keys:
468cc1dc7a3Sopenharmony_ci            count = decim_count[x_key][y_key]
469cc1dc7a3Sopenharmony_ci            dat = (x_key, y_key, count)
470cc1dc7a3Sopenharmony_ci            print("  - %ux%u weights      = %6u blocks" % dat)
471cc1dc7a3Sopenharmony_ci
472cc1dc7a3Sopenharmony_ci            q_keys = sorted(quant_count[x_key][y_key])
473cc1dc7a3Sopenharmony_ci            for q_key in q_keys:
474cc1dc7a3Sopenharmony_ci                count = quant_count[x_key][y_key][q_key]
475cc1dc7a3Sopenharmony_ci                dat = (q_key, count)
476cc1dc7a3Sopenharmony_ci                print("    - %2u quant range = %6u blocks" % dat)
477cc1dc7a3Sopenharmony_ci
478cc1dc7a3Sopenharmony_ci    print("")
479cc1dc7a3Sopenharmony_ci
480cc1dc7a3Sopenharmony_ci    # -------------------------------------------------------------------------
481cc1dc7a3Sopenharmony_ci    # Refinement usage
482cc1dc7a3Sopenharmony_ci
483cc1dc7a3Sopenharmony_ci    total_count = 0
484cc1dc7a3Sopenharmony_ci    better_count = 0
485cc1dc7a3Sopenharmony_ci    could_have_count = 0
486cc1dc7a3Sopenharmony_ci    success_count = 0
487cc1dc7a3Sopenharmony_ci
488cc1dc7a3Sopenharmony_ci    refinement_step = []
489cc1dc7a3Sopenharmony_ci
490cc1dc7a3Sopenharmony_ci    for block, pas, candidate in foreach_candidate(data):
491cc1dc7a3Sopenharmony_ci        # Ignore zero partition blocks - they don't use refinement
492cc1dc7a3Sopenharmony_ci        if not candidate:
493cc1dc7a3Sopenharmony_ci            continue
494cc1dc7a3Sopenharmony_ci
495cc1dc7a3Sopenharmony_ci        target_error = block.error_target
496cc1dc7a3Sopenharmony_ci        start_error = candidate.refinement_errors[0]
497cc1dc7a3Sopenharmony_ci        end_error = candidate.refinement_errors[-1]
498cc1dc7a3Sopenharmony_ci
499cc1dc7a3Sopenharmony_ci        rpf = float(start_error - end_error) / float(len(candidate.refinement_errors))
500cc1dc7a3Sopenharmony_ci        rpf = abs(rpf)
501cc1dc7a3Sopenharmony_ci        refinement_step.append(rpf / start_error)
502cc1dc7a3Sopenharmony_ci
503cc1dc7a3Sopenharmony_ci        total_count += 1
504cc1dc7a3Sopenharmony_ci        if end_error <= start_error:
505cc1dc7a3Sopenharmony_ci            better_count += 1
506cc1dc7a3Sopenharmony_ci
507cc1dc7a3Sopenharmony_ci        if end_error <= target_error:
508cc1dc7a3Sopenharmony_ci            success_count += 1
509cc1dc7a3Sopenharmony_ci        else:
510cc1dc7a3Sopenharmony_ci            for refinement in candidate.refinement_errors:
511cc1dc7a3Sopenharmony_ci                if refinement <= target_error:
512cc1dc7a3Sopenharmony_ci                    could_have_count += 1
513cc1dc7a3Sopenharmony_ci                    break
514cc1dc7a3Sopenharmony_ci
515cc1dc7a3Sopenharmony_ci
516cc1dc7a3Sopenharmony_ci    print("Refinement Usage")
517cc1dc7a3Sopenharmony_ci    print("================")
518cc1dc7a3Sopenharmony_ci    print("  - %u refinements(s)" % total_count)
519cc1dc7a3Sopenharmony_ci    print("  - %u refinements(s) improved" % better_count)
520cc1dc7a3Sopenharmony_ci    print("  - %u refinements(s) worsened" % (total_count - better_count))
521cc1dc7a3Sopenharmony_ci    print("  - %u refinements(s) could hit target, but didn't" % could_have_count)
522cc1dc7a3Sopenharmony_ci    print("  - %u refinements(s) hit target" % success_count)
523cc1dc7a3Sopenharmony_ci    print("  - %f mean step improvement" % np.mean(refinement_step))
524cc1dc7a3Sopenharmony_ci
525cc1dc7a3Sopenharmony_ci
526cc1dc7a3Sopenharmony_cidef parse_command_line():
527cc1dc7a3Sopenharmony_ci    """
528cc1dc7a3Sopenharmony_ci    Parse the command line.
529cc1dc7a3Sopenharmony_ci
530cc1dc7a3Sopenharmony_ci    Returns:
531cc1dc7a3Sopenharmony_ci        Namespace: The parsed command line container.
532cc1dc7a3Sopenharmony_ci    """
533cc1dc7a3Sopenharmony_ci    parser = argparse.ArgumentParser()
534cc1dc7a3Sopenharmony_ci
535cc1dc7a3Sopenharmony_ci    parser.add_argument("trace", type=argparse.FileType("r"),
536cc1dc7a3Sopenharmony_ci                        help="The trace file to analyze")
537cc1dc7a3Sopenharmony_ci
538cc1dc7a3Sopenharmony_ci    return parser.parse_args()
539cc1dc7a3Sopenharmony_ci
540cc1dc7a3Sopenharmony_ci
541cc1dc7a3Sopenharmony_cidef main():
542cc1dc7a3Sopenharmony_ci    """
543cc1dc7a3Sopenharmony_ci    The main function.
544cc1dc7a3Sopenharmony_ci
545cc1dc7a3Sopenharmony_ci    Returns:
546cc1dc7a3Sopenharmony_ci        int: The process return code.
547cc1dc7a3Sopenharmony_ci    """
548cc1dc7a3Sopenharmony_ci    args = parse_command_line()
549cc1dc7a3Sopenharmony_ci
550cc1dc7a3Sopenharmony_ci    data = json.load(args.trace)
551cc1dc7a3Sopenharmony_ci    db = generate_database(data)
552cc1dc7a3Sopenharmony_ci    filter_database(db)
553cc1dc7a3Sopenharmony_ci
554cc1dc7a3Sopenharmony_ci    generate_feature_statistics(db)
555cc1dc7a3Sopenharmony_ci
556cc1dc7a3Sopenharmony_ci    return 0
557cc1dc7a3Sopenharmony_ci
558cc1dc7a3Sopenharmony_ci
559cc1dc7a3Sopenharmony_ciif __name__ == "__main__":
560cc1dc7a3Sopenharmony_ci    sys.exit(main())
561