Skip to content

Commit 362033f

Browse files
authored
Refactor Logging for Improved Debugging (#115)
This pull request introduces several improvements and refactors across the codebase, focusing on enhanced logging, memory tracking, type checking, and developer usability. The most significant changes include replacing print statements with structured logging, adding detailed memory usage tracking for buffers, improving type and level checking for data types, and providing more informative string representations and debugging messages for core classes. All runners and the generation scripts support different verbosity levels: - `-v`: Show errors, warning and info messages - `-vv`: Show errors, warnings, info and debug messages - `-vvv`: Maximum verbosity with information about where the message was emitted. Also enable verbose compilation during the build step for the test runners. ## Added - Logging and Error Handling Improvements: Replaced all `print` statements with structured logging using `DEFAULT_LOGGER` throughout the codebase, improving consistency and enabling better log management. - Added debug-level logs to type checking and parsing routines to indicate success/failure and binding exhaustion, aiding troubleshooting. - Implemented `__repr__` methods for core classes (`NodeTemplate`, `NodeBinding`, `NodeMapper`) to provide more informative string representations for debugging and logging - Added `checkNumLevels` methods to relevant data type classes to validate that the number of levels assigned to buffers is supported by their type, and integrated warning logs if mismatches are detected during type inference. - Introduced a `sizeInBytes` method to `VariableBuffer`, `TransientBuffer`, and related classes to standardize buffer size calculation. - Report the maximum static and dynamic memory usage for all memory level: - Added dynamic and maximum memory usage tracking to `NetworkContext` via `_dynamicSize` and `_maxDynamicSize` dictionaries, and updated memory allocation/deallocation logic in `MemoryAllocation.py` to maintain these statistics per memory level. (This is only used for untitled platforms to track the maximum buffer size.) - Exposed new summary methods (`_printMemorySummary`, `_printInputOutputSummary`) in deployer wrappers and implemented input/output summary logging in `SignPropDeployer`. ## Changed - Deployer workflow now uses `prepare(...)` instead of `generateFunction(...)`.
1 parent 2fa3c31 commit 362033f

File tree

27 files changed

+588
-232
lines changed

27 files changed

+588
-232
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This file contains the changelog for the Deeploy project. The changelog is divid
44
## Unreleased (Planned Release Target: v0.2.1)
55

66
### List of Pull Requests
7+
- Refactor Logging for Improved Debugging [#115](https://github.com/pulp-platform/Deeploy/pull/115)
78
- Add reuse-tool as an SPDX license header linter [#113](https://github.com/pulp-platform/Deeploy/pull/113)
89
- Bug fixes, API Cleanup and Reduce Compiler Warning on PULP [#112](https://github.com/pulp-platform/Deeploy/pull/112)
910
- Fix PULP GEMM `batch` serialization [#109](https://github.com/pulp-platform/Deeploy/pull/109)
@@ -39,6 +40,11 @@ This file contains the changelog for the Deeploy project. The changelog is divid
3940
- Reshape operator support for PULP (`ReshapeTemplate` in bindings)
4041
- Missing class attributes in `Closure.py`
4142
- reuse_skip_wrapper.py to manually skip files
43+
- Centralized logging with `DEFAULT_LOGGER`, replacing `print` statements
44+
- Debug logs for type checking/parsing; `__repr__` for core classes
45+
- Buffer utilities: `checkNumLevels` validation and `sizeInBytes` method
46+
- Per–memory-level usage tracking and worst-case reporting in `NetworkContext`
47+
- Memory/I/O summaries and input/output logging in deployers
4248

4349
### Changed
4450
- Replaced platform-specific tags (`*-amd64`, `*-arm64`) with direct digest references in `Noelware/docker-manifest-action`.
@@ -65,6 +71,7 @@ This file contains the changelog for the Deeploy project. The changelog is divid
6571
- Removed unnecessary includes from the PULP platform header list, such as `DeeployBasicMath.h`, for cleaner code generation
6672
- Changed types and added correct casts to fix many compiler warnings in the PULP target library
6773
- Use [reuse-tool](https://github.com/fsfe/reuse-tool) in pre-commit, CI, and Makefile for SPDX license header linting
74+
- Deployer workflow now uses `prepare(...)` instead of `generateFunction(...)`.
6875

6976
### Fixed
7077
- Prevent node duplication for graphs generated via GraphSurgeon

Deeploy/AbstractDataTypes.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
_DeeployType = TypeVar("_DeeployType", _PointerType, _ImmediateType, _StructType)
2222
_PythonType = TypeVar("_PythonType", str, int, float, Dict[str, "_PythonType"], Iterable["_PythonType"])
2323

24+
from Deeploy.Logging import DEFAULT_LOGGER as log
25+
2426

2527
class _ClassPropertyDescriptor(object):
2628

@@ -188,6 +190,10 @@ def typeMin(cls) -> int:
188190
else:
189191
return 0
190192

193+
@_classproperty
194+
def nLevels(cls) -> int:
195+
return cls.typeMax - cls.typeMin + 1
196+
191197
@classmethod
192198
def partialOrderUpcast(cls, otherCls: Type[Immediate]) -> bool:
193199
if issubclass(otherCls, IntegerImmediate):
@@ -213,6 +219,10 @@ def checkValue(cls, value: Union[int, Iterable[int], np.ndarray], ctxt: Optional
213219
return False
214220
return True
215221

222+
@classmethod
223+
def fitsNumLevels(cls, nLevels: int) -> bool:
224+
return nLevels <= cls.nLevels
225+
216226

217227
class FloatImmediate(Immediate[Union[float, Iterable[float]], _ImmediateType]):
218228
typeMantissa: int #: int: Represents the number of bits reserved for the mantissa part
@@ -308,7 +318,7 @@ def checkValue(cls, value: Optional[str], ctxt: Optional[_NetworkContext] = None
308318
return False
309319

310320
if value is None or value == "NULL":
311-
print("WARNING: Setting pointer value to NULL - Referenced data is invalid!")
321+
log.warning("Setting pointer value to NULL - Referenced data is invalid!")
312322
return True
313323

314324
reference = ctxt.lookup(value)
@@ -332,6 +342,10 @@ def checkPromotion(cls, _value: Union[Optional[str], Pointer], ctxt: Optional[_N
332342
value = _value
333343
return cls.checkValue(value, ctxt)
334344

345+
@classmethod
346+
def fitsNumLevels(cls, nLevels: int) -> bool:
347+
return cls.referencedType.fitsNumLevels(nLevels)
348+
335349
def __init__(self, _value: Union[Optional[str], Pointer], ctxt: Optional[_NetworkContext] = None):
336350
"""Initializes a pointer to a registered object in the NetworkContext
337351

Deeploy/CommonExtensions/CodeTransformationPasses/MemoryAllocation.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,31 @@ def apply(self,
122122
for buffer in reversed(self.topologicallySortBuffers(outputs + transients)):
123123
assert buffer._live == False, f"Tried to allocate already live buffer {buffer.name}"
124124
buffer._live = True
125+
126+
memoryLevel = "None" if not hasattr(buffer, "_memoryLevel") else buffer._memoryLevel
127+
if memoryLevel not in ctxt._dynamicSize:
128+
ctxt._dynamicSize[memoryLevel] = int(buffer.sizeInBytes())
129+
else:
130+
ctxt._dynamicSize[memoryLevel] += int(buffer.sizeInBytes())
131+
125132
executionBlock.addLeft(buffer.allocTemplate, buffer._bufferRepresentation())
126133

134+
for levels in ctxt._dynamicSize.keys():
135+
if levels not in ctxt._maxDynamicSize:
136+
ctxt._maxDynamicSize[levels] = max(0, ctxt._dynamicSize[levels])
137+
else:
138+
ctxt._maxDynamicSize[levels] = max(ctxt._maxDynamicSize.get(levels, 0), ctxt._dynamicSize[levels])
139+
127140
for buffer in inputs + transients:
128141
assert buffer._live == True, f"Tried to deallocate already dead buffer {buffer.name}"
129142
buffer._live = False
130143
# Don't deallocate if it's an alias of a live buffer
131144
if not buffer.has_live_ancestors(ctxt = ctxt):
145+
memoryLevel = "None" if not hasattr(buffer, "_memoryLevel") else buffer._memoryLevel
146+
if memoryLevel not in ctxt._dynamicSize:
147+
ctxt._dynamicSize[memoryLevel] = 0
148+
else:
149+
ctxt._dynamicSize[memoryLevel] -= int(buffer.sizeInBytes())
132150
executionBlock.addRight(buffer.deallocTemplate, buffer._bufferRepresentation())
133151

134152
return ctxt, executionBlock
@@ -157,10 +175,30 @@ def apply(self,
157175

158176
for buffer in outputs + transients:
159177
assert buffer._live == False, f"Tried to allocate already live buffer {buffer.name}"
178+
179+
memoryLevel = "None" if not hasattr(buffer, "_memoryLevel") else buffer._memoryLevel
180+
if memoryLevel not in ctxt._dynamicSize:
181+
ctxt._dynamicSize[memoryLevel] = int(buffer.sizeInBytes())
182+
else:
183+
ctxt._dynamicSize[memoryLevel] += int(buffer.sizeInBytes())
184+
160185
buffer._live = True
161186

187+
for levels in ctxt._dynamicSize.keys():
188+
if levels not in ctxt._maxDynamicSize:
189+
ctxt._maxDynamicSize[levels] = max(0, ctxt._dynamicSize[levels])
190+
else:
191+
ctxt._maxDynamicSize[levels] = max(ctxt._maxDynamicSize.get(levels, 0), ctxt._dynamicSize[levels])
192+
162193
for buffer in inputs + transients:
163194
assert buffer._live == True, f"Tried to deallocate already dead buffer {buffer.name}"
195+
196+
memoryLevel = "None" if not hasattr(buffer, "_memoryLevel") else buffer._memoryLevel
197+
if memoryLevel not in ctxt._dynamicSize:
198+
ctxt._dynamicSize[memoryLevel] = 0
199+
else:
200+
ctxt._dynamicSize[memoryLevel] -= int(buffer.sizeInBytes())
201+
164202
buffer._live = False
165203

166204
return ctxt, executionBlock

Deeploy/CommonExtensions/NetworkDeployers/NetworkDeployerWrapper.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,9 @@ def generateBufferAllocationCode(self) -> str:
7575
# MultiEngineDeployer augment
7676
def _mapNode(self, node: gs.Node) -> Union[ONNXLayer, Any]:
7777
return self._innerObject._mapNode(node)
78+
79+
def _printMemorySummary(self):
80+
return self._innerObject._printMemorySummary()
81+
82+
def _printInputOutputSummary(self):
83+
return self._innerObject._printInputOutputSummary()

Deeploy/CommonExtensions/NetworkDeployers/SignPropDeployer.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from Deeploy.AbstractDataTypes import Pointer
1010
from Deeploy.DeeployTypes import DeploymentPlatform, NetworkDeployer, TopologyOptimizer
11+
from Deeploy.Logging import DEFAULT_LOGGER as log
1112

1213

1314
class SignPropDeployer(NetworkDeployer):
@@ -41,3 +42,16 @@ def _createIOBindings(self, ctxt, graph):
4142
nb.nLevels = (2**data_type.referencedType.typeWidth)
4243

4344
return ctxt
45+
46+
def _printInputOutputSummary(self):
47+
log.info('Input:')
48+
for buf in self.inputs():
49+
log.info(
50+
f" - '{buf.name}': Type: {buf._type.referencedType.typeName}, nLevels: {buf.nLevels}, Signed: {buf._signed}, Offset: {self.inputOffsets[buf.name]}"
51+
)
52+
53+
log.info('Output:')
54+
for buf in self.outputs():
55+
log.info(
56+
f" - '{buf.name}': Type: {buf._type.referencedType.typeName}, nLevels: {buf.nLevels}, Signed: {buf._signed}"
57+
)

Deeploy/CommonExtensions/OptimizationPasses/PassClasses.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import onnx_graphsurgeon as gs
88

99
from Deeploy.DeeployTypes import NetworkContext
10+
from Deeploy.Logging import DEFAULT_LOGGER as log
1011

1112
from .Matchers import Match, NonBranchingMatcher, SubgraphMatcher
1213

@@ -129,7 +130,7 @@ def remove_subpass(self, name):
129130
try:
130131
del self._subpasses[name]
131132
except KeyError:
132-
print(f"No subpass with name {name}, cannot remove!")
133+
log.error(f"No subpass with name {name}, cannot remove!")
133134
except AttributeError:
134135
raise AttributeError("Cannot remove sub-pass before calling Pass.__init__!")
135136

Deeploy/CommonExtensions/TypeCheckers/SignPropTypeChecker.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
import onnx_graphsurgeon as gs
88

9+
from Deeploy.AbstractDataTypes import IntegerImmediate
910
from Deeploy.DeeployTypes import ConstantBuffer, NetworkContext, NodeTypeChecker, OperatorRepresentation, VariableBuffer
11+
from Deeploy.Logging import DEFAULT_LOGGER as log
1012

1113

1214
class SignPropTypeChecker(NodeTypeChecker):
@@ -46,8 +48,15 @@ def typeInferOutput(self, ctxt: NetworkContext, node: gs.Node,
4648
nLevels = self._inferNumLevels(inputs, operatorRepresentation)
4749
signedness = self._inferSignedness(inputs, operatorRepresentation)
4850

49-
for obj, nLevels, sign in zip(outputs, nLevels, signedness):
50-
obj.nLevels = nLevels
51+
if nLevels is None or signedness is None:
52+
return ctxt
53+
for obj, nLevel, sign in zip(outputs, nLevels, signedness):
54+
obj.nLevels = nLevel
5155
obj._signed = sign
5256

57+
if issubclass(obj._type.referencedType, IntegerImmediate) and not obj._type.fitsNumLevels(nLevel):
58+
log.warning(
59+
f"{obj.name} has {nLevel} levels, but {obj._type.referencedType.typeName} only supports {obj._type.referencedType.nLevels} levels."
60+
)
61+
5362
return ctxt

0 commit comments

Comments
 (0)