xref: /aosp_15_r20/external/grpc-grpc/test/cpp/qps/scenario_runner.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cc02d7e2SAndroid Build Coastguard Worker
3*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2023 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker#
5*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker#
9*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker#
11*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker"""
17*cc02d7e2SAndroid Build Coastguard WorkerLocal QPS benchmark runner for the OSS Benchmark loadtest configurations.
18*cc02d7e2SAndroid Build Coastguard Worker
19*cc02d7e2SAndroid Build Coastguard WorkerThis tool will run a scenario locally, either already extracted from
20*cc02d7e2SAndroid Build Coastguard Workerscenario_config_exporter, or extracted from a benchmark loadtest config. The
21*cc02d7e2SAndroid Build Coastguard Workerdriver, client, and server all in the same process. You can run the process
22*cc02d7e2SAndroid Build Coastguard Workerunder a custom runner using the --runner_cmd="<COMMAND>" flag, and with custom
23*cc02d7e2SAndroid Build Coastguard Workerenvironment variables if needed.
24*cc02d7e2SAndroid Build Coastguard Worker
25*cc02d7e2SAndroid Build Coastguard WorkerThis example will run an optimized build of the loadtest under gdb
26*cc02d7e2SAndroid Build Coastguard Worker
27*cc02d7e2SAndroid Build Coastguard WorkerGRPC_VERBOSITY=debug \
28*cc02d7e2SAndroid Build Coastguard Worker    bazel run \
29*cc02d7e2SAndroid Build Coastguard Worker    --config=opt \
30*cc02d7e2SAndroid Build Coastguard Worker    --cxxopt="-gmlt" \
31*cc02d7e2SAndroid Build Coastguard Worker    test/cpp/qps:scenario_runner -- \
32*cc02d7e2SAndroid Build Coastguard Worker    --loadtest_file=/path/to/loadtest.config \
33*cc02d7e2SAndroid Build Coastguard Worker    --runner_cmd="gdb --args"
34*cc02d7e2SAndroid Build Coastguard Worker
35*cc02d7e2SAndroid Build Coastguard WorkerThis builds the binary and runs:
36*cc02d7e2SAndroid Build Coastguard Worker
37*cc02d7e2SAndroid Build Coastguard Worker    gdb --args bazel-bin/.../scenario_runner -- \
38*cc02d7e2SAndroid Build Coastguard Worker        --loadtest_config=/tmp/path/extracted_scenario_json.config
39*cc02d7e2SAndroid Build Coastguard Worker
40*cc02d7e2SAndroid Build Coastguard Worker
41*cc02d7e2SAndroid Build Coastguard WorkerIf you have already extracted the JSON scenario using scenario_config_exporter,
42*cc02d7e2SAndroid Build Coastguard Workeryou can replace `--loadtest_file=loadtest.yaml` with
43*cc02d7e2SAndroid Build Coastguard Worker`--scenario_file=scenario.json`.
44*cc02d7e2SAndroid Build Coastguard Worker
45*cc02d7e2SAndroid Build Coastguard Worker
46*cc02d7e2SAndroid Build Coastguard WorkerOther --runner_cmd examples:
47*cc02d7e2SAndroid Build Coastguard Worker    --runner_cmd="perf record -F 777 -o $(pwd)/perf.data -g --event=cpu-cycles",
48*cc02d7e2SAndroid Build Coastguard Worker    --runner_cmd="perf stat record -o $(pwd)/perf.stat.data",
49*cc02d7e2SAndroid Build Coastguard Worker"
50*cc02d7e2SAndroid Build Coastguard Worker"""
51*cc02d7e2SAndroid Build Coastguard Worker
52*cc02d7e2SAndroid Build Coastguard Worker
53*cc02d7e2SAndroid Build Coastguard Workerimport os
54*cc02d7e2SAndroid Build Coastguard Workerimport subprocess
55*cc02d7e2SAndroid Build Coastguard Workerimport sys
56*cc02d7e2SAndroid Build Coastguard Workerimport tempfile
57*cc02d7e2SAndroid Build Coastguard Worker
58*cc02d7e2SAndroid Build Coastguard Workerfrom absl import app
59*cc02d7e2SAndroid Build Coastguard Workerfrom absl import flags
60*cc02d7e2SAndroid Build Coastguard Workerimport yaml
61*cc02d7e2SAndroid Build Coastguard Worker
62*cc02d7e2SAndroid Build Coastguard Worker_LOADTEST_YAML = flags.DEFINE_string(
63*cc02d7e2SAndroid Build Coastguard Worker    "loadtest_file", default=None, help="Path to the benchmark loadtest file"
64*cc02d7e2SAndroid Build Coastguard Worker)
65*cc02d7e2SAndroid Build Coastguard Worker_SCENARIO_JSON = flags.DEFINE_string(
66*cc02d7e2SAndroid Build Coastguard Worker    "scenario_file", default=None, help="Path to a scenario JSON file"
67*cc02d7e2SAndroid Build Coastguard Worker)
68*cc02d7e2SAndroid Build Coastguard Worker_RUNNER_CMD = flags.DEFINE_string(
69*cc02d7e2SAndroid Build Coastguard Worker    "runner_cmd",
70*cc02d7e2SAndroid Build Coastguard Worker    default="",
71*cc02d7e2SAndroid Build Coastguard Worker    help="Run the scearnio runner under a custom command (example: bazel ... --cmd='perf lock record -o $(pwd)/out')",
72*cc02d7e2SAndroid Build Coastguard Worker)
73*cc02d7e2SAndroid Build Coastguard Worker_RUN_FIRST = flags.DEFINE_bool(
74*cc02d7e2SAndroid Build Coastguard Worker    "run_first",
75*cc02d7e2SAndroid Build Coastguard Worker    default=False,
76*cc02d7e2SAndroid Build Coastguard Worker    help="Only run the first scenario in the loadtest",
77*cc02d7e2SAndroid Build Coastguard Worker)
78*cc02d7e2SAndroid Build Coastguard Worker_RUN_ALL = flags.DEFINE_bool(
79*cc02d7e2SAndroid Build Coastguard Worker    "run_all", default=False, help="Run all scenarios in the loadtest"
80*cc02d7e2SAndroid Build Coastguard Worker)
81*cc02d7e2SAndroid Build Coastguard Worker
82*cc02d7e2SAndroid Build Coastguard Worker
83*cc02d7e2SAndroid Build Coastguard Workerdef run_command(filename):
84*cc02d7e2SAndroid Build Coastguard Worker    cmd = [
85*cc02d7e2SAndroid Build Coastguard Worker        os.path.join(
86*cc02d7e2SAndroid Build Coastguard Worker            os.path.dirname(os.path.abspath(__file__)),
87*cc02d7e2SAndroid Build Coastguard Worker            "scenario_runner_cc",
88*cc02d7e2SAndroid Build Coastguard Worker        ),
89*cc02d7e2SAndroid Build Coastguard Worker        "--loadtest_config",
90*cc02d7e2SAndroid Build Coastguard Worker        filename,
91*cc02d7e2SAndroid Build Coastguard Worker    ]
92*cc02d7e2SAndroid Build Coastguard Worker    if _RUNNER_CMD.value:
93*cc02d7e2SAndroid Build Coastguard Worker        cmd = _RUNNER_CMD.value.split(" ") + cmd
94*cc02d7e2SAndroid Build Coastguard Worker    print(cmd)
95*cc02d7e2SAndroid Build Coastguard Worker    subprocess.run(cmd, check=True)
96*cc02d7e2SAndroid Build Coastguard Worker    if _RUN_FIRST.value:
97*cc02d7e2SAndroid Build Coastguard Worker        print("Exiting due to --run_first")
98*cc02d7e2SAndroid Build Coastguard Worker        sys.exit(0)
99*cc02d7e2SAndroid Build Coastguard Worker
100*cc02d7e2SAndroid Build Coastguard Worker
101*cc02d7e2SAndroid Build Coastguard Workerdef run_loadtests():
102*cc02d7e2SAndroid Build Coastguard Worker    loadtests = []
103*cc02d7e2SAndroid Build Coastguard Worker    with open(
104*cc02d7e2SAndroid Build Coastguard Worker        os.path.join(
105*cc02d7e2SAndroid Build Coastguard Worker            os.path.dirname(os.path.abspath(__file__)), _LOADTEST_YAML.value
106*cc02d7e2SAndroid Build Coastguard Worker        )
107*cc02d7e2SAndroid Build Coastguard Worker    ) as f:
108*cc02d7e2SAndroid Build Coastguard Worker        loadtests = list(yaml.safe_load_all(f))
109*cc02d7e2SAndroid Build Coastguard Worker    if len(loadtests) > 1 and not (_RUN_FIRST.value or _RUN_ALL.value):
110*cc02d7e2SAndroid Build Coastguard Worker        print(
111*cc02d7e2SAndroid Build Coastguard Worker            "The loadtest configuration file contains more than one loadtest. Please specify --run_first or --run_all.",
112*cc02d7e2SAndroid Build Coastguard Worker            file=sys.stderr,
113*cc02d7e2SAndroid Build Coastguard Worker        )
114*cc02d7e2SAndroid Build Coastguard Worker        sys.exit(1)
115*cc02d7e2SAndroid Build Coastguard Worker    for loadtest in loadtests:
116*cc02d7e2SAndroid Build Coastguard Worker        with tempfile.NamedTemporaryFile() as tmp_f:
117*cc02d7e2SAndroid Build Coastguard Worker            tmp_f.write(
118*cc02d7e2SAndroid Build Coastguard Worker                "".join(loadtest["spec"]["scenariosJSON"]).encode("utf-8")
119*cc02d7e2SAndroid Build Coastguard Worker            )
120*cc02d7e2SAndroid Build Coastguard Worker            tmp_f.flush()
121*cc02d7e2SAndroid Build Coastguard Worker            run_command(tmp_f.name)
122*cc02d7e2SAndroid Build Coastguard Worker
123*cc02d7e2SAndroid Build Coastguard Worker
124*cc02d7e2SAndroid Build Coastguard Workerdef run_scenario_file():
125*cc02d7e2SAndroid Build Coastguard Worker    run_command(_SCENARIO_JSON.value)
126*cc02d7e2SAndroid Build Coastguard Worker
127*cc02d7e2SAndroid Build Coastguard Worker
128*cc02d7e2SAndroid Build Coastguard Workerdef main(args):
129*cc02d7e2SAndroid Build Coastguard Worker    if _LOADTEST_YAML.value:
130*cc02d7e2SAndroid Build Coastguard Worker        run_loadtests()
131*cc02d7e2SAndroid Build Coastguard Worker    elif _SCENARIO_JSON.value:
132*cc02d7e2SAndroid Build Coastguard Worker        run_scenario_file()
133*cc02d7e2SAndroid Build Coastguard Worker    else:
134*cc02d7e2SAndroid Build Coastguard Worker        "You must provide either a scenario.json or loadtest.yaml"
135*cc02d7e2SAndroid Build Coastguard Worker
136*cc02d7e2SAndroid Build Coastguard Worker
137*cc02d7e2SAndroid Build Coastguard Workerif __name__ == "__main__":
138*cc02d7e2SAndroid Build Coastguard Worker    app.run(main)
139