chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
# 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.
|
||||
"""Logging interface in MetaSchedule"""
|
||||
|
||||
import logging
|
||||
import logging.config
|
||||
import os
|
||||
import os.path as osp
|
||||
from collections.abc import Callable
|
||||
from logging import Logger
|
||||
from typing import Any
|
||||
|
||||
|
||||
def get_logger(name: str) -> Logger:
|
||||
"""Create or get a logger by its name. This is essentially a wrapper of python's native logger.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
The name of the logger.
|
||||
|
||||
Returns
|
||||
-------
|
||||
logger : Logger
|
||||
The logger instance.
|
||||
"""
|
||||
return logging.getLogger(name)
|
||||
|
||||
|
||||
def get_logging_func(logger: Logger) -> Callable[[int, str, int, str], None] | None:
|
||||
"""Get the logging function.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
logger : Logger
|
||||
The logger instance.
|
||||
Returns
|
||||
-------
|
||||
result : Optional[Callable]
|
||||
The function to do the specified level of logging.
|
||||
"""
|
||||
if logger is None:
|
||||
return None
|
||||
|
||||
level2log = {
|
||||
logging.DEBUG: logger.debug,
|
||||
logging.INFO: logger.info,
|
||||
logging.WARNING: logger.warning,
|
||||
logging.ERROR: logger.error,
|
||||
# logging.FATAL not included
|
||||
}
|
||||
|
||||
def logging_func(level: int, filename: str, lineo: int, msg: str):
|
||||
if level < 0: # clear the output in notebook / console
|
||||
from IPython.display import ( # type: ignore # pylint: disable=import-outside-toplevel
|
||||
clear_output,
|
||||
)
|
||||
|
||||
clear_output(wait=True)
|
||||
else:
|
||||
level2log[level](f"[{os.path.basename(filename)}:{lineo}] " + msg)
|
||||
|
||||
return logging_func
|
||||
|
||||
|
||||
def create_loggers(
|
||||
log_dir: str,
|
||||
params: list[dict[str, Any]],
|
||||
logger_config: dict[str, Any] | None = None,
|
||||
disable_existing_loggers: bool = False,
|
||||
):
|
||||
"""Create loggers from configuration"""
|
||||
if logger_config is None:
|
||||
config = {}
|
||||
else:
|
||||
config = logger_config
|
||||
|
||||
config.setdefault("loggers", {})
|
||||
config.setdefault("handlers", {})
|
||||
config.setdefault("formatters", {})
|
||||
|
||||
global_logger_name = "tvm.s_tir.meta_schedule"
|
||||
global_logger = logging.getLogger(global_logger_name)
|
||||
if global_logger.level is logging.NOTSET:
|
||||
global_logger.setLevel(logging.DEBUG)
|
||||
console_logging_level = logging._levelToName[ # pylint: disable=protected-access
|
||||
global_logger.level
|
||||
]
|
||||
|
||||
config["loggers"].setdefault(
|
||||
global_logger_name,
|
||||
{
|
||||
"level": logging.DEBUG,
|
||||
"handlers": [handler.get_name() for handler in global_logger.handlers]
|
||||
+ [global_logger_name + ".console", global_logger_name + ".file"],
|
||||
"propagate": False,
|
||||
},
|
||||
)
|
||||
config["loggers"].setdefault(
|
||||
"{logger_name}",
|
||||
{
|
||||
"level": "DEBUG",
|
||||
"handlers": [
|
||||
"{logger_name}.file",
|
||||
],
|
||||
"propagate": False,
|
||||
},
|
||||
)
|
||||
config["handlers"].setdefault(
|
||||
global_logger_name + ".console",
|
||||
{
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stdout",
|
||||
"formatter": "tvm.s_tir.meta_schedule.standard_formatter",
|
||||
"level": console_logging_level,
|
||||
},
|
||||
)
|
||||
config["handlers"].setdefault(
|
||||
global_logger_name + ".file",
|
||||
{
|
||||
"class": "logging.FileHandler",
|
||||
"filename": "{log_dir}/" + __name__ + ".task_scheduler.log",
|
||||
"mode": "a",
|
||||
"level": "DEBUG",
|
||||
"formatter": "tvm.s_tir.meta_schedule.standard_formatter",
|
||||
},
|
||||
)
|
||||
config["handlers"].setdefault(
|
||||
"{logger_name}.file",
|
||||
{
|
||||
"class": "logging.FileHandler",
|
||||
"filename": "{log_dir}/{logger_name}.log",
|
||||
"mode": "a",
|
||||
"level": "DEBUG",
|
||||
"formatter": "tvm.s_tir.meta_schedule.standard_formatter",
|
||||
},
|
||||
)
|
||||
config["formatters"].setdefault(
|
||||
"tvm.s_tir.meta_schedule.standard_formatter",
|
||||
{
|
||||
"format": "%(asctime)s [%(levelname)s] %(message)s",
|
||||
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||
},
|
||||
)
|
||||
|
||||
# set up dictConfig loggers
|
||||
p_config = {"version": 1, "disable_existing_loggers": disable_existing_loggers}
|
||||
for k, v in config.items():
|
||||
if k in ["formatters", "handlers", "loggers"]:
|
||||
p_config[k] = _batch_parameterize_config(v, params) # type: ignore
|
||||
else:
|
||||
p_config[k] = v
|
||||
logging.config.dictConfig(p_config)
|
||||
|
||||
# check global logger
|
||||
if global_logger.level not in [logging.DEBUG, logging.INFO]:
|
||||
global_logger.warning(
|
||||
"Logging level set to %s, please set to logging.INFO"
|
||||
" or logging.DEBUG to view full log.",
|
||||
logging._levelToName[global_logger.level], # pylint: disable=protected-access
|
||||
)
|
||||
global_logger.info("Logging directory: %s", log_dir)
|
||||
|
||||
|
||||
def _batch_parameterize_config(
|
||||
config: dict[str, Any],
|
||||
params: list[dict[str, str]],
|
||||
) -> dict[str, Any]:
|
||||
"""Parameterize the given configuration with multiple parameters sets.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
config : Dict[str, Any]
|
||||
The given config dict.
|
||||
Params : List[Dict[str, str]]
|
||||
List of the given multiple parameters sets.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : Dict[str, Any]
|
||||
The parameterized configuration.
|
||||
"""
|
||||
results = {}
|
||||
for name, cfg in config.items():
|
||||
for p in params:
|
||||
p_name = name.format(**p)
|
||||
if p_name not in results:
|
||||
p_cfg = _parameterize_config(cfg, p)
|
||||
results[p_name] = p_cfg
|
||||
return results
|
||||
|
||||
|
||||
def _parameterize_config(
|
||||
config: dict[str, Any],
|
||||
params: dict[str, str],
|
||||
) -> dict[str, Any]:
|
||||
"""Parameterize the given configuration.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
config : Dict[str, Any]
|
||||
The given config dict.
|
||||
Params : Dict[str, str]
|
||||
The given parameters.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : Dict[str, Any]
|
||||
The parameterized configuration.
|
||||
"""
|
||||
result = {}
|
||||
for k, v in config.items():
|
||||
if isinstance(k, str):
|
||||
k = k.format(**params)
|
||||
if isinstance(v, str):
|
||||
v = v.format(**params)
|
||||
elif isinstance(v, dict):
|
||||
v = _parameterize_config(v, params)
|
||||
elif isinstance(v, list):
|
||||
v = [t.format(**params) for t in v]
|
||||
result[k] = v
|
||||
return result
|
||||
|
||||
|
||||
def get_loggers_from_work_dir(
|
||||
work_dir: str,
|
||||
task_names: list[str],
|
||||
) -> list[Logger]:
|
||||
"""Create loggers from work directory
|
||||
|
||||
Parameters
|
||||
----------
|
||||
work_dir : str
|
||||
The work directory.
|
||||
task_names : List[str]
|
||||
The list of task names.
|
||||
|
||||
Returns
|
||||
-------
|
||||
loggers : List[Logger]
|
||||
The list of loggers.
|
||||
"""
|
||||
log_dir = osp.join(work_dir, "logs")
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
pattern = __name__ + ".task_{i:0" + f"{len(str(len(task_names) - 1))}" + "d}_{name}"
|
||||
# Very long names may need be clipped to prevent os errors, we use the first 100 characters.
|
||||
loggers = [pattern.format(i=i, name=name[:100]) for i, name in enumerate(task_names)]
|
||||
create_loggers(
|
||||
log_dir=log_dir,
|
||||
params=[{"log_dir": log_dir, "logger_name": logger} for logger in loggers],
|
||||
)
|
||||
return [get_logger(logger) for logger in loggers]
|
||||
Reference in New Issue
Block a user