xref: /aosp_15_r20/external/grpc-grpc/tools/profiling/microbenchmarks/bm_json.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2017 gRPC authors.
3*cc02d7e2SAndroid Build Coastguard Worker#
4*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*cc02d7e2SAndroid Build Coastguard Worker#
8*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
9*cc02d7e2SAndroid Build Coastguard Worker#
10*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
15*cc02d7e2SAndroid Build Coastguard Worker
16*cc02d7e2SAndroid Build Coastguard Worker# Utilities for manipulating JSON data that represents microbenchmark results.
17*cc02d7e2SAndroid Build Coastguard Worker
18*cc02d7e2SAndroid Build Coastguard Workerimport os
19*cc02d7e2SAndroid Build Coastguard Worker
20*cc02d7e2SAndroid Build Coastguard Worker# template arguments and dynamic arguments of individual benchmark types
21*cc02d7e2SAndroid Build Coastguard Worker# Example benchmark name: "BM_UnaryPingPong<TCP, NoOpMutator, NoOpMutator>/0/0"
22*cc02d7e2SAndroid Build Coastguard Worker_BM_SPECS = {
23*cc02d7e2SAndroid Build Coastguard Worker    "BM_UnaryPingPong": {
24*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture", "client_mutator", "server_mutator"],
25*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size", "response_size"],
26*cc02d7e2SAndroid Build Coastguard Worker    },
27*cc02d7e2SAndroid Build Coastguard Worker    "BM_PumpStreamClientToServer": {
28*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
29*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
30*cc02d7e2SAndroid Build Coastguard Worker    },
31*cc02d7e2SAndroid Build Coastguard Worker    "BM_PumpStreamServerToClient": {
32*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
33*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
34*cc02d7e2SAndroid Build Coastguard Worker    },
35*cc02d7e2SAndroid Build Coastguard Worker    "BM_StreamingPingPong": {
36*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture", "client_mutator", "server_mutator"],
37*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size", "request_count"],
38*cc02d7e2SAndroid Build Coastguard Worker    },
39*cc02d7e2SAndroid Build Coastguard Worker    "BM_StreamingPingPongMsgs": {
40*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture", "client_mutator", "server_mutator"],
41*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
42*cc02d7e2SAndroid Build Coastguard Worker    },
43*cc02d7e2SAndroid Build Coastguard Worker    "BM_PumpStreamServerToClient_Trickle": {
44*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
45*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size", "bandwidth_kilobits"],
46*cc02d7e2SAndroid Build Coastguard Worker    },
47*cc02d7e2SAndroid Build Coastguard Worker    "BM_PumpUnbalancedUnary_Trickle": {
48*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
49*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["cli_req_size", "svr_req_size", "bandwidth_kilobits"],
50*cc02d7e2SAndroid Build Coastguard Worker    },
51*cc02d7e2SAndroid Build Coastguard Worker    "BM_ErrorStringOnNewError": {
52*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
53*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
54*cc02d7e2SAndroid Build Coastguard Worker    },
55*cc02d7e2SAndroid Build Coastguard Worker    "BM_ErrorStringRepeatedly": {
56*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
57*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
58*cc02d7e2SAndroid Build Coastguard Worker    },
59*cc02d7e2SAndroid Build Coastguard Worker    "BM_ErrorGetStatus": {
60*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
61*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
62*cc02d7e2SAndroid Build Coastguard Worker    },
63*cc02d7e2SAndroid Build Coastguard Worker    "BM_ErrorGetStatusCode": {
64*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
65*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
66*cc02d7e2SAndroid Build Coastguard Worker    },
67*cc02d7e2SAndroid Build Coastguard Worker    "BM_ErrorHttpError": {
68*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
69*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
70*cc02d7e2SAndroid Build Coastguard Worker    },
71*cc02d7e2SAndroid Build Coastguard Worker    "BM_HasClearGrpcStatus": {
72*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
73*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
74*cc02d7e2SAndroid Build Coastguard Worker    },
75*cc02d7e2SAndroid Build Coastguard Worker    "BM_IsolatedFilter": {
76*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture", "client_mutator"],
77*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
78*cc02d7e2SAndroid Build Coastguard Worker    },
79*cc02d7e2SAndroid Build Coastguard Worker    "BM_HpackEncoderEncodeHeader": {
80*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
81*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["end_of_stream", "request_size"],
82*cc02d7e2SAndroid Build Coastguard Worker    },
83*cc02d7e2SAndroid Build Coastguard Worker    "BM_HpackParserParseHeader": {
84*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
85*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
86*cc02d7e2SAndroid Build Coastguard Worker    },
87*cc02d7e2SAndroid Build Coastguard Worker    "BM_CallCreateDestroy": {
88*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
89*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
90*cc02d7e2SAndroid Build Coastguard Worker    },
91*cc02d7e2SAndroid Build Coastguard Worker    "BM_Zalloc": {
92*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
93*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
94*cc02d7e2SAndroid Build Coastguard Worker    },
95*cc02d7e2SAndroid Build Coastguard Worker    "BM_PollEmptyPollset_SpeedOfLight": {
96*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
97*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size", "request_count"],
98*cc02d7e2SAndroid Build Coastguard Worker    },
99*cc02d7e2SAndroid Build Coastguard Worker    "BM_StreamCreateSendInitialMetadataDestroy": {
100*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture"],
101*cc02d7e2SAndroid Build Coastguard Worker        "dyn": [],
102*cc02d7e2SAndroid Build Coastguard Worker    },
103*cc02d7e2SAndroid Build Coastguard Worker    "BM_TransportStreamSend": {
104*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
105*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
106*cc02d7e2SAndroid Build Coastguard Worker    },
107*cc02d7e2SAndroid Build Coastguard Worker    "BM_TransportStreamRecv": {
108*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
109*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
110*cc02d7e2SAndroid Build Coastguard Worker    },
111*cc02d7e2SAndroid Build Coastguard Worker    "BM_StreamingPingPongWithCoalescingApi": {
112*cc02d7e2SAndroid Build Coastguard Worker        "tpl": ["fixture", "client_mutator", "server_mutator"],
113*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size", "request_count", "end_of_stream"],
114*cc02d7e2SAndroid Build Coastguard Worker    },
115*cc02d7e2SAndroid Build Coastguard Worker    "BM_Base16SomeStuff": {
116*cc02d7e2SAndroid Build Coastguard Worker        "tpl": [],
117*cc02d7e2SAndroid Build Coastguard Worker        "dyn": ["request_size"],
118*cc02d7e2SAndroid Build Coastguard Worker    },
119*cc02d7e2SAndroid Build Coastguard Worker}
120*cc02d7e2SAndroid Build Coastguard Worker
121*cc02d7e2SAndroid Build Coastguard Worker
122*cc02d7e2SAndroid Build Coastguard Workerdef numericalize(s):
123*cc02d7e2SAndroid Build Coastguard Worker    """Convert abbreviations like '100M' or '10k' to a number."""
124*cc02d7e2SAndroid Build Coastguard Worker    if not s:
125*cc02d7e2SAndroid Build Coastguard Worker        return ""
126*cc02d7e2SAndroid Build Coastguard Worker    if s[-1] == "k":
127*cc02d7e2SAndroid Build Coastguard Worker        return float(s[:-1]) * 1024
128*cc02d7e2SAndroid Build Coastguard Worker    if s[-1] == "M":
129*cc02d7e2SAndroid Build Coastguard Worker        return float(s[:-1]) * 1024 * 1024
130*cc02d7e2SAndroid Build Coastguard Worker    if 0 <= (ord(s[-1]) - ord("0")) <= 9:
131*cc02d7e2SAndroid Build Coastguard Worker        return float(s)
132*cc02d7e2SAndroid Build Coastguard Worker    assert "not a number: %s" % s
133*cc02d7e2SAndroid Build Coastguard Worker
134*cc02d7e2SAndroid Build Coastguard Worker
135*cc02d7e2SAndroid Build Coastguard Workerdef parse_name(name):
136*cc02d7e2SAndroid Build Coastguard Worker    cpp_name = name
137*cc02d7e2SAndroid Build Coastguard Worker    if "<" not in name and "/" not in name and name not in _BM_SPECS:
138*cc02d7e2SAndroid Build Coastguard Worker        return {"name": name, "cpp_name": name}
139*cc02d7e2SAndroid Build Coastguard Worker    rest = name
140*cc02d7e2SAndroid Build Coastguard Worker    out = {}
141*cc02d7e2SAndroid Build Coastguard Worker    tpl_args = []
142*cc02d7e2SAndroid Build Coastguard Worker    dyn_args = []
143*cc02d7e2SAndroid Build Coastguard Worker    if "<" in rest:
144*cc02d7e2SAndroid Build Coastguard Worker        tpl_bit = rest[rest.find("<") + 1 : rest.rfind(">")]
145*cc02d7e2SAndroid Build Coastguard Worker        arg = ""
146*cc02d7e2SAndroid Build Coastguard Worker        nesting = 0
147*cc02d7e2SAndroid Build Coastguard Worker        for c in tpl_bit:
148*cc02d7e2SAndroid Build Coastguard Worker            if c == "<":
149*cc02d7e2SAndroid Build Coastguard Worker                nesting += 1
150*cc02d7e2SAndroid Build Coastguard Worker                arg += c
151*cc02d7e2SAndroid Build Coastguard Worker            elif c == ">":
152*cc02d7e2SAndroid Build Coastguard Worker                nesting -= 1
153*cc02d7e2SAndroid Build Coastguard Worker                arg += c
154*cc02d7e2SAndroid Build Coastguard Worker            elif c == ",":
155*cc02d7e2SAndroid Build Coastguard Worker                if nesting == 0:
156*cc02d7e2SAndroid Build Coastguard Worker                    tpl_args.append(arg.strip())
157*cc02d7e2SAndroid Build Coastguard Worker                    arg = ""
158*cc02d7e2SAndroid Build Coastguard Worker                else:
159*cc02d7e2SAndroid Build Coastguard Worker                    arg += c
160*cc02d7e2SAndroid Build Coastguard Worker            else:
161*cc02d7e2SAndroid Build Coastguard Worker                arg += c
162*cc02d7e2SAndroid Build Coastguard Worker        tpl_args.append(arg.strip())
163*cc02d7e2SAndroid Build Coastguard Worker        rest = rest[: rest.find("<")] + rest[rest.rfind(">") + 1 :]
164*cc02d7e2SAndroid Build Coastguard Worker    if "/" in rest:
165*cc02d7e2SAndroid Build Coastguard Worker        s = rest.split("/")
166*cc02d7e2SAndroid Build Coastguard Worker        rest = s[0]
167*cc02d7e2SAndroid Build Coastguard Worker        dyn_args = s[1:]
168*cc02d7e2SAndroid Build Coastguard Worker    name = rest
169*cc02d7e2SAndroid Build Coastguard Worker    assert name in _BM_SPECS, "_BM_SPECS needs to be expanded for %s" % name
170*cc02d7e2SAndroid Build Coastguard Worker    assert len(dyn_args) == len(_BM_SPECS[name]["dyn"])
171*cc02d7e2SAndroid Build Coastguard Worker    assert len(tpl_args) == len(_BM_SPECS[name]["tpl"])
172*cc02d7e2SAndroid Build Coastguard Worker    out["name"] = name
173*cc02d7e2SAndroid Build Coastguard Worker    out["cpp_name"] = cpp_name
174*cc02d7e2SAndroid Build Coastguard Worker    out.update(
175*cc02d7e2SAndroid Build Coastguard Worker        dict(
176*cc02d7e2SAndroid Build Coastguard Worker            (k, numericalize(v))
177*cc02d7e2SAndroid Build Coastguard Worker            for k, v in zip(_BM_SPECS[name]["dyn"], dyn_args)
178*cc02d7e2SAndroid Build Coastguard Worker        )
179*cc02d7e2SAndroid Build Coastguard Worker    )
180*cc02d7e2SAndroid Build Coastguard Worker    out.update(dict(zip(_BM_SPECS[name]["tpl"], tpl_args)))
181*cc02d7e2SAndroid Build Coastguard Worker    return out
182*cc02d7e2SAndroid Build Coastguard Worker
183*cc02d7e2SAndroid Build Coastguard Worker
184*cc02d7e2SAndroid Build Coastguard Workerdef expand_json(js):
185*cc02d7e2SAndroid Build Coastguard Worker    if not js:
186*cc02d7e2SAndroid Build Coastguard Worker        raise StopIteration()
187*cc02d7e2SAndroid Build Coastguard Worker    for bm in js["benchmarks"]:
188*cc02d7e2SAndroid Build Coastguard Worker        if bm["name"].endswith("_stddev") or bm["name"].endswith("_mean"):
189*cc02d7e2SAndroid Build Coastguard Worker            continue
190*cc02d7e2SAndroid Build Coastguard Worker        context = js["context"]
191*cc02d7e2SAndroid Build Coastguard Worker        if "label" in bm:
192*cc02d7e2SAndroid Build Coastguard Worker            labels_list = [
193*cc02d7e2SAndroid Build Coastguard Worker                s.split(":")
194*cc02d7e2SAndroid Build Coastguard Worker                for s in bm["label"].strip().split(" ")
195*cc02d7e2SAndroid Build Coastguard Worker                if len(s) and s[0] != "#"
196*cc02d7e2SAndroid Build Coastguard Worker            ]
197*cc02d7e2SAndroid Build Coastguard Worker            for el in labels_list:
198*cc02d7e2SAndroid Build Coastguard Worker                el[0] = el[0].replace("/iter", "_per_iteration")
199*cc02d7e2SAndroid Build Coastguard Worker            labels = dict(labels_list)
200*cc02d7e2SAndroid Build Coastguard Worker        else:
201*cc02d7e2SAndroid Build Coastguard Worker            labels = {}
202*cc02d7e2SAndroid Build Coastguard Worker        # TODO(jtattermusch): grabbing kokoro env values shouldn't be buried
203*cc02d7e2SAndroid Build Coastguard Worker        # deep in the JSON conversion logic.
204*cc02d7e2SAndroid Build Coastguard Worker        # Link the data to a kokoro job run by adding
205*cc02d7e2SAndroid Build Coastguard Worker        # well known kokoro env variables as metadata for each row
206*cc02d7e2SAndroid Build Coastguard Worker        row = {
207*cc02d7e2SAndroid Build Coastguard Worker            "jenkins_build": os.environ.get("KOKORO_BUILD_NUMBER", ""),
208*cc02d7e2SAndroid Build Coastguard Worker            "jenkins_job": os.environ.get("KOKORO_JOB_NAME", ""),
209*cc02d7e2SAndroid Build Coastguard Worker        }
210*cc02d7e2SAndroid Build Coastguard Worker        row.update(context)
211*cc02d7e2SAndroid Build Coastguard Worker        row.update(bm)
212*cc02d7e2SAndroid Build Coastguard Worker        row.update(parse_name(row["name"]))
213*cc02d7e2SAndroid Build Coastguard Worker        row.update(labels)
214*cc02d7e2SAndroid Build Coastguard Worker        yield row
215