halib 0.2.19__tar.gz → 0.2.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. {halib-0.2.19 → halib-0.2.20}/PKG-INFO +4 -1
  2. {halib-0.2.19 → halib-0.2.20}/README.md +3 -0
  3. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/profiler.py +131 -12
  4. {halib-0.2.19 → halib-0.2.20}/halib.egg-info/PKG-INFO +4 -1
  5. {halib-0.2.19 → halib-0.2.20}/setup.py +1 -1
  6. {halib-0.2.19 → halib-0.2.20}/.gitignore +0 -0
  7. {halib-0.2.19 → halib-0.2.20}/GDriveFolder.txt +0 -0
  8. {halib-0.2.19 → halib-0.2.20}/LICENSE.txt +0 -0
  9. {halib-0.2.19 → halib-0.2.20}/MANIFEST.in +0 -0
  10. {halib-0.2.19 → halib-0.2.20}/halib/__init__.py +0 -0
  11. {halib-0.2.19 → halib-0.2.20}/halib/common/__init__.py +0 -0
  12. {halib-0.2.19 → halib-0.2.20}/halib/common/common.py +0 -0
  13. {halib-0.2.19 → halib-0.2.20}/halib/common/rich_color.py +0 -0
  14. {halib-0.2.19 → halib-0.2.20}/halib/exp/__init__.py +0 -0
  15. {halib-0.2.19 → halib-0.2.20}/halib/exp/core/__init__.py +0 -0
  16. {halib-0.2.19 → halib-0.2.20}/halib/exp/core/base_config.py +0 -0
  17. {halib-0.2.19 → halib-0.2.20}/halib/exp/core/base_exp.py +0 -0
  18. {halib-0.2.19 → halib-0.2.20}/halib/exp/core/param_gen.py +0 -0
  19. {halib-0.2.19 → halib-0.2.20}/halib/exp/core/wandb_op.py +0 -0
  20. {halib-0.2.19 → halib-0.2.20}/halib/exp/data/__init__.py +0 -0
  21. {halib-0.2.19 → halib-0.2.20}/halib/exp/data/dataclass_util.py +0 -0
  22. {halib-0.2.19 → halib-0.2.20}/halib/exp/data/dataset.py +0 -0
  23. {halib-0.2.19 → halib-0.2.20}/halib/exp/data/torchloader.py +0 -0
  24. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/__init__.py +0 -0
  25. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/flop_calc.py +0 -0
  26. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/gpu_mon.py +0 -0
  27. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/perfcalc.py +0 -0
  28. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/perfmetrics.py +0 -0
  29. {halib-0.2.19 → halib-0.2.20}/halib/exp/perf/perftb.py +0 -0
  30. {halib-0.2.19 → halib-0.2.20}/halib/exp/viz/__init__.py +0 -0
  31. {halib-0.2.19 → halib-0.2.20}/halib/exp/viz/plot.py +0 -0
  32. {halib-0.2.19 → halib-0.2.20}/halib/filetype/__init__.py +0 -0
  33. {halib-0.2.19 → halib-0.2.20}/halib/filetype/csvfile.py +0 -0
  34. {halib-0.2.19 → halib-0.2.20}/halib/filetype/ipynb.py +0 -0
  35. {halib-0.2.19 → halib-0.2.20}/halib/filetype/jsonfile.py +0 -0
  36. {halib-0.2.19 → halib-0.2.20}/halib/filetype/textfile.py +0 -0
  37. {halib-0.2.19 → halib-0.2.20}/halib/filetype/videofile.py +0 -0
  38. {halib-0.2.19 → halib-0.2.20}/halib/filetype/yamlfile.py +0 -0
  39. {halib-0.2.19 → halib-0.2.20}/halib/online/__init__.py +0 -0
  40. {halib-0.2.19 → halib-0.2.20}/halib/online/gdrive.py +0 -0
  41. {halib-0.2.19 → halib-0.2.20}/halib/online/gdrive_mkdir.py +0 -0
  42. {halib-0.2.19 → halib-0.2.20}/halib/online/projectmake.py +0 -0
  43. {halib-0.2.19 → halib-0.2.20}/halib/online/tele_noti.py +0 -0
  44. {halib-0.2.19 → halib-0.2.20}/halib/system/__init__.py +0 -0
  45. {halib-0.2.19 → halib-0.2.20}/halib/system/_list_pc.csv +0 -0
  46. {halib-0.2.19 → halib-0.2.20}/halib/system/cmd.py +0 -0
  47. {halib-0.2.19 → halib-0.2.20}/halib/system/filesys.py +0 -0
  48. {halib-0.2.19 → halib-0.2.20}/halib/system/path.py +0 -0
  49. {halib-0.2.19 → halib-0.2.20}/halib/utils/__init__.py +0 -0
  50. {halib-0.2.19 → halib-0.2.20}/halib/utils/dict.py +0 -0
  51. {halib-0.2.19 → halib-0.2.20}/halib/utils/list.py +0 -0
  52. {halib-0.2.19 → halib-0.2.20}/halib.egg-info/SOURCES.txt +0 -0
  53. {halib-0.2.19 → halib-0.2.20}/halib.egg-info/dependency_links.txt +0 -0
  54. {halib-0.2.19 → halib-0.2.20}/halib.egg-info/requires.txt +0 -0
  55. {halib-0.2.19 → halib-0.2.20}/halib.egg-info/top_level.txt +0 -0
  56. {halib-0.2.19 → halib-0.2.20}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.19
3
+ Version: 0.2.20
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -56,6 +56,9 @@ Dynamic: summary
56
56
 
57
57
  ## v0.2.x (Experiment & Core Updates)
58
58
 
59
+ ### **v0.2.20**
60
+ - 🚀 **Improvement:** `exp.perf.profiler` - allow to export *report dict* as csv files for further analysis
61
+
59
62
  ### **v0.2.19**
60
63
  - ✨ **New Feature:** Added `exp.core.param_gen` to facilitate fast generation of parameter combination sweeps (grid search) using YAML configurations.
61
64
 
@@ -2,6 +2,9 @@
2
2
 
3
3
  ## v0.2.x (Experiment & Core Updates)
4
4
 
5
+ ### **v0.2.20**
6
+ - 🚀 **Improvement:** `exp.perf.profiler` - allow to export *report dict* as csv files for further analysis
7
+
5
8
  ### **v0.2.19**
6
9
  - ✨ **New Feature:** Added `exp.core.param_gen` to facilitate fast generation of parameter combination sweeps (grid search) using YAML configurations.
7
10
 
@@ -182,9 +182,9 @@ class zProfiler:
182
182
  │ │ │ [278091.230944486, 278091.251378469],
183
183
  │ }
184
184
  """
185
- assert (
186
- len(ctx_step_dict.keys()) > 0
187
- ), "step_dict must have only one key (step_name) for detail."
185
+ assert len(ctx_step_dict.keys()) > 0, (
186
+ "step_dict must have only one key (step_name) for detail."
187
+ )
188
188
  normed_ctx_step_dict = {}
189
189
  for step_name, time_list in ctx_step_dict.items():
190
190
  if not isinstance(ctx_step_dict[step_name], list):
@@ -246,14 +246,126 @@ class zProfiler:
246
246
  report_dict[ctx_name]["step_dict"]["summary"]["avg_time"][
247
247
  f"avg_{step_name}"
248
248
  ] = avg_time
249
- report_dict[ctx_name]["step_dict"]["summary"][
250
- "total_avg_time"
251
- ] = total_avg_time
249
+ report_dict[ctx_name]["step_dict"]["summary"]["total_avg_time"] = (
250
+ total_avg_time
251
+ )
252
252
  report_dict[ctx_name]["step_dict"]["summary"] = dict(
253
253
  sorted(report_dict[ctx_name]["step_dict"]["summary"].items())
254
254
  )
255
255
  return report_dict
256
256
 
257
+ def get_report_dataframes(self):
258
+ """
259
+ Returns two pandas DataFrames containing profiling data.
260
+
261
+ Returns:
262
+ tuple: (df_summary, df_detail)
263
+ - df_summary: Aggregated stats (Context, Step, Avg, %, Count)
264
+ - df_detail: Raw duration for every single iteration
265
+ """
266
+ try:
267
+ import pandas as pd
268
+ except ImportError:
269
+ logger.error(
270
+ "Pandas is required for get_pandas_dfs(). Please pip install pandas."
271
+ )
272
+ return None, None
273
+
274
+ # Get full data structure
275
+ data = self.get_report_dict(with_detail=True)
276
+
277
+ summary_rows = []
278
+ detail_rows = []
279
+
280
+ for ctx_name, ctx_data in data.items():
281
+ summary = ctx_data["step_dict"]["summary"]
282
+ detail_dict = ctx_data["step_dict"]["detail"]
283
+
284
+ # --- 1. Build Summary Data ---
285
+ # Iterate keys in 'avg_time' to ensure we capture all steps
286
+ for avg_key, avg_val in summary["avg_time"].items():
287
+ step_name = avg_key.replace("avg_", "")
288
+
289
+ # Get corresponding percent
290
+ per_key = f"per_{step_name}"
291
+ percent_val = summary["percent_time"].get(per_key, 0.0)
292
+
293
+ # Get sample count from detail list length
294
+ count = len(detail_dict.get(step_name, []))
295
+
296
+ summary_rows.append(
297
+ {
298
+ "context_name": ctx_name,
299
+ "step_name": step_name,
300
+ "avg_time_sec": avg_val,
301
+ "percent_total": percent_val,
302
+ "sample_count": count,
303
+ }
304
+ )
305
+
306
+ # --- 2. Build Detail Data ---
307
+ for step_name, time_list in detail_dict.items():
308
+ # time_list format: [(idx, duration), (idx, duration)...]
309
+ for item in time_list:
310
+ if len(item) == 2:
311
+ idx, duration = item
312
+ detail_rows.append(
313
+ {
314
+ "context_name": ctx_name,
315
+ "step_name": step_name,
316
+ "iteration_idx": idx,
317
+ "duration_sec": duration,
318
+ }
319
+ )
320
+
321
+ # Create DataFrames
322
+ df_summary = pd.DataFrame(summary_rows)
323
+ df_detail = pd.DataFrame(detail_rows)
324
+
325
+ # Reorder columns for readability (optional but nice)
326
+ if not df_summary.empty:
327
+ df_summary = df_summary[
328
+ [
329
+ "context_name",
330
+ "step_name",
331
+ "avg_time_sec",
332
+ "percent_total",
333
+ "sample_count",
334
+ ]
335
+ ]
336
+
337
+ if not df_detail.empty:
338
+ df_detail = df_detail[
339
+ ["context_name", "step_name", "iteration_idx", "duration_sec"]
340
+ ]
341
+
342
+ return df_summary, df_detail
343
+
344
+ def get_report_csv_files(self, outdir, tag="profiler"):
345
+ """
346
+ Exports profiling data to two CSV files:
347
+ 1. {tag}_summary.csv: Aggregated stats (Avg time, %)
348
+ 2. {tag}_detailed_logs.csv: Raw duration for every iteration
349
+
350
+ Args:
351
+ outdir (str): Directory to save files.
352
+ tag (str): Optional prefix for filenames.
353
+ """
354
+
355
+ if not os.path.exists(outdir):
356
+ os.makedirs(outdir)
357
+ tag_str = f"{tag}_" if tag else ""
358
+ summary_file = os.path.join(outdir, f"{tag_str}summary.csv")
359
+ detail_file = os.path.join(outdir, f"{tag_str}detailed_logs.csv")
360
+
361
+ df_summary, df_detail = self.get_report_dataframes()
362
+ if df_summary is not None:
363
+ df_summary.to_csv(summary_file, index=False, sep=";", encoding="utf-8")
364
+ logger.info(f"Saved summary CSV to: {summary_file}")
365
+ if df_detail is not None:
366
+ df_detail.to_csv(detail_file, index=False, sep=";", encoding="utf-8")
367
+ logger.info(f"Saved detailed logs CSV to: {detail_file}")
368
+
257
369
  @classmethod
258
370
  def plot_formatted_data(
259
371
  cls, profiler_data, outdir=None, file_format="png", do_show=False, tag=""
@@ -282,9 +394,13 @@ class zProfiler:
282
394
 
283
395
  assert n_steps > 0, "No steps found for context: {}".format(ctx)
284
396
  # Generate dynamic colors
285
- colors = px.colors.sample_colorscale(
286
- "Viridis", [i / (n_steps - 1) for i in range(n_steps)]
287
- ) if n_steps > 1 else [px.colors.sample_colorscale("Viridis", [0])[0]]
397
+ colors = (
398
+ px.colors.sample_colorscale(
399
+ "Viridis", [i / (n_steps - 1) for i in range(n_steps)]
400
+ )
401
+ if n_steps > 1
402
+ else [px.colors.sample_colorscale("Viridis", [0])[0]]
403
+ )
288
404
  # pprint(f'{len(colors)} colors generated for {n_steps} steps')
289
405
  color_map = dict(zip(step_names, colors))
290
406
 
@@ -301,7 +417,7 @@ class zProfiler:
301
417
  go.Bar(
302
418
  x=step_names,
303
419
  y=list(avg_times.values()),
304
- text=[f"{v*1000:.2f} ms" for v in avg_times.values()],
420
+ text=[f"{v * 1000:.2f} ms" for v in avg_times.values()],
305
421
  textposition="outside",
306
422
  marker=dict(color=[color_map[s] for s in step_names]),
307
423
  name="", # unified legend
@@ -345,7 +461,9 @@ class zProfiler:
345
461
  # Save figure
346
462
  if outdir is not None:
347
463
  file_prefix = ctx if len(tag_str) == 0 else f"{tag_str}_{ctx}"
348
- file_path = os.path.join(outdir, f"{file_prefix}_summary.{file_format.lower()}")
464
+ file_path = os.path.join(
465
+ outdir, f"{file_prefix}_summary.{file_format.lower()}"
466
+ )
349
467
  fig.write_image(file_path)
350
468
  pprint(f"Saved figure to: 🔽")
351
469
  pprint_local_path(file_path)
@@ -368,6 +486,7 @@ class zProfiler:
368
486
  return self.plot_formatted_data(
369
487
  report, outdir=outdir, file_format=file_format, do_show=do_show, tag=tag
370
488
  )
489
+
371
490
  def meta_info(self):
372
491
  """
373
492
  Print the structure of the profiler's time dictionary.
@@ -375,7 +494,7 @@ class zProfiler:
375
494
  """
376
495
  for ctx_name, ctx_dict in self.time_dict.items():
377
496
  with ConsoleLog(f"Context: {ctx_name}"):
378
- step_names = list(ctx_dict['step_dict'].keys())
497
+ step_names = list(ctx_dict["step_dict"].keys())
379
498
  for step_name in step_names:
380
499
  pprint(f"Step: {step_name}")
381
500
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.19
3
+ Version: 0.2.20
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -56,6 +56,9 @@ Dynamic: summary
56
56
 
57
57
  ## v0.2.x (Experiment & Core Updates)
58
58
 
59
+ ### **v0.2.20**
60
+ - 🚀 **Improvement:** `exp.perf.profiler` - allow to export *report dict* as csv files for further analysis
61
+
59
62
  ### **v0.2.19**
60
63
  - ✨ **New Feature:** Added `exp.core.param_gen` to facilitate fast generation of parameter combination sweeps (grid search) using YAML configurations.
61
64
 
@@ -8,7 +8,7 @@ with open("requirements.txt", "r", encoding="utf-8") as f:
8
8
 
9
9
  setuptools.setup(
10
10
  name="halib",
11
- version="0.2.19",
11
+ version="0.2.20",
12
12
  author="Hoang Van Ha",
13
13
  author_email="hoangvanhauit@gmail.com",
14
14
  description="Small library for common tasks",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes