Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / auto_parallel / sapp_ppb / utils / interactive.py: 97%
119 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-06 05:41 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-07-06 05:41 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""Interactive CLI flow used when ``run_pipeline_balance.py`` is launched without arguments."""
16from collections import namedtuple
17from typing import Any, List
19import hyper_parallel.auto_parallel.sapp_ppb.utils.recompute as Recompute
20from hyper_parallel.auto_parallel.sapp_ppb.sapp.sapp_pipeline import SappPipeline
21from hyper_parallel.auto_parallel.sapp_ppb.utils.config import generate_solvable_config, print_dryrun_config
22from hyper_parallel.auto_parallel.sapp_ppb.utils.error import check_in_bounds
23from hyper_parallel.auto_parallel.sapp_ppb.utils.layer import Layer
24from hyper_parallel.auto_parallel.sapp_ppb.utils.logger import logger
26YES_OR_NO = "[y/n]? "
28OPTIONAL = " if you wish: "
30GLOBALARGUMENTS = namedtuple('GLOBALARGUMENTS', ['stage_num', 'micro_batch', 'interleave', 'max_memory'])
33def default_v(d: Any) -> str:
34 """Format an inline ``(<default> if none)`` hint for ``input()`` prompts."""
35 return " (" + str(d) + " if none): "
38def is_yes(s: str) -> bool:
39 """Return True when ``s`` is a yes-like response (``y``, ``yes``, ``1``)."""
40 return s.lower().startswith('y') or s == "1"
43def is_empty(s: str) -> bool:
44 """Return True when ``s`` is blank or equal to ``*``."""
45 return len(s.strip()) == 0 or (s.strip() == '*')
48def global_arguments() -> GLOBALARGUMENTS:
49 """Prompt the user for the global pipeline arguments and return them as a named tuple."""
50 stage_num = 4
51 micro_batch = 8
52 interleave = 1
53 max_memory = 56000
54 s = input("Please enter the pipeline stage number" + default_v(stage_num))
55 if not is_empty(s):
56 stage_num = int(s)
57 check_in_bounds(stage_num, "Pipeline stage number", 1, 10000)
59 s = input("Please enter the micro batch number" + default_v(micro_batch))
60 if not is_empty(s):
61 micro_batch = int(s)
62 check_in_bounds(micro_batch, "Micro batch number", 1, 10000)
64 s = input("Please enter the pipeline interleave number" + default_v(interleave))
65 if not is_empty(s):
66 interleave = int(s)
67 check_in_bounds(interleave, "Interleave", 1, 10)
69 s = input("Please enter maximum memory" + default_v(max_memory))
70 if not is_empty(s):
71 max_memory = int(s)
72 check_in_bounds(max_memory, "Maximum memory", 1, 1000000)
74 return GLOBALARGUMENTS(stage_num, micro_batch, interleave, max_memory)
77def make_layer(t: Layer.type_enum, model_name: str) -> Layer:
78 """Prompt the user for one layer's metadata and return the resulting :class:`Layer`."""
79 nb_layer = 1
80 layer_time = 0
81 memory_parameter = 0
82 memory_activation_rec = {r: None for r in Recompute.TYPE}
83 layer_name = "misc_" + t.name
84 s = input("\tEnter the layer name" + OPTIONAL)
85 if not is_empty(s):
86 layer_name = s
87 s = input("\tEnter the layer execution time: ")
88 if not is_empty(s):
89 layer_time = int(s)
90 if t is Layer.type_enum.BODY:
91 s = input("\tEnter the number of such layer: ")
92 if not is_empty(s):
93 nb_layer = int(s)
94 s = input("\tEnter the layer parameter memory (MB): ")
95 if not is_empty(s):
96 memory_parameter = int(s)
97 for r in Recompute.TYPE:
98 s = input("\tEnter the layer " + Recompute.JSON_MEMORY_NAME[r] + OPTIONAL)
99 if not is_empty(s):
100 memory_activation_rec[r] = int(s)
101 else:
102 s = input("\tEnter the layer memory (MB): ")
103 if not is_empty(s):
104 memory_parameter = int(s)
106 return Layer(name=layer_name, ltype=t, nb_layer=nb_layer, time=layer_time,
107 model_name=model_name, memory_activation_rec=memory_activation_rec,
108 memory_parameter=memory_parameter,)
111def dryrun_guide() -> None:
112 """Prompt the user through a dry-run configuration and print a candidate layout."""
113 considered_rec: List[Recompute.TYPE] = []
114 stage_num = 0
115 num_layers = 0
116 s = input("Please enter the pipeline stage number" + default_v(stage_num))
117 if not is_empty(s):
118 stage_num = int(s)
119 check_in_bounds(stage_num, "Pipeline stage number", 1, 10000)
120 else:
121 return
123 s = input("Please enter the number of layers" + default_v(num_layers))
124 if not is_empty(s):
125 num_layers = int(s)
126 check_in_bounds(num_layers, "Micro batch number", 1, 10000)
127 else:
128 return
130 s = input("Do you consider full recomputation?" + YES_OR_NO)
131 if is_yes(s):
132 considered_rec.append(Recompute.TYPE.FULL)
134 s = input("Do you consider select recomputation?" + YES_OR_NO)
135 if is_yes(s):
136 considered_rec.append(Recompute.TYPE.SLCT)
138 s = input("Does your communication recomputation co-work with select recomputation?" + YES_OR_NO)
139 if is_yes(s):
140 considered_rec.append(Recompute.TYPE.BOTH)
142 s = input("Do you consider extra communication recomputation?" + YES_OR_NO)
143 if is_yes(s):
144 considered_rec.append(Recompute.TYPE.COMM)
146 offset_config_list, rec_config_list = generate_solvable_config(stage_num, num_layers, considered_rec)
147 print_dryrun_config(offset_config_list, rec_config_list)
150def main() -> None:
151 """Entry point for the interactive session launched without CLI arguments."""
152 s = input(
153 "No arguments were given. Would you like to proceed to the interactive mode " + YES_OR_NO)
154 if not is_yes(s):
155 return
157 global_args = global_arguments()
158 number_of_stage = global_args.stage_num
159 number_of_micro_batch = global_args.micro_batch
160 interleave_degree = global_args.interleave
161 max_memory = global_args.max_memory
163 model_name = "misc"
164 s = input("\tEnter the model name" + OPTIONAL)
165 if not is_empty(s):
166 model_name = s
168 layers = []
169 for ltype in Layer.type_enum:
170 if ltype is not Layer.type_enum.UNKNOWN:
171 logger.info("Please enter information of your network %s", ltype.name)
172 layers.append(make_layer(ltype, model_name))
174 pipe = SappPipeline(model_name=model_name, num_of_stage=number_of_stage,
175 num_of_micro_batch=number_of_micro_batch, max_memory=max_memory,
176 layers=layers, num_of_interleave=interleave_degree,)
178 for layer in layers:
179 logger.info("%s", layer)
181 pipe.construct_problem(solver="pulp")
182 pipe.solve_problem(time_limit=40, dump_folder="output")
183 pipe.print_yaml_results()
184 pipe.simulate(show=True)