# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. """The core tuning API""" from .builder import Builder from .cost_model import CostModel from .database import Database from .measure_callback import MeasureCallback from .post_optimization import PostOpt from .runner import Runner from .task_scheduler import TaskScheduler from .tune_context import TuneContext def tune_tasks( *, tasks: list[TuneContext], task_weights: list[float], work_dir: str, max_trials_global: int, max_trials_per_task: int | None = None, num_trials_per_iter: int = 64, builder: Builder.BuilderType = "local", runner: Runner.RunnerType = "local", database: Database.DatabaseType = "json", cost_model: CostModel.CostModelType = "xgb", measure_callbacks: MeasureCallback.CallbackListType = "default", task_scheduler: TaskScheduler.TaskSchedulerType = "gradient", module_equality: str = "structural", post_optimization: bool | None = False, ) -> Database: """Tune a list of tasks. Using a task scheduler. Parameters ---------- tasks : List[TuneContext] The list of tasks to tune. task_weights : List[float] The weight of each task. work_dir : str The working directory. max_trials_global : int The maximum number of trials to run globally. max_trials_per_task : Optional[int] The maximum number of trials to run per task. num_trials_per_iter : int The number of trials to run per iteration builder : Builder.BuilderType The builder. runner : Runner.RunnerType The runner. database : Database.DatabaseType The database. cost_model : CostModel.CostModelType The cost model. measure_callbacks : MeasureCallback.CallbackListType The measure callbacks. task_scheduler : TaskScheduler.TaskSchedulerType The task scheduler. module_equality : Optional[str] A string to specify the module equality testing and hashing method. It must be one of the followings: - "structural": Use StructuralEqual/Hash - "ignore-tensor": Same as "structural", but ignore tensor raw data during equality testing and hashing. - "anchor-block": Apply equality testing and hashing on the anchor block extracted from a given module. The "ignore-tensor" varint is used for the extracted blocks or in case no anchor block is found. For the definition of the anchor block, see tirx/analysis/analysis.py. post_optimization : Optional[Bool] Generate post-optimization using Droplet Search as exploitation space. Returns ------- database : Database The database with all tuning records """ if len(tasks) == 0: raise ValueError("No tasks to tune.") if len(tasks) != len(task_weights): raise ValueError( f"Length of tasks ({len(tasks)}) and task_weights ({len(task_weights)}) do not match." ) num_cores = tasks[0].num_threads if max_trials_per_task is None: max_trials_per_task = max_trials_global if not isinstance(builder, Builder): builder = Builder.create(builder, max_workers=num_cores) if not isinstance(runner, Runner): runner = Runner.create(runner, max_workers=num_cores) if database == "json": database = Database.create(database, work_dir=work_dir, module_equality=module_equality) elif not isinstance(database, Database): database = Database.create(database, module_equality=module_equality) if not isinstance(cost_model, CostModel): cost_model = CostModel.create(cost_model, num_tuning_cores=num_cores, tree_method="auto") if isinstance(measure_callbacks, MeasureCallback): measure_callbacks = [measure_callbacks] elif measure_callbacks == "default": measure_callbacks = MeasureCallback.create(measure_callbacks) if not isinstance(task_scheduler, TaskScheduler): task_scheduler = TaskScheduler.create(task_scheduler) task_scheduler.tune( tasks=tasks, task_weights=task_weights, max_trials_global=max_trials_global, max_trials_per_task=max_trials_per_task, num_trials_per_iter=num_trials_per_iter, builder=builder, runner=runner, measure_callbacks=measure_callbacks, database=database, cost_model=cost_model, ) if post_optimization: post_opt = PostOpt(work_dir, tasks[0].target) post_opt.run() return database