From a5424707832f9164f21675eea70c472f1e58d291 Mon Sep 17 00:00:00 2001 From: xionghuichen Date: Fri, 25 Nov 2022 03:21:19 +0000 Subject: [PATCH 1/8] Add time tracker --- RLA/easy_log/time_used_recorder.py | 71 +++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/RLA/easy_log/time_used_recorder.py b/RLA/easy_log/time_used_recorder.py index 21771da..958cbb7 100644 --- a/RLA/easy_log/time_used_recorder.py +++ b/RLA/easy_log/time_used_recorder.py @@ -3,9 +3,78 @@ from RLA.easy_log import logger import time +class SingleTimeTracker: + def __init__(self,name:str='untitled') -> None: + self.name=name + self.t = 0.0 + self.call_time=0 + self.time_cost = 0.0 -rc_start_time = {} + def __enter__(self): + # trace time + self.call_time+=1 + self.t = time.perf_counter() + + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.time_cost += time.perf_counter() - self.t + + +class TimeTracker: + def __init__(self): + self.t0=time.time()#to calc total time + self.time_dict=dict() + + def add(self,name='untitled'): + """ + :param name: specify the SingleTimeTracker in the time_dict, recommend use + line num in the scripts, like 'xxx.py Line xxx', can be easily got in python scripts using + `os.path.basename(__file__)+' line '+str(sys._getframe().f_lineno)` + """ + if name not in self.time_dict.keys(): + self.time_dict.update({name:SingleTimeTracker(name)}) + return self.time_dict[name] + + def __call__(self, name:str): + return self.time_dict[name] + + def clear(self): + self.time_dict=dict() + def statistic_entry(self,name:str): + """ + calc total calls of the + """ + assert name in self.time_dict.keys() + + t1=time.time() + t_passed=t1-self.t0 + return { + 'total calls/'+name:self.time_dict[name].call_time, + 'total time cost/'+name:self.time_dict[name].time_cost, + 'average time cost/'+name:self.time_dict[name].time_cost/(1e-6+self.time_dict[name].call_time), + 'time cost percentage/'+name:self.time_dict[name].time_cost/(1e-6+t_passed) + } + + def get_info(self): + info={} + for k in self.time_dict.keys(): + for entry_k,entry_v in self.statistic_entry(k).items(): + info[entry_k]=entry_v + return info + + def log(self,exclude_lst=['csv']): + logger.info('---------time dashboard---------') + for k in self.time_dict.keys(): + for entry_k,entry_v in self.statistic_entry(k).items(): + logger.record_tabular('time_used/'+entry_k,entry_v,exclude=exclude_lst) + logger.info(f"[{entry_k}]: {entry_v}") + logger.info('') + logger.info('---------dashboard end---------') + + +rc_start_time = {} def time_record(name): """ From 7d0ac446ea9a80201a96ea43af1d57db995ebf0b Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Thu, 24 Nov 2022 23:36:19 +0800 Subject: [PATCH 2/8] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d1fb8b1..7b73328 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name='RLA', - version="0.6.0-pre", + version="0.6.0", description=( 'RL assistant' ), From 3d5ff12f6deaec5a0bf880ff25ba4ed5ba837383 Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Fri, 25 Nov 2022 14:14:44 +0800 Subject: [PATCH 3/8] rm dpi (set to default) --- RLA/easy_plot/plot_util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RLA/easy_plot/plot_util.py b/RLA/easy_plot/plot_util.py index b82c039..e6a30d5 100644 --- a/RLA/easy_plot/plot_util.py +++ b/RLA/easy_plot/plot_util.py @@ -315,6 +315,7 @@ def plot_results( show_number=True, skip_legend=False, split_by_metrics=False, + base_dpi=90, rescale_idx=None): ''' Plot multiple Results objects @@ -356,6 +357,7 @@ def plot_results( smooth_step: float - when resampling (i.e. when resample > 0 or average_group is True), use this EMA decay parameter (in units of the new grid step). See docstrings for decay_steps in symmetric_ema or one_sided_ema functions. + ''' score_results = {} if vary_len_plot: @@ -401,7 +403,7 @@ def plot_results( # figsize = list(figsize) # figsize[0] += 4 # figsize = tuple(figsize) - f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize, dpi=90 * ncols) + f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize) groups = [] for results in allresults: groups.extend(group_fn(results)[0]) From b22b8f9d4ea699232583a090486055a7f6ef3df3 Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Thu, 24 Nov 2022 19:01:51 +0800 Subject: [PATCH 4/8] feat(plot): add multiply-metric plotting mode. add demos of plotting function usages. --- RLA/easy_plot/plot_util.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/RLA/easy_plot/plot_util.py b/RLA/easy_plot/plot_util.py index e6a30d5..4ac899e 100644 --- a/RLA/easy_plot/plot_util.py +++ b/RLA/easy_plot/plot_util.py @@ -315,7 +315,6 @@ def plot_results( show_number=True, skip_legend=False, split_by_metrics=False, - base_dpi=90, rescale_idx=None): ''' Plot multiple Results objects @@ -403,7 +402,7 @@ def plot_results( # figsize = list(figsize) # figsize[0] += 4 # figsize = tuple(figsize) - f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize) + f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize, dpi=90 * ncols) groups = [] for results in allresults: groups.extend(group_fn(results)[0]) From 65e482b84b929cb788ecee5962e59b764dc8b02e Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Fri, 25 Nov 2022 14:14:44 +0800 Subject: [PATCH 5/8] rm dpi (set to default) --- RLA/easy_plot/plot_util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RLA/easy_plot/plot_util.py b/RLA/easy_plot/plot_util.py index 4ac899e..e6a30d5 100644 --- a/RLA/easy_plot/plot_util.py +++ b/RLA/easy_plot/plot_util.py @@ -315,6 +315,7 @@ def plot_results( show_number=True, skip_legend=False, split_by_metrics=False, + base_dpi=90, rescale_idx=None): ''' Plot multiple Results objects @@ -402,7 +403,7 @@ def plot_results( # figsize = list(figsize) # figsize[0] += 4 # figsize = tuple(figsize) - f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize, dpi=90 * ncols) + f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize) groups = [] for results in allresults: groups.extend(group_fn(results)[0]) From 52cdb8047c5b458942f1f7d3cd69f486f511acfc Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Fri, 25 Nov 2022 14:19:45 +0800 Subject: [PATCH 6/8] rm useless params --- RLA/easy_plot/plot_util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/RLA/easy_plot/plot_util.py b/RLA/easy_plot/plot_util.py index e6a30d5..fa9176c 100644 --- a/RLA/easy_plot/plot_util.py +++ b/RLA/easy_plot/plot_util.py @@ -315,7 +315,6 @@ def plot_results( show_number=True, skip_legend=False, split_by_metrics=False, - base_dpi=90, rescale_idx=None): ''' Plot multiple Results objects From dda2251ba5fdc0fdde881130e3135c8f970677c5 Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Fri, 25 Nov 2022 15:30:36 +0800 Subject: [PATCH 7/8] refactor(tracker): add a folder for frequently-used trackers --- RLA/trackers/__init__.py | 2 + RLA/trackers/memory_used_recorder.py | 28 +++++++ RLA/trackers/time_used_recorder.py | 107 +++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 RLA/trackers/__init__.py create mode 100644 RLA/trackers/memory_used_recorder.py create mode 100644 RLA/trackers/time_used_recorder.py diff --git a/RLA/trackers/__init__.py b/RLA/trackers/__init__.py new file mode 100644 index 0000000..87302b9 --- /dev/null +++ b/RLA/trackers/__init__.py @@ -0,0 +1,2 @@ +# Created by xionghuichen at 2022/11/25 +# Email: chenxh@lamda.nju.edu.cn diff --git a/RLA/trackers/memory_used_recorder.py b/RLA/trackers/memory_used_recorder.py new file mode 100644 index 0000000..55c9a7f --- /dev/null +++ b/RLA/trackers/memory_used_recorder.py @@ -0,0 +1,28 @@ +# Created by xionghuichen at 2022/11/25 +# Email: chenxh@lamda.nju.edu.cn +import sys + + +from RLA import logger, exp_manager + + +def print_large_memory_variable(): + large_mermory_dict = {} + + def sizeof_fmt(num, suffix='B'): + for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']: + if abs(num) < 1024.0: + return "%3.1f %s%s" % (num, unit, suffix), unit + num /= 1024.0 + return "%.1f %s%s" % (num, 'Yi', suffix), 'Yi' + + for name, size in sorted(((name, sys.getsizeof(value)) for name, value in locals().items()), + key=lambda x: -x[1])[:10]: + size_str, fmt_type = sizeof_fmt(size) + if fmt_type in ['', 'Ki', 'Mi']: + continue + logger.info("{:>30}: {:>8}".format(name, size_str)) + large_mermory_dict[str(name)] = size_str + if large_mermory_dict != {}: + summary = exp_manager.dict_to_table_text_summary(large_mermory_dict, 'large_memory') + exp_manager.add_summary_to_logger(summary, 'large_memory') \ No newline at end of file diff --git a/RLA/trackers/time_used_recorder.py b/RLA/trackers/time_used_recorder.py new file mode 100644 index 0000000..958cbb7 --- /dev/null +++ b/RLA/trackers/time_used_recorder.py @@ -0,0 +1,107 @@ +# Created by xionghuichen at 2022/7/29 +# Email: chenxh@lamda.nju.edu.cn +from RLA.easy_log import logger +import time + +class SingleTimeTracker: + def __init__(self,name:str='untitled') -> None: + self.name=name + self.t = 0.0 + self.call_time=0 + self.time_cost = 0.0 + + def __enter__(self): + # trace time + self.call_time+=1 + self.t = time.perf_counter() + + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.time_cost += time.perf_counter() - self.t + + +class TimeTracker: + def __init__(self): + self.t0=time.time()#to calc total time + self.time_dict=dict() + + def add(self,name='untitled'): + """ + :param name: specify the SingleTimeTracker in the time_dict, recommend use + line num in the scripts, like 'xxx.py Line xxx', can be easily got in python scripts using + `os.path.basename(__file__)+' line '+str(sys._getframe().f_lineno)` + """ + if name not in self.time_dict.keys(): + self.time_dict.update({name:SingleTimeTracker(name)}) + return self.time_dict[name] + + def __call__(self, name:str): + return self.time_dict[name] + + def clear(self): + self.time_dict=dict() + + def statistic_entry(self,name:str): + """ + calc total calls of the + """ + assert name in self.time_dict.keys() + + t1=time.time() + t_passed=t1-self.t0 + return { + 'total calls/'+name:self.time_dict[name].call_time, + 'total time cost/'+name:self.time_dict[name].time_cost, + 'average time cost/'+name:self.time_dict[name].time_cost/(1e-6+self.time_dict[name].call_time), + 'time cost percentage/'+name:self.time_dict[name].time_cost/(1e-6+t_passed) + } + + def get_info(self): + info={} + for k in self.time_dict.keys(): + for entry_k,entry_v in self.statistic_entry(k).items(): + info[entry_k]=entry_v + return info + + def log(self,exclude_lst=['csv']): + logger.info('---------time dashboard---------') + for k in self.time_dict.keys(): + for entry_k,entry_v in self.statistic_entry(k).items(): + logger.record_tabular('time_used/'+entry_k,entry_v,exclude=exclude_lst) + logger.info(f"[{entry_k}]: {entry_v}") + logger.info('') + logger.info('---------dashboard end---------') + + +rc_start_time = {} + +def time_record(name): + """ + record the consumed time of your code snippet. call this function to start a recorder. + "name" is identifier to distinguish different recorder and record different snippets at the same time. + call time_record_end to end a recorder. + :param name: identifier of your code snippet. + :type name: str + :return: + :rtype: + """ + assert name not in rc_start_time + rc_start_time[name] = time.time() + + +def time_record_end(name): + """ + record the consumed time of your code snippet. call this function to start a recorder. + "name" is identifier to distinguish different recorder and record different snippets at the same time. + call time_record_end to end a recorder. + :param name: identifier of your code snippet. + :type name: str + :return: + :rtype: + """ + end_time = time.time() + start_time = rc_start_time[name] + logger.record_tabular("time_used/{}".format(name), end_time - start_time) + logger.info("[test] func {0} time used {1:.2f}".format(name, end_time - start_time)) + del rc_start_time[name] \ No newline at end of file From 6bc18a3dcf3901c519db97a8050dcc08f626365c Mon Sep 17 00:00:00 2001 From: Xiong-Hui Chen Date: Fri, 25 Nov 2022 15:47:27 +0800 Subject: [PATCH 8/8] refactor(easy_plot): better composition for multiple-metrics plotting --- RLA/easy_plot/plot_util.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/RLA/easy_plot/plot_util.py b/RLA/easy_plot/plot_util.py index fa9176c..73eab89 100644 --- a/RLA/easy_plot/plot_util.py +++ b/RLA/easy_plot/plot_util.py @@ -391,12 +391,12 @@ def plot_results( elif tiling == 'symmetric': import math N = len(sk2r) - largest_divisor = 1 - for i in range(1, int(math.sqrt(N))+1): - if N % i == 0: - largest_divisor = i - ncols = largest_divisor - nrows = N // ncols + largest_divisor = int(math.sqrt(N)) + # for i in range(1, int(math.sqrt(N))+1): + # if N % i == 0: + # largest_divisor = i + nrows = largest_divisor + ncols = int(math.ceil(N / nrows)) figsize = figsize or (7 * ncols, 6 * nrows) # if legend_outside: # figsize = list(figsize)