dsa-profiler-rishad 0.1.1__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.
- dsa_profiler_rishad-0.1.1/PKG-INFO +124 -0
- dsa_profiler_rishad-0.1.1/README.md +112 -0
- dsa_profiler_rishad-0.1.1/pyproject.toml +22 -0
- dsa_profiler_rishad-0.1.1/setup.cfg +4 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler/__init__.py +6 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler/analyzer.py +56 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler/core.py +102 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler/reporter.py +68 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler/storage.py +57 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler_rishad.egg-info/PKG-INFO +124 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler_rishad.egg-info/SOURCES.txt +12 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler_rishad.egg-info/dependency_links.txt +1 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler_rishad.egg-info/requires.txt +1 -0
- dsa_profiler_rishad-0.1.1/src/dsa_profiler_rishad.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dsa-profiler-rishad
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A local-first profiling tool to benchmark and compare DSA solution efficiency.
|
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Classifier: Topic :: Software Development :: Testing
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: rich>=13.0.0
|
|
12
|
+
|
|
13
|
+
# 📊 DSA Profiler (`dsa-profiler-rishad`)
|
|
14
|
+
|
|
15
|
+
A local-first, production-grade profiling framework engineered for developers and students to benchmark Data Structures and Algorithms (DSA) solutions. The tool captures high-precision runtime execution metrics, monitors dynamic peak memory allocation, tracks local performance history via an embedded relational database, and utilizes empirical statistical curve-fitting to programmatically predict algorithmic Big-O complexities.
|
|
16
|
+
|
|
17
|
+
## ✨ Core Engineering Features
|
|
18
|
+
|
|
19
|
+
- **⏱️ High-Precision Performance Benchmarking:** Bypasses standard wrapper latencies using hardware-level system counters (`time.perf_counter`). Utilizes customizable multi-iteration tracking and calculates **median execution runtimes** to systematically filter out background operating system process jitter.
|
|
20
|
+
- **🧠 Dynamic Peak Memory Tracking:** Integrates native virtual memory space tracking via `tracemalloc` to capture the exact maximum byte footprint utilized by an algorithm during execution.
|
|
21
|
+
- **💾 Persistent Local Data Storage Engine:** Built with a serverless relational `sqlite3` data layer. Automatically initializes and manages a hidden repository file (`.dsa_profile_history.db`) inside the execution workspace to preserve historical performance states across terminal runs.
|
|
22
|
+
- **📈 Automated Optimization Delta Engine:** Computes exact optimization shifts between successive approaches using structural percentage metrics. Generates beautiful, color-coded tabular comparisons (`rich`) displaying runtime shifts, memory gains, or regression warnings.
|
|
23
|
+
- **🚀 Empirical Asymptotic Analyzer:** Runs solutions over variable scaling input sizes ($N$) and implements a **Pure-Python Ordinary Least Squares (OLS) Linear Regression Engine**. Computes Pearson Correlation Coefficients ($R^2$) across distinct linearized transformation spaces to predict mathematical time complexities ($O(1)$, $O(\log N)$, $O(N)$, $O(N \log N)$, $O(N^2)$).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🛠️ System Architecture & Mathematical Foundations
|
|
28
|
+
|
|
29
|
+
### 1. The Optimization Delta Logic
|
|
30
|
+
When consecutive alternative approaches are registered under the same `problem_id`, the system isolates the immediately preceding run from the relational database to calculate the exact structural evolution metric:
|
|
31
|
+
|
|
32
|
+
$$\Delta \text{Time} = \left( \frac{\text{Time}_{\text{previous}} - \text{Time}_{\text{current}}}{\text{Time}_{\text{previous}}} \right) \times 100$$
|
|
33
|
+
|
|
34
|
+
A positive result signals a **Speedup Success** (color-coded green), whereas a negative result automatically trips a **Performance Drop** warning (color-coded red).
|
|
35
|
+
|
|
36
|
+
### 2. Empirical Big-O Curve Fitting
|
|
37
|
+
Instead of reading code text structures statically, the library profiles data points across a scaling range of $N$ and transforms input parameters to find linear relationships. The system manual regression uses the Pearson Correlation Coefficient ($R$) formula:
|
|
38
|
+
|
|
39
|
+
$$R = \frac{n\sum xy - (\sum x)(\sum y)}{\sqrt{[n\sum x^2 - (\sum x)^2][n\sum y^2 - (\sum y)^2]}}$$
|
|
40
|
+
|
|
41
|
+
The model evaluating the highest Coefficient of Determination ($R^2$) closest to `1.0` is programmatically crowned as the predicted asymptotic complexity bound.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 📦 Installation
|
|
46
|
+
|
|
47
|
+
Ensure you have Python >= 3.8 installed, then fetch the package from the index:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install --index-url [https://test.pypi.org/simple/](https://test.pypi.org/simple/) --extra-index-url [https://pypi.org/simple/](https://pypi.org/simple/) dsa-profiler-rishad
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
🚀 Practical Guide & Usage
|
|
54
|
+
1. Comparative Solution Tracking
|
|
55
|
+
Track execution shifts across different iterations of an optimization cycle:
|
|
56
|
+
|
|
57
|
+
import time
|
|
58
|
+
from dsa_profiler import profile_dsa
|
|
59
|
+
|
|
60
|
+
@profile_dsa(problem_id="two-sum", run_name="brute-force", iteration=3)
|
|
61
|
+
def solve_via_brute():
|
|
62
|
+
time.sleep(0.1) # Simulate nested loop overhead
|
|
63
|
+
return "done"
|
|
64
|
+
|
|
65
|
+
@profile_dsa(problem_id="two-sum", run_name="hash-map-optimized", iteration=3)
|
|
66
|
+
def solve_via_map():
|
|
67
|
+
time.sleep(0.01) # Simulate high-speed lookup
|
|
68
|
+
return "done"
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
solve_via_brute()
|
|
72
|
+
solve_via_map()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
2. Algorithmic Big-O Estimation
|
|
76
|
+
Empirically isolate the asymptotic complexity profile of an approach over expanding dataset sizes:
|
|
77
|
+
|
|
78
|
+
import time
|
|
79
|
+
from dsa_profiler import profile_big_o
|
|
80
|
+
|
|
81
|
+
@profile_big_o(n_range=[100, 500, 1000, 2000])
|
|
82
|
+
def simulate_linear_growth(n):
|
|
83
|
+
for i in range(n):
|
|
84
|
+
pass
|
|
85
|
+
time.sleep(n * 0.00001)
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
simulate_linear_growth()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
🧱 Project Directory Layout
|
|
92
|
+
dsa_profiler/
|
|
93
|
+
│
|
|
94
|
+
├── src/
|
|
95
|
+
│ └── dsa_profiler/
|
|
96
|
+
│ ├── __init__.py # Clean package API exports
|
|
97
|
+
│ ├── core.py # Main execution interceptor decorators
|
|
98
|
+
│ ├── storage.py # SQLite data access persistence layer
|
|
99
|
+
│ ├── reporter.py # Analytics engine & UI generator
|
|
100
|
+
│ └── analyzer.py # Mathematical OLS regression engine
|
|
101
|
+
│
|
|
102
|
+
├── tests/
|
|
103
|
+
│ └── demo.py # Sandbox execution suite
|
|
104
|
+
│
|
|
105
|
+
├── pyproject.toml # Package distribution metadata configurations
|
|
106
|
+
└── README.md # Architecture documentation centerpiece
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
📄 License
|
|
110
|
+
This framework is open-source software licensed under the MIT License.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### What to do next:
|
|
115
|
+
1. Save this into `README.md`.
|
|
116
|
+
2. Follow our rebuild sequence to update the package version to `0.1.1` in `pyproject.toml` and compile it:
|
|
117
|
+
```cmd
|
|
118
|
+
rmdir /s /q dist
|
|
119
|
+
python -m build
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
Upload it to TestPyPI:
|
|
123
|
+
|
|
124
|
+
python -m twine upload --repository testpypi dist/*
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# 📊 DSA Profiler (`dsa-profiler-rishad`)
|
|
2
|
+
|
|
3
|
+
A local-first, production-grade profiling framework engineered for developers and students to benchmark Data Structures and Algorithms (DSA) solutions. The tool captures high-precision runtime execution metrics, monitors dynamic peak memory allocation, tracks local performance history via an embedded relational database, and utilizes empirical statistical curve-fitting to programmatically predict algorithmic Big-O complexities.
|
|
4
|
+
|
|
5
|
+
## ✨ Core Engineering Features
|
|
6
|
+
|
|
7
|
+
- **⏱️ High-Precision Performance Benchmarking:** Bypasses standard wrapper latencies using hardware-level system counters (`time.perf_counter`). Utilizes customizable multi-iteration tracking and calculates **median execution runtimes** to systematically filter out background operating system process jitter.
|
|
8
|
+
- **🧠 Dynamic Peak Memory Tracking:** Integrates native virtual memory space tracking via `tracemalloc` to capture the exact maximum byte footprint utilized by an algorithm during execution.
|
|
9
|
+
- **💾 Persistent Local Data Storage Engine:** Built with a serverless relational `sqlite3` data layer. Automatically initializes and manages a hidden repository file (`.dsa_profile_history.db`) inside the execution workspace to preserve historical performance states across terminal runs.
|
|
10
|
+
- **📈 Automated Optimization Delta Engine:** Computes exact optimization shifts between successive approaches using structural percentage metrics. Generates beautiful, color-coded tabular comparisons (`rich`) displaying runtime shifts, memory gains, or regression warnings.
|
|
11
|
+
- **🚀 Empirical Asymptotic Analyzer:** Runs solutions over variable scaling input sizes ($N$) and implements a **Pure-Python Ordinary Least Squares (OLS) Linear Regression Engine**. Computes Pearson Correlation Coefficients ($R^2$) across distinct linearized transformation spaces to predict mathematical time complexities ($O(1)$, $O(\log N)$, $O(N)$, $O(N \log N)$, $O(N^2)$).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🛠️ System Architecture & Mathematical Foundations
|
|
16
|
+
|
|
17
|
+
### 1. The Optimization Delta Logic
|
|
18
|
+
When consecutive alternative approaches are registered under the same `problem_id`, the system isolates the immediately preceding run from the relational database to calculate the exact structural evolution metric:
|
|
19
|
+
|
|
20
|
+
$$\Delta \text{Time} = \left( \frac{\text{Time}_{\text{previous}} - \text{Time}_{\text{current}}}{\text{Time}_{\text{previous}}} \right) \times 100$$
|
|
21
|
+
|
|
22
|
+
A positive result signals a **Speedup Success** (color-coded green), whereas a negative result automatically trips a **Performance Drop** warning (color-coded red).
|
|
23
|
+
|
|
24
|
+
### 2. Empirical Big-O Curve Fitting
|
|
25
|
+
Instead of reading code text structures statically, the library profiles data points across a scaling range of $N$ and transforms input parameters to find linear relationships. The system manual regression uses the Pearson Correlation Coefficient ($R$) formula:
|
|
26
|
+
|
|
27
|
+
$$R = \frac{n\sum xy - (\sum x)(\sum y)}{\sqrt{[n\sum x^2 - (\sum x)^2][n\sum y^2 - (\sum y)^2]}}$$
|
|
28
|
+
|
|
29
|
+
The model evaluating the highest Coefficient of Determination ($R^2$) closest to `1.0` is programmatically crowned as the predicted asymptotic complexity bound.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 📦 Installation
|
|
34
|
+
|
|
35
|
+
Ensure you have Python >= 3.8 installed, then fetch the package from the index:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install --index-url [https://test.pypi.org/simple/](https://test.pypi.org/simple/) --extra-index-url [https://pypi.org/simple/](https://pypi.org/simple/) dsa-profiler-rishad
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
🚀 Practical Guide & Usage
|
|
42
|
+
1. Comparative Solution Tracking
|
|
43
|
+
Track execution shifts across different iterations of an optimization cycle:
|
|
44
|
+
|
|
45
|
+
import time
|
|
46
|
+
from dsa_profiler import profile_dsa
|
|
47
|
+
|
|
48
|
+
@profile_dsa(problem_id="two-sum", run_name="brute-force", iteration=3)
|
|
49
|
+
def solve_via_brute():
|
|
50
|
+
time.sleep(0.1) # Simulate nested loop overhead
|
|
51
|
+
return "done"
|
|
52
|
+
|
|
53
|
+
@profile_dsa(problem_id="two-sum", run_name="hash-map-optimized", iteration=3)
|
|
54
|
+
def solve_via_map():
|
|
55
|
+
time.sleep(0.01) # Simulate high-speed lookup
|
|
56
|
+
return "done"
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
solve_via_brute()
|
|
60
|
+
solve_via_map()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
2. Algorithmic Big-O Estimation
|
|
64
|
+
Empirically isolate the asymptotic complexity profile of an approach over expanding dataset sizes:
|
|
65
|
+
|
|
66
|
+
import time
|
|
67
|
+
from dsa_profiler import profile_big_o
|
|
68
|
+
|
|
69
|
+
@profile_big_o(n_range=[100, 500, 1000, 2000])
|
|
70
|
+
def simulate_linear_growth(n):
|
|
71
|
+
for i in range(n):
|
|
72
|
+
pass
|
|
73
|
+
time.sleep(n * 0.00001)
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
simulate_linear_growth()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
🧱 Project Directory Layout
|
|
80
|
+
dsa_profiler/
|
|
81
|
+
│
|
|
82
|
+
├── src/
|
|
83
|
+
│ └── dsa_profiler/
|
|
84
|
+
│ ├── __init__.py # Clean package API exports
|
|
85
|
+
│ ├── core.py # Main execution interceptor decorators
|
|
86
|
+
│ ├── storage.py # SQLite data access persistence layer
|
|
87
|
+
│ ├── reporter.py # Analytics engine & UI generator
|
|
88
|
+
│ └── analyzer.py # Mathematical OLS regression engine
|
|
89
|
+
│
|
|
90
|
+
├── tests/
|
|
91
|
+
│ └── demo.py # Sandbox execution suite
|
|
92
|
+
│
|
|
93
|
+
├── pyproject.toml # Package distribution metadata configurations
|
|
94
|
+
└── README.md # Architecture documentation centerpiece
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
📄 License
|
|
98
|
+
This framework is open-source software licensed under the MIT License.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### What to do next:
|
|
103
|
+
1. Save this into `README.md`.
|
|
104
|
+
2. Follow our rebuild sequence to update the package version to `0.1.1` in `pyproject.toml` and compile it:
|
|
105
|
+
```cmd
|
|
106
|
+
rmdir /s /q dist
|
|
107
|
+
python -m build
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
Upload it to TestPyPI:
|
|
111
|
+
|
|
112
|
+
python -m twine upload --repository testpypi dist/*
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dsa-profiler-rishad"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "A local-first profiling tool to benchmark and compare DSA solution efficiency."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
"Topic :: Software Development :: Testing",
|
|
16
|
+
]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"rich>=13.0.0",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from typing import List, Tuple
|
|
3
|
+
|
|
4
|
+
class BigOAnalyzer:
|
|
5
|
+
@staticmethod
|
|
6
|
+
def estimate_complexity(data_points: List[Tuple[int, float]]) -> str:
|
|
7
|
+
|
|
8
|
+
if len(data_points) < 3:
|
|
9
|
+
return "Inconclusive (Need at least 3 data points)"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
models = {
|
|
13
|
+
"O(1)": lambda n, t: (1.0, t),
|
|
14
|
+
"O(log N)": lambda n, t: (math.log(n) if n > 1 else 0.0, t),
|
|
15
|
+
"O(N)": lambda n, t: (float(n), t),
|
|
16
|
+
"O(N log N)": lambda n, t: (n * math.log(n) if n > 1 else 0.0, t),
|
|
17
|
+
"O(N^2)": lambda n, t: (float(n ** 2), t)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
best_fit = "O(1)"
|
|
21
|
+
highest_r_squared = -1.0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
for complexity, transform in models.items():
|
|
25
|
+
try:
|
|
26
|
+
transformed_points = [transform(n, t) for n, t in data_points]
|
|
27
|
+
r_sq = BigOAnalyzer._calculate_r_squared(transformed_points)
|
|
28
|
+
|
|
29
|
+
if r_sq > highest_r_squared:
|
|
30
|
+
highest_r_squared = r_sq
|
|
31
|
+
best_fit = complexity
|
|
32
|
+
except (ValueError, ZeroDivisionError):
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
return best_fit
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def _calculate_r_squared(points: List[Tuple[float, float]]) -> float:
|
|
39
|
+
|
|
40
|
+
n = len(points)
|
|
41
|
+
sum_x = sum(p[0] for p in points)
|
|
42
|
+
sum_y = sum(p[1] for p in points)
|
|
43
|
+
sum_x_sq = sum(p[0]**2 for p in points)
|
|
44
|
+
sum_y_sq = sum(p[1]**2 for p in points)
|
|
45
|
+
sum_xy = sum(p[0] * p[1] for p in points)
|
|
46
|
+
|
|
47
|
+
numerator = (n * sum_xy) - (sum_x * sum_y)
|
|
48
|
+
denominator_x = (n * sum_x_sq) - (sum_x ** 2)
|
|
49
|
+
denominator_y = (n * sum_y_sq) - (sum_y ** 2)
|
|
50
|
+
|
|
51
|
+
if denominator_x == 0 or denominator_y == 0:
|
|
52
|
+
return 0.0
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
r = numerator / math.sqrt(denominator_x * denominator_y)
|
|
56
|
+
return r ** 2
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import time
|
|
3
|
+
import tracemalloc
|
|
4
|
+
from typing import Any,Callable,Dict,List
|
|
5
|
+
from dsa_profiler.storage import StorageEngine
|
|
6
|
+
from dsa_profiler.reporter import ConsoleReporter
|
|
7
|
+
from dsa_profiler.analyzer import BigOAnalyzer
|
|
8
|
+
|
|
9
|
+
storage=StorageEngine()
|
|
10
|
+
|
|
11
|
+
def profile_dsa(problem_id:str,run_name:str,iteration:int=5)->Callable:
|
|
12
|
+
|
|
13
|
+
def decorator(func:Callable[...,Any])->Callable[...,Any]:
|
|
14
|
+
@functools.wraps(func)
|
|
15
|
+
def wrapper(*args:Any,**kwargs:Any)->Any:
|
|
16
|
+
|
|
17
|
+
tracemalloc.start()
|
|
18
|
+
execution_times=[]
|
|
19
|
+
result=None
|
|
20
|
+
|
|
21
|
+
for i in range(iteration):
|
|
22
|
+
|
|
23
|
+
start_time=time.perf_counter()
|
|
24
|
+
if i==0:
|
|
25
|
+
result=func(*args,**kwargs)
|
|
26
|
+
else:
|
|
27
|
+
_=func(*args,**kwargs)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
end_time=time.perf_counter()
|
|
31
|
+
execution_times.append((end_time-start_time)*1000)
|
|
32
|
+
|
|
33
|
+
_,peak_bytes=tracemalloc.get_traced_memory()
|
|
34
|
+
tracemalloc.stop()
|
|
35
|
+
|
|
36
|
+
execution_times.sort()
|
|
37
|
+
median_time_ms=execution_times[len(execution_times)//2]
|
|
38
|
+
peak_memory_mb=peak_bytes/(1024*1024)
|
|
39
|
+
|
|
40
|
+
storage.save_run(problem_id,run_name,median_time_ms,peak_memory_mb)
|
|
41
|
+
|
|
42
|
+
historical_runs=storage.get_history(problem_id=problem_id)
|
|
43
|
+
|
|
44
|
+
current_run_payload = {
|
|
45
|
+
"run_name": run_name,
|
|
46
|
+
"execution_time_ms": median_time_ms,
|
|
47
|
+
"peak_memory_mb": peak_memory_mb
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
ConsoleReporter.generate_report(problem_id,current_run_payload,historical_runs)
|
|
51
|
+
|
|
52
|
+
return result
|
|
53
|
+
return wrapper
|
|
54
|
+
return decorator
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def profile_big_o(n_range: List[int]) -> Callable:
|
|
58
|
+
|
|
59
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
60
|
+
@functools.wraps(func)
|
|
61
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
62
|
+
from rich.console import Console
|
|
63
|
+
from rich.panel import Panel
|
|
64
|
+
console = Console()
|
|
65
|
+
|
|
66
|
+
data_points = []
|
|
67
|
+
result = None
|
|
68
|
+
|
|
69
|
+
console.print(f"\n[bold magenta][Big-O Analyzer][/bold magenta] Benchmarking [cyan]{func.__name__}[/cyan] over N = {n_range}...")
|
|
70
|
+
|
|
71
|
+
for n in n_range:
|
|
72
|
+
|
|
73
|
+
tracemalloc.start()
|
|
74
|
+
start_time = time.perf_counter()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
result = func(n, *args, **kwargs)
|
|
78
|
+
|
|
79
|
+
end_time = time.perf_counter()
|
|
80
|
+
_, peak_bytes = tracemalloc.get_traced_memory()
|
|
81
|
+
tracemalloc.stop()
|
|
82
|
+
|
|
83
|
+
time_ms = (end_time - start_time) * 1000
|
|
84
|
+
data_points.append((n, time_ms))
|
|
85
|
+
|
|
86
|
+
console.print(f" • N = {n:<7} | Time: {time_ms:.4f} ms | Peak Memory: {peak_bytes/(1024*1024):.4f} MB")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
estimated_complexity = BigOAnalyzer.estimate_complexity(data_points)
|
|
90
|
+
|
|
91
|
+
console.print(Panel(
|
|
92
|
+
f"Based on empirical growth trends, the estimated time complexity is:\n\n[bold green]🚀 {estimated_complexity}[/bold green]",
|
|
93
|
+
title="[bold magenta]Asymptotic Analysis Result[/bold magenta]",
|
|
94
|
+
border_style="magenta",
|
|
95
|
+
expand=False
|
|
96
|
+
))
|
|
97
|
+
|
|
98
|
+
return result
|
|
99
|
+
return wrapper
|
|
100
|
+
return decorator
|
|
101
|
+
|
|
102
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from typing import List, Dict, Any
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
from rich.table import Table
|
|
4
|
+
from rich.panel import Panel
|
|
5
|
+
|
|
6
|
+
console = Console()
|
|
7
|
+
|
|
8
|
+
class ConsoleReporter:
|
|
9
|
+
@staticmethod
|
|
10
|
+
def generate_report(problem_id: str, current_run: Dict[str, Any], history: List[Dict[str, Any]]) -> None:
|
|
11
|
+
"""Calculates performance deltas and displays a beautiful terminal analytics dashboard."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
table = Table(title=f"Performance Logs for: [bold cyan]{problem_id}[/bold cyan]", title_justify="left")
|
|
15
|
+
table.add_column("Run Name", style="bold white")
|
|
16
|
+
table.add_column("Execution Time", justify="right")
|
|
17
|
+
table.add_column("Peak Memory", justify="right")
|
|
18
|
+
table.add_column("Timestamp", style="dim", justify="center")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
for run in history:
|
|
22
|
+
|
|
23
|
+
if run['run_name'] == current_run['run_name'] and run['execution_time_ms'] == current_run['execution_time_ms']:
|
|
24
|
+
table.add_row(
|
|
25
|
+
f"[bold yellow]→ {run['run_name']}[/bold yellow]",
|
|
26
|
+
f"[bold yellow]{run['execution_time_ms']:.4f} ms[/bold yellow]",
|
|
27
|
+
f"[bold yellow]{run['peak_memory_mb']:.4f} MB[/bold yellow]",
|
|
28
|
+
run['timestamp']
|
|
29
|
+
)
|
|
30
|
+
else:
|
|
31
|
+
table.add_row(
|
|
32
|
+
run['run_name'],
|
|
33
|
+
f"{run['execution_time_ms']:.4f} ms",
|
|
34
|
+
f"{run['peak_memory_mb']:.4f} MB",
|
|
35
|
+
run['timestamp']
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
console.print("\n")
|
|
40
|
+
console.print(table)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if len(history) > 1:
|
|
44
|
+
prev_run = history[-2]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
time_delta = ((prev_run['execution_time_ms'] - current_run['execution_time_ms']) / prev_run['execution_time_ms']) * 100
|
|
48
|
+
mem_delta = ((prev_run['peak_memory_mb'] - current_run['peak_memory_mb']) / prev_run['peak_memory_mb']) * 100
|
|
49
|
+
|
|
50
|
+
if time_delta >= 0:
|
|
51
|
+
time_msg = f"[bold green]🔥 Speedup Success:[/bold green] Your new approach is [bold green]{time_delta:.1f}% FASTER[/bold green] than '{prev_run['run_name']}'!"
|
|
52
|
+
else:
|
|
53
|
+
time_msg = f"[bold red]⚠️ Performance Drop:[/bold red] Execution time slowed down by [bold red]{abs(time_delta):.1f}%[/bold red]."
|
|
54
|
+
|
|
55
|
+
if mem_delta >= 0:
|
|
56
|
+
mem_msg = f"[bold green]📉 Memory Optimization:[/bold green] Saved [bold green]{mem_delta:.1f}%[/bold green] more space."
|
|
57
|
+
else:
|
|
58
|
+
mem_msg = f"[bold yellow]⚠️ Memory Overhead:[/bold yellow] This approach consumed [bold yellow]{abs(mem_delta):.1f}% MORE[/bold yellow] RAM."
|
|
59
|
+
|
|
60
|
+
summary_panel = Panel(
|
|
61
|
+
f"{time_msg}\n{mem_msg}",
|
|
62
|
+
title="[bold gold1]Optimization Insights[/bold gold1]",
|
|
63
|
+
border_style="bright_blue",
|
|
64
|
+
expand=False
|
|
65
|
+
)
|
|
66
|
+
console.print(summary_panel)
|
|
67
|
+
else:
|
|
68
|
+
console.print(Panel("[bold green]✨ Baseline Recorded![/bold green]\nCreate an alternate solution setup to generate comparative analytics graphs.", title="Insights", expand=False))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sqlite3
|
|
3
|
+
from typing import Dict,List,Any
|
|
4
|
+
|
|
5
|
+
class StorageEngine:
|
|
6
|
+
def __init__(self,db_name:str=".dsa_profile_history.db"):
|
|
7
|
+
self.db_name=db_name
|
|
8
|
+
self._initialize_db()
|
|
9
|
+
|
|
10
|
+
def _get_connection(self)->sqlite3.Connection:
|
|
11
|
+
return sqlite3.connect(self.db_name)
|
|
12
|
+
|
|
13
|
+
def _initialize_db(self)->None:
|
|
14
|
+
schema="""
|
|
15
|
+
CREATE TABLE IF NOT EXISTS dsa_runs (
|
|
16
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
17
|
+
problem_id TEXT NOT NULL,
|
|
18
|
+
run_name TEXT NOT NULL,
|
|
19
|
+
execution_time_ms REAL NOT NULL,
|
|
20
|
+
peak_memory_mb REAL NOT NULL,
|
|
21
|
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
22
|
+
);
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
with self._get_connection() as conn:
|
|
26
|
+
cursor=conn.cursor()
|
|
27
|
+
cursor.execute(schema)
|
|
28
|
+
conn.commit()
|
|
29
|
+
|
|
30
|
+
def save_run(self,problem_id:str,run_name:str,time_ms:float,memory_mb:float)->None:
|
|
31
|
+
|
|
32
|
+
query="""
|
|
33
|
+
INSERT INTO dsa_runs (problem_id,run_name,execution_time_ms,peak_memory_mb) VALUES (?,?,?,?)
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
with self._get_connection() as conn:
|
|
37
|
+
cursor=conn.cursor()
|
|
38
|
+
cursor.execute(query,(problem_id,run_name,time_ms,memory_mb))
|
|
39
|
+
conn.commit()
|
|
40
|
+
|
|
41
|
+
def get_history(self,problem_id:str)->List[Dict[str,Any]]:
|
|
42
|
+
|
|
43
|
+
query="""
|
|
44
|
+
SELECT run_name,execution_time_ms,peak_memory_mb,timestamp FROM dsa_runs WHERE problem_id = ?
|
|
45
|
+
ORDER BY timestamp ASC;
|
|
46
|
+
"""
|
|
47
|
+
with self._get_connection() as conn:
|
|
48
|
+
conn.row_factory=sqlite3.Row
|
|
49
|
+
cursor=conn.cursor()
|
|
50
|
+
cursor.execute(query,(problem_id,))
|
|
51
|
+
|
|
52
|
+
rows=cursor.fetchall()
|
|
53
|
+
return [dict(row) for row in rows]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dsa-profiler-rishad
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A local-first profiling tool to benchmark and compare DSA solution efficiency.
|
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Classifier: Topic :: Software Development :: Testing
|
|
9
|
+
Requires-Python: >=3.8
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: rich>=13.0.0
|
|
12
|
+
|
|
13
|
+
# 📊 DSA Profiler (`dsa-profiler-rishad`)
|
|
14
|
+
|
|
15
|
+
A local-first, production-grade profiling framework engineered for developers and students to benchmark Data Structures and Algorithms (DSA) solutions. The tool captures high-precision runtime execution metrics, monitors dynamic peak memory allocation, tracks local performance history via an embedded relational database, and utilizes empirical statistical curve-fitting to programmatically predict algorithmic Big-O complexities.
|
|
16
|
+
|
|
17
|
+
## ✨ Core Engineering Features
|
|
18
|
+
|
|
19
|
+
- **⏱️ High-Precision Performance Benchmarking:** Bypasses standard wrapper latencies using hardware-level system counters (`time.perf_counter`). Utilizes customizable multi-iteration tracking and calculates **median execution runtimes** to systematically filter out background operating system process jitter.
|
|
20
|
+
- **🧠 Dynamic Peak Memory Tracking:** Integrates native virtual memory space tracking via `tracemalloc` to capture the exact maximum byte footprint utilized by an algorithm during execution.
|
|
21
|
+
- **💾 Persistent Local Data Storage Engine:** Built with a serverless relational `sqlite3` data layer. Automatically initializes and manages a hidden repository file (`.dsa_profile_history.db`) inside the execution workspace to preserve historical performance states across terminal runs.
|
|
22
|
+
- **📈 Automated Optimization Delta Engine:** Computes exact optimization shifts between successive approaches using structural percentage metrics. Generates beautiful, color-coded tabular comparisons (`rich`) displaying runtime shifts, memory gains, or regression warnings.
|
|
23
|
+
- **🚀 Empirical Asymptotic Analyzer:** Runs solutions over variable scaling input sizes ($N$) and implements a **Pure-Python Ordinary Least Squares (OLS) Linear Regression Engine**. Computes Pearson Correlation Coefficients ($R^2$) across distinct linearized transformation spaces to predict mathematical time complexities ($O(1)$, $O(\log N)$, $O(N)$, $O(N \log N)$, $O(N^2)$).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🛠️ System Architecture & Mathematical Foundations
|
|
28
|
+
|
|
29
|
+
### 1. The Optimization Delta Logic
|
|
30
|
+
When consecutive alternative approaches are registered under the same `problem_id`, the system isolates the immediately preceding run from the relational database to calculate the exact structural evolution metric:
|
|
31
|
+
|
|
32
|
+
$$\Delta \text{Time} = \left( \frac{\text{Time}_{\text{previous}} - \text{Time}_{\text{current}}}{\text{Time}_{\text{previous}}} \right) \times 100$$
|
|
33
|
+
|
|
34
|
+
A positive result signals a **Speedup Success** (color-coded green), whereas a negative result automatically trips a **Performance Drop** warning (color-coded red).
|
|
35
|
+
|
|
36
|
+
### 2. Empirical Big-O Curve Fitting
|
|
37
|
+
Instead of reading code text structures statically, the library profiles data points across a scaling range of $N$ and transforms input parameters to find linear relationships. The system manual regression uses the Pearson Correlation Coefficient ($R$) formula:
|
|
38
|
+
|
|
39
|
+
$$R = \frac{n\sum xy - (\sum x)(\sum y)}{\sqrt{[n\sum x^2 - (\sum x)^2][n\sum y^2 - (\sum y)^2]}}$$
|
|
40
|
+
|
|
41
|
+
The model evaluating the highest Coefficient of Determination ($R^2$) closest to `1.0` is programmatically crowned as the predicted asymptotic complexity bound.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 📦 Installation
|
|
46
|
+
|
|
47
|
+
Ensure you have Python >= 3.8 installed, then fetch the package from the index:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install --index-url [https://test.pypi.org/simple/](https://test.pypi.org/simple/) --extra-index-url [https://pypi.org/simple/](https://pypi.org/simple/) dsa-profiler-rishad
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
🚀 Practical Guide & Usage
|
|
54
|
+
1. Comparative Solution Tracking
|
|
55
|
+
Track execution shifts across different iterations of an optimization cycle:
|
|
56
|
+
|
|
57
|
+
import time
|
|
58
|
+
from dsa_profiler import profile_dsa
|
|
59
|
+
|
|
60
|
+
@profile_dsa(problem_id="two-sum", run_name="brute-force", iteration=3)
|
|
61
|
+
def solve_via_brute():
|
|
62
|
+
time.sleep(0.1) # Simulate nested loop overhead
|
|
63
|
+
return "done"
|
|
64
|
+
|
|
65
|
+
@profile_dsa(problem_id="two-sum", run_name="hash-map-optimized", iteration=3)
|
|
66
|
+
def solve_via_map():
|
|
67
|
+
time.sleep(0.01) # Simulate high-speed lookup
|
|
68
|
+
return "done"
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
solve_via_brute()
|
|
72
|
+
solve_via_map()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
2. Algorithmic Big-O Estimation
|
|
76
|
+
Empirically isolate the asymptotic complexity profile of an approach over expanding dataset sizes:
|
|
77
|
+
|
|
78
|
+
import time
|
|
79
|
+
from dsa_profiler import profile_big_o
|
|
80
|
+
|
|
81
|
+
@profile_big_o(n_range=[100, 500, 1000, 2000])
|
|
82
|
+
def simulate_linear_growth(n):
|
|
83
|
+
for i in range(n):
|
|
84
|
+
pass
|
|
85
|
+
time.sleep(n * 0.00001)
|
|
86
|
+
|
|
87
|
+
if __name__ == "__main__":
|
|
88
|
+
simulate_linear_growth()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
🧱 Project Directory Layout
|
|
92
|
+
dsa_profiler/
|
|
93
|
+
│
|
|
94
|
+
├── src/
|
|
95
|
+
│ └── dsa_profiler/
|
|
96
|
+
│ ├── __init__.py # Clean package API exports
|
|
97
|
+
│ ├── core.py # Main execution interceptor decorators
|
|
98
|
+
│ ├── storage.py # SQLite data access persistence layer
|
|
99
|
+
│ ├── reporter.py # Analytics engine & UI generator
|
|
100
|
+
│ └── analyzer.py # Mathematical OLS regression engine
|
|
101
|
+
│
|
|
102
|
+
├── tests/
|
|
103
|
+
│ └── demo.py # Sandbox execution suite
|
|
104
|
+
│
|
|
105
|
+
├── pyproject.toml # Package distribution metadata configurations
|
|
106
|
+
└── README.md # Architecture documentation centerpiece
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
📄 License
|
|
110
|
+
This framework is open-source software licensed under the MIT License.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### What to do next:
|
|
115
|
+
1. Save this into `README.md`.
|
|
116
|
+
2. Follow our rebuild sequence to update the package version to `0.1.1` in `pyproject.toml` and compile it:
|
|
117
|
+
```cmd
|
|
118
|
+
rmdir /s /q dist
|
|
119
|
+
python -m build
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
Upload it to TestPyPI:
|
|
123
|
+
|
|
124
|
+
python -m twine upload --repository testpypi dist/*
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/dsa_profiler/__init__.py
|
|
4
|
+
src/dsa_profiler/analyzer.py
|
|
5
|
+
src/dsa_profiler/core.py
|
|
6
|
+
src/dsa_profiler/reporter.py
|
|
7
|
+
src/dsa_profiler/storage.py
|
|
8
|
+
src/dsa_profiler_rishad.egg-info/PKG-INFO
|
|
9
|
+
src/dsa_profiler_rishad.egg-info/SOURCES.txt
|
|
10
|
+
src/dsa_profiler_rishad.egg-info/dependency_links.txt
|
|
11
|
+
src/dsa_profiler_rishad.egg-info/requires.txt
|
|
12
|
+
src/dsa_profiler_rishad.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rich>=13.0.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dsa_profiler
|