xref: /XiangShan/scripts/constantHelper.py (revision f24210142010f7e7a701ca25e9fc1aa15595843e)
1ea280170Shappy-lximport os
2ea280170Shappy-lximport random
3ea280170Shappy-lxfrom subprocess import Popen, PIPE
4ea280170Shappy-lximport psutil
5ea280170Shappy-lximport json
6ea280170Shappy-lximport sys
7ea280170Shappy-lximport math
8*f2421014SYanqin Liimport time
9*f2421014SYanqin Lifrom datetime import datetime
10ea280170Shappy-lx
11*f2421014SYanqin Li# usage: python3 constantHelper.py JSON_FILE_PATH [BUILD_PATH]
12ea280170Shappy-lx#
13ea280170Shappy-lx# an example json config file is as follow:
14ea280170Shappy-lx# visit https://bosc.yuque.com/yny0gi/gr7hyo/oy3dagqi9v97p696 for detail
15ea280170Shappy-lx# {
16ea280170Shappy-lx#     "constants": [
17ea280170Shappy-lx#         {
18ea280170Shappy-lx#             "name": "block_cycles_cache_0",
19ea280170Shappy-lx#             "width": 7,
20ea280170Shappy-lx#             "guide": 20,
21ea280170Shappy-lx#             "init": 11
22ea280170Shappy-lx#         },
23ea280170Shappy-lx#         {
24ea280170Shappy-lx#             "name": "block_cycles_cache_1",
25ea280170Shappy-lx#             "width": 7,
26ea280170Shappy-lx#             "init": 18
27ea280170Shappy-lx#         },
28ea280170Shappy-lx#         {
29ea280170Shappy-lx#             "name": "block_cycles_cache_2",
30ea280170Shappy-lx#             "width": 7,
31ea280170Shappy-lx#             "init": 127
32ea280170Shappy-lx#         },
33ea280170Shappy-lx#         {
34ea280170Shappy-lx#             "name": "block_cycles_cache_3",
35ea280170Shappy-lx#             "width": 7,
36ea280170Shappy-lx#             "init": 17
37ea280170Shappy-lx#         }
38ea280170Shappy-lx#     ],
39ea280170Shappy-lx#     "opt_target": [
40ea280170Shappy-lx#         {"successfully_forward_channel_D": {"policy" :"max", "baseline" :0} },
41ea280170Shappy-lx#         {"successfully_forward_mshr": {"policy" :"max", "baseline" :0} },
42ea280170Shappy-lx#         {"dcache.missQueue.entries_0: load_miss_penalty_to_use,": {"policy" :"min", "baseline" :250396} },
43ea280170Shappy-lx#         {"dcache.missQueue.entries_1: load_miss_penalty_to_use,": {"policy" :"min", "baseline" :5634} },
44ea280170Shappy-lx#         {"dcache.missQueue.entries_2: load_miss_penalty_to_use,": {"policy" :"min", "baseline" :4599} },
45ea280170Shappy-lx#         {"dcache.missQueue.entries_3: load_miss_penalty_to_use,": {"policy" :"min", "baseline" :4146} }
46ea280170Shappy-lx#     ],
47ea280170Shappy-lx
48ea280170Shappy-lx#     "population_num": 50,
49ea280170Shappy-lx#     "iteration_num": 50,
50ea280170Shappy-lx#     "crossover_rate": 50,
51ea280170Shappy-lx#     "mutation_rate": 50,
52ea280170Shappy-lx
53ea280170Shappy-lx#     "emu_threads": 16,
54ea280170Shappy-lx#     "concurrent_emu": 4,
55ea280170Shappy-lx#     "max_instr": 1000000,
56ea280170Shappy-lx#     "seed": 3888,
57ea280170Shappy-lx#     "work_load": "~/nexus-am/apps/maprobe/build/maprobe-riscv64-xs.bin"
58ea280170Shappy-lx# }
59ea280170Shappy-lx
60ea280170Shappy-lx
61ea280170Shappy-lx# parameters according to noop
62ea280170Shappy-lxNOOP_HOME = os.getenv("NOOP_HOME")
63*f2421014SYanqin LiXS_PROJECT_ROOT = os.getenv("XS_PROJECT_ROOT")
64*f2421014SYanqin Liif NOOP_HOME is None:
65*f2421014SYanqin Li    print("Please set NOOP_HOME first.")
66*f2421014SYanqin Li    exit(1)
67*f2421014SYanqin Liif XS_PROJECT_ROOT is None:
68*f2421014SYanqin Li    print("Please set XS_PROJECT_ROOT first.")
69*f2421014SYanqin Li    exit(1)
70ea280170Shappy-lxDIFF_PATH = os.path.join(NOOP_HOME, "ready-to-run", "riscv64-nemu-interpreter-so")
71ea280170Shappy-lx
72*f2421014SYanqin Li# get arguments
73*f2421014SYanqin Liif len(sys.argv) > 1:
74*f2421014SYanqin Li    JSON_FILE_PATH=sys.argv[1]
75*f2421014SYanqin Lielse:
76*f2421014SYanqin Li    print("Please specify the json file path")
77*f2421014SYanqin Li    exit(1)
78*f2421014SYanqin Liif len(sys.argv) > 2:
79*f2421014SYanqin Li    BUILD_PATH = sys.argv[2]
80*f2421014SYanqin Lielse:
81*f2421014SYanqin Li    BUILD_PATH = os.path.join(NOOP_HOME, "build")
82*f2421014SYanqin Li
83*f2421014SYanqin LiEMU_PATH = os.path.join(BUILD_PATH, "emu")
84ea280170Shappy-lxCONFIG_FILE_PREFIX = ".constant_result_"
85ea280170Shappy-lxPERF_FILE_POSTFIX = "tmp"
86ea280170Shappy-lxMAXVAL = (1 << 63) - 1
87ea280170Shappy-lx
88ea280170Shappy-lxclass Constant:
89ea280170Shappy-lx    def __init__(self, obj: dict) -> None:
90ea280170Shappy-lx        self.name = obj['name']
91ea280170Shappy-lx        self.width = obj['width']
92ea280170Shappy-lx        self.guide = (1 << self.width - 1) - 1 if 'guide' not in obj.keys() else obj['guide']
93ea280170Shappy-lx        self.init = random.randint(0, self.guide) if 'init' not in obj.keys() else obj['init']
94ea280170Shappy-lx    def maxrange(self) -> int:
95ea280170Shappy-lx        return (1 << self.width) - 1
96ea280170Shappy-lx
97ea280170Shappy-lx
98ea280170Shappy-lxclass Config:
99*f2421014SYanqin Li    def __init__(self, constants, opt_target, population_num, iteration_num, crossover_rate, mutation_rate, emu_threads, concurrent_emu, max_instr, seed, work_load, tag) -> None:
100ea280170Shappy-lx        self.constants = constants
101ea280170Shappy-lx        self.opt_target = opt_target
102ea280170Shappy-lx        self.population_num = int(population_num)
103ea280170Shappy-lx        self.iteration_num = int(iteration_num)
104ea280170Shappy-lx        self.crossover_rate = int(crossover_rate)
105ea280170Shappy-lx        self.mutation_rate = int(mutation_rate)
106ea280170Shappy-lx        self.emu_threads = int(emu_threads)
107ea280170Shappy-lx        self.concurrent_emu = int(concurrent_emu)
108ea280170Shappy-lx        self.max_instr = int(max_instr)
109ea280170Shappy-lx        self.seed = int(seed)
110ea280170Shappy-lx        self.work_load = work_load
111*f2421014SYanqin Li        self.tag = tag
112ea280170Shappy-lx    def get_ith_constant(self, i) -> Constant:
113ea280170Shappy-lx        return self.constants[i]
114ea280170Shappy-lx    def get_constain_num(self) -> int:
115ea280170Shappy-lx        return len(self.constants)
116ea280170Shappy-lx
117ea280170Shappy-lx
118*f2421014SYanqin Lidef loadConfig(json_path, tag) -> Config:
119ea280170Shappy-lx    obj = json.load(open(json_path, "r"))
120ea280170Shappy-lx    constants = [Constant(obj['constants'][i]) for i in range(len(obj['constants']))]
121*f2421014SYanqin Li    config = Config(constants, obj['opt_target'], obj['population_num'], obj['iteration_num'], obj['crossover_rate'], obj['mutation_rate'], obj['emu_threads'], obj['concurrent_emu'], obj['max_instr'], obj['seed'], obj['work_load'], tag)
122ea280170Shappy-lx    return config
123ea280170Shappy-lx
124ea280170Shappy-lxclass RunContext:
125ea280170Shappy-lx    def __init__(self, config: Config) -> None:
126ea280170Shappy-lx        self.config = config
127*f2421014SYanqin Li    def checkCoreFree(self) -> bool:
128ea280170Shappy-lx        percent_per_core = psutil.cpu_percent(interval=1 ,percpu=True)
129ea280170Shappy-lx        acc = 0
130ea280170Shappy-lx        for i in range(self.config.concurrent_emu * self.config.emu_threads):
131ea280170Shappy-lx            acc += percent_per_core[i]
132ea280170Shappy-lx        if acc < (0.1 * (100 * self.config.concurrent_emu * self.config.emu_threads)):
133ea280170Shappy-lx            return True
134ea280170Shappy-lx        else:
135ea280170Shappy-lx            print("no free {} core, core usage:".format(self.config.concurrent_emu * self.config.emu_threads))
136ea280170Shappy-lx            print(percent_per_core)
137ea280170Shappy-lx            return False
138*f2421014SYanqin Li    def get_free_cores(self) -> tuple[bool, int, int, int]:
139*f2421014SYanqin Li        thread = self.config.emu_threads
140*f2421014SYanqin Li        # return (Success?, numa node, start_core, end_core)
141*f2421014SYanqin Li        num_core = psutil.cpu_count(logical=False) # SMT is not allowed
142*f2421014SYanqin Li        core_usage = psutil.cpu_percent(interval=2, percpu=True)
143*f2421014SYanqin Li        num_window = num_core // thread
144*f2421014SYanqin Li        for i in range(num_window):
145*f2421014SYanqin Li            start = i * thread
146*f2421014SYanqin Li            end = (i + 1) * thread
147*f2421014SYanqin Li            window_usage = core_usage[start:end]
148*f2421014SYanqin Li            free = sum(window_usage) < 30 * thread and True not in map(lambda x: x > 80, window_usage)
149*f2421014SYanqin Li            if free:
150*f2421014SYanqin Li                return (True, int(start >= (num_core // 2)), start, end - 1)
151*f2421014SYanqin Li        return (False, 0, 0, 0)
152ea280170Shappy-lx    def getStdIn(self, population: list, id: int) -> str:
153ea280170Shappy-lx        res = 'echo \"'
154ea280170Shappy-lx        res += str(len(population[id]))
155ea280170Shappy-lx        res += '\\n'
156ea280170Shappy-lx        for item in population[id]:
157ea280170Shappy-lx            res += item[0] + ' ' + str(item[1]) + '\\n'
158ea280170Shappy-lx        res += '\"'
159ea280170Shappy-lx        return res
160ea280170Shappy-lx
161*f2421014SYanqin Li    def genRunCMD(self, population, id, numa = None, coreStart = None, coreEnd = None) -> str:
162ea280170Shappy-lx        stdinStr = self.getStdIn(population, id)
163*f2421014SYanqin Li        if None in [numa, coreStart, coreEnd]:
164*f2421014SYanqin Li            return "{} | {} -i {} --diff {} -I {} -s {}".format(stdinStr, EMU_PATH, self.config.work_load, DIFF_PATH, self.config.max_instr, self.config.seed)
165*f2421014SYanqin Li        return "{} | numactl -m {} -C {}-{} {} -i {} --diff {} -I {} -s {}".format(stdinStr, numa, coreStart, coreEnd, EMU_PATH, self.config.work_load, DIFF_PATH, self.config.max_instr, self.config.seed)
166*f2421014SYanqin Li
167*f2421014SYanqin Li    def getOutPath(self, iterid, i):
168*f2421014SYanqin Li        dirPath = os.path.join(BUILD_PATH, self.config.tag)
169*f2421014SYanqin Li        if not os.path.exists(dirPath):
170*f2421014SYanqin Li            os.mkdir(dirPath)
171*f2421014SYanqin Li        return os.path.join(dirPath, f"{iterid}-{i}-out.txt")
172*f2421014SYanqin Li
173*f2421014SYanqin Li    def getPerfPath(self, iterid, i):
174*f2421014SYanqin Li        # return os.path.join(BUILD_PATH, CONFIG_FILE_PREFIX + str(i) + '.' + PERF_FILE_POSTFIX)
175*f2421014SYanqin Li        dirPath = os.path.join(BUILD_PATH, self.config.tag)
176*f2421014SYanqin Li        if not os.path.exists(dirPath):
177*f2421014SYanqin Li            os.mkdir(dirPath)
178*f2421014SYanqin Li        return os.path.join(dirPath, f"{iterid}-{i}-err.txt")
179ea280170Shappy-lx
180ea280170Shappy-lxclass Solution:
181ea280170Shappy-lx    def __init__(self, config: Config) -> None:
182ea280170Shappy-lx        self.config = config
183ea280170Shappy-lx        self.context = RunContext(config)
184ea280170Shappy-lx    def genFirstPopulation(self) -> list:
185ea280170Shappy-lx        res = []
186ea280170Shappy-lx        used = []
187ea280170Shappy-lx        config = self.config
188ea280170Shappy-lx        for i in range(config.population_num):
189ea280170Shappy-lx            candidate = [[config.get_ith_constant(i).name, random.randint(0, config.get_ith_constant(i).maxrange()) % config.get_ith_constant(i).guide] for i in range(config.get_constain_num())]
190ea280170Shappy-lx            while(candidate in used):
191ea280170Shappy-lx                candidate = [[config.get_ith_constant(i).name, random.randint(0, config.get_ith_constant(i).maxrange()) % config.get_ith_constant(i).guide] for i in range(config.get_constain_num())]
192ea280170Shappy-lx            used.append(candidate)
193ea280170Shappy-lx            res.append(candidate)
194ea280170Shappy-lx        assert(len(res) == config.population_num)
195ea280170Shappy-lx        return res
196*f2421014SYanqin Li    def profilling_fitness(self, iterid: int) -> list:
197ea280170Shappy-lx        fitness = []
198ea280170Shappy-lx        lines = []
199ea280170Shappy-lx        for idx in range(self.config.population_num):
200*f2421014SYanqin Li            with open(self.context.getPerfPath(iterid, idx), "r") as fp:
201ea280170Shappy-lx                lines = fp.readlines()
202ea280170Shappy-lx                res = 0
203ea280170Shappy-lx                for line in lines:
204ea280170Shappy-lx                    for opt in config.opt_target:
205ea280170Shappy-lx                        if list(opt.keys())[0] in line:
206ea280170Shappy-lx                            # max and min policy
207ea280170Shappy-lx                            if list(opt.values())[0]['policy'] == 'max':
208ea280170Shappy-lx                                res += int(list(filter(lambda x: x != '', line.split(' ')))[-1]) - int(list(opt.values())[0]['baseline'])
209ea280170Shappy-lx                            elif list(opt.values())[0]['policy'] == 'min':
210ea280170Shappy-lx                                res += int(list(opt.values())[0]['baseline']) - int(list(filter(lambda x: x != '', line.split(' ')))[-1])
211ea280170Shappy-lx                fitness.append(res)
212ea280170Shappy-lx        assert(len(fitness) == self.config.population_num)
213ea280170Shappy-lx        return fitness
214*f2421014SYanqin Li    def run_one_round(self, iterid: int, population: list) -> None:
215ea280170Shappy-lx        procs = []
216ea280170Shappy-lx        i = 0
217ea280170Shappy-lx        while i < len(population):
218ea280170Shappy-lx            if i % self.config.concurrent_emu == 0:
219ea280170Shappy-lx                for proc in procs:
220ea280170Shappy-lx                    proc.wait()
221ea280170Shappy-lx                procs.clear()
222ea280170Shappy-lx            print(population[i])
223*f2421014SYanqin Li            # while True:
224*f2421014SYanqin Li            #     (succ, numa, coreStart, coreEnd) = self.context.get_free_cores()
225*f2421014SYanqin Li            #     if succ:
226*f2421014SYanqin Li            #         with open(self.context.getOutPath(iterid, i), "w") as stdout, open(self.context.getPerfPath(iterid, i), "w") as stderr:
227*f2421014SYanqin Li            #             # print(self.context.genRunCMD(population, i, numa, coreStart, coreEnd), flush=True)
228*f2421014SYanqin Li            #             procs.append(Popen(args=self.context.genRunCMD(population, i, numa, coreStart, coreEnd), shell=True, encoding='utf-8', stdin=PIPE, stdout=stdout, stderr=stderr))
229*f2421014SYanqin Li            #         break
230*f2421014SYanqin Li            #     print("no free {} core".format(self.config.concurrent_emu * self.config.emu_threads))
231*f2421014SYanqin Li            #     time.sleep(5)
232*f2421014SYanqin Li            ## only for tutorial
233*f2421014SYanqin Li            with open(self.context.getOutPath(iterid, i), "w") as stdout, open(self.context.getPerfPath(iterid, i), "w") as stderr:
234*f2421014SYanqin Li                procs.append(Popen(args=self.context.genRunCMD(population, i), shell=True, encoding='utf-8', stdin=PIPE, stdout=stdout, stderr=stderr))
235ea280170Shappy-lx            i += 1
236ea280170Shappy-lx        for proc in procs:
237ea280170Shappy-lx            proc.wait()
238ea280170Shappy-lx    def mutation(self, item: list) -> list:
239ea280170Shappy-lx        res = []
240ea280170Shappy-lx        for val in item:
241ea280170Shappy-lx            width = 0
242ea280170Shappy-lx            guide = 0
243ea280170Shappy-lx            for constant in self.config.constants:
244ea280170Shappy-lx                if(constant.name == val[0]):
245ea280170Shappy-lx                    width = constant.width
246ea280170Shappy-lx                    guide = constant.guide
247ea280170Shappy-lx            mask = 1 << random.randint(0, width - 1)
248ea280170Shappy-lx            if random.randint(0, 100) > self.config.mutation_rate:
249ea280170Shappy-lx                res.append(val)
250ea280170Shappy-lx            else:
251ea280170Shappy-lx                val[1] = (((val[1] & mask) ^ mask) | val[1]) % guide
252ea280170Shappy-lx                res.append(val)
253ea280170Shappy-lx        assert(len(item) == len(res))
254ea280170Shappy-lx        return res
255ea280170Shappy-lx    def crossover(self, poplulation: list) -> list:
256ea280170Shappy-lx        res = []
257ea280170Shappy-lx        if len(poplulation) < 2:
258ea280170Shappy-lx            return poplulation
259ea280170Shappy-lx        for individual in poplulation:
260ea280170Shappy-lx            indivi = []
261ea280170Shappy-lx            for (index, constant) in enumerate(individual):
262ea280170Shappy-lx                const = constant
263ea280170Shappy-lx                if random.randint(0, 100) < self.config.crossover_rate:
264ea280170Shappy-lx                    crossover_target_id = 0
265ea280170Shappy-lx                    while crossover_target_id == index:
266ea280170Shappy-lx                        crossover_target_id = random.randint(0, len(poplulation) - 1)
267ea280170Shappy-lx                    maskMax = 0
268ea280170Shappy-lx                    guide = 0
269ea280170Shappy-lx                    for config_const in self.config.constants:
270ea280170Shappy-lx                        if config_const.name == constant[0]:
271ea280170Shappy-lx                            maskMax = config_const.width
272ea280170Shappy-lx                            guide = config_const.guide
273ea280170Shappy-lx                    maskMax = int(math.log2(guide)) + 1 if (int(math.log2(guide)) + 1 < maskMax) else maskMax
274ea280170Shappy-lx                    maskLen = random.randint(1, maskMax)
275ea280170Shappy-lx                    mask = (1 << maskLen) - 1
276ea280170Shappy-lx                    shiftLen = random.randint(0, maskMax - maskLen)
277ea280170Shappy-lx                    mask = mask << shiftLen
278ea280170Shappy-lx                    const_now = const[1]
279ea280170Shappy-lx                    target_now = poplulation[crossover_target_id][index][1]
280ea280170Shappy-lx                    const_now = ((const_now & ~(mask)) | (target_now & mask)) % guide
281ea280170Shappy-lx                    const = [constant[0], const_now]
282ea280170Shappy-lx                indivi.append(const)
283ea280170Shappy-lx            res.append(indivi)
284ea280170Shappy-lx        assert(len(poplulation) == len(res))
285ea280170Shappy-lx        return res
286ea280170Shappy-lx    def genNextPop(self, curPop, fitness) -> list:
287ea280170Shappy-lx        nextgen = []
288ea280170Shappy-lx        tmp = sorted(zip(curPop, fitness), key=lambda x : x[1], reverse=True)
289ea280170Shappy-lx        print()
290ea280170Shappy-lx        print("opt constant in this round is ", list(tmp)[0][0], " fitness is ", int(list(tmp)[0][1]))
291ea280170Shappy-lx        cross = []
292ea280170Shappy-lx        for i in range(len(tmp)):
293ea280170Shappy-lx            if i < (len(tmp) // 2):
294ea280170Shappy-lx                # select
295ea280170Shappy-lx                nextgen.append(tmp[i][0])
296ea280170Shappy-lx            else:
297ea280170Shappy-lx                cross.append(tmp[i][0])
298ea280170Shappy-lx        # crossover
299ea280170Shappy-lx        cross = self.crossover(cross)
300ea280170Shappy-lx        nextgen = nextgen + cross
301ea280170Shappy-lx        # mutation
302ea280170Shappy-lx        for i in range(len(tmp)):
303ea280170Shappy-lx            nextgen[i] = self.mutation(nextgen[i])
304ea280170Shappy-lx        assert(len(curPop) == len(nextgen))
305ea280170Shappy-lx        return nextgen
306ea280170Shappy-lx
307ea280170Shappy-lx    class HashList:
308ea280170Shappy-lx        def __init__(self, obj: list) -> None:
309ea280170Shappy-lx            # obj: [['test1', 38], ['test2', 15]]
310ea280170Shappy-lx            self.obj = obj
311ea280170Shappy-lx        def __hash__(self) -> str:
312ea280170Shappy-lx            res = ''
313ea280170Shappy-lx            for const in self.obj:
314ea280170Shappy-lx                res += ' '.join(map(lambda x : str(x), const))
315ea280170Shappy-lx            return hash(res)
316ea280170Shappy-lx        def __eq__(self, __o: object) -> bool:
317ea280170Shappy-lx            for (idx, const) in enumerate(self.obj):
318ea280170Shappy-lx                if const != __o.obj[idx]:
319ea280170Shappy-lx                    return False
320ea280170Shappy-lx            return True
321ea280170Shappy-lx
322ea280170Shappy-lx    def gene_cal(self) -> None:
323ea280170Shappy-lx        globalMap = dict()
324ea280170Shappy-lx        if(self.config.population_num % 2 != 0):
325ea280170Shappy-lx            print("gene algrithom must ensure that population_num is an even value")
326ea280170Shappy-lx            return
327ea280170Shappy-lx        parentPoplation = self.genFirstPopulation()
328ea280170Shappy-lx        init_indiv = []
329ea280170Shappy-lx        for constant in self.config.constants:
330ea280170Shappy-lx            const = []
331ea280170Shappy-lx            const.append(constant.name)
332ea280170Shappy-lx            const.append(constant.init)
333ea280170Shappy-lx            init_indiv.append(const)
334ea280170Shappy-lx        parentPoplation.pop()
335ea280170Shappy-lx        parentPoplation.append(init_indiv)
336ea280170Shappy-lx        for i in range(self.config.iteration_num):
337ea280170Shappy-lx            if i != 0:
338ea280170Shappy-lx                print()
339ea280170Shappy-lx            print("iteration ", i, " begins")
340ea280170Shappy-lx            print()
341*f2421014SYanqin Li            self.run_one_round(i, parentPoplation)
342*f2421014SYanqin Li            fitness = self.profilling_fitness(i)
343ea280170Shappy-lx            for (pop, fit) in zip(parentPoplation, fitness):
344ea280170Shappy-lx                globalMap[self.HashList(pop)] = fit
345ea280170Shappy-lx            parentPoplation = self.genNextPop(parentPoplation, fitness)
346*f2421014SYanqin Li
347ea280170Shappy-lx        globalMap = zip(globalMap.keys(), globalMap.values())
348ea280170Shappy-lx        globalMap = sorted(globalMap, key=lambda x : x[1], reverse=True)
349ea280170Shappy-lx        print("opt constant for gene algrithom is ", list(globalMap)[0][0].obj, " fitness", int(list(globalMap)[0][1]))
350ea280170Shappy-lx
351*f2421014SYanqin Litid = datetime.now().strftime("%m%d%H%M")
352*f2421014SYanqin Liconfig = loadConfig(JSON_FILE_PATH, f"constantin_{tid}")
353ea280170Shappy-lxSolution(config).gene_cal()
354