5. Contributing
This section provides guidelines for developers to extend the MemSysExplorer framework by adding custom profilers into the profiling pipeline. The core components required for extension include:
FrontendInterface Abstract Class: Acts as the execution core responsible for activating and managing profilers.
PatternConfig Abstract Class: Serves as a configuration bridge between raw profiler data and downstream modeling utilities.
BaseMetadata Interface (optional): Defines how system-level and runtime metadata should be captured during profiling.
All profiler modules, pattern configurations, and metadata handlers should reside in their respective subdirectories under profilers/ to ensure consistency and maintainability.
4.1 Adding Custom Profilers
To add a new profiler, developers should subclass:
FrontendInterface (for profiling behavior)
PatternConfig (for visualization or modeling utilities)
Optionally, BaseMetadata (to add system/hardware context)
Then, register your new components through the centralized registry system described below.
4.2 Dynamic Profiler Registration
Starting with v1.1, MemSysExplorer uses a JSON-driven dynamic loader to register supported profilers. The file built_profilers.json controls which components are active.
Example `built_profilers.json`:
{
"ncu": true,
"perf": true,
"nvbit": true,
"dynamorio": false,
"sniper": true
}
Only profilers with a true flag will be registered dynamically at runtime.
Unified Profiler Registry:
Starting with v1.2, all module and class registration is controlled via a central dictionary:
PROFILER_REGISTRY = {
"ncu": {
"profiler": ("profilers.ncu.ncu_profilers", "NsightComputeProfilers"),
"config": ("profilers.ncu.ncu_PatternConfig", "NsightComputeConfig"),
"metadata": ("profilers.ncu.ncu_Metadata", "NsightMetadata")
},
"perf": {
"profiler": ("profilers.perf.perf_profilers", "PerfProfilers"),
"config": ("profilers.perf.perf_PatternConfig", "PerfConfig"),
"metadata": ("profilers.perf.perf_Metadata", "PerfMetadata")
},
...
}
This centralized mapping allows for concise and scalable extension by defining all module-class paths in one place.
Dynamic Registration Workflow:
def register_profilers():
for profiler, entries in PROFILER_REGISTRY.items():
if built_profilers.get(profiler, False):
module_name, class_name = entries["profiler"]
module = importlib.import_module(module_name)
profiler_class = getattr(module, class_name)
FrontendInterface.register_profiler(profiler, profiler_class)
def register_PatternConfig():
for profiler, entries in PROFILER_REGISTRY.items():
if built_profilers.get(profiler, False):
module_name, class_name = entries["config"]
config_class = getattr(importlib.import_module(module_name), class_name)
PatternConfig.register_config(profiler, config_class)
def register_MetadataClasses():
for profiler, entries in PROFILER_REGISTRY.items():
if built_profilers.get(profiler, False):
module_name, class_name = entries["metadata"]
metadata_class = getattr(importlib.import_module(module_name), class_name)
FrontendInterface.register_metadata(profiler, metadata_class)
This architecture allows developers to enable or disable profiler components without modifying source logic beyond the registry dictionary.
4.3 Directory Structure
Profiler components should follow the modular structure below:
profilers/
├── FrontendInterface.py
├── PatternConfig.py
├── BaseMetadata.py
├── registry.py
├── built_profilers.json
├── ncu/
│ ├── ncu_profilers.py
│ ├── ncu_PatternConfig.py
│ ├── ncu_Metadata.py
├── nvbit/
│ ├── nvbit_profilers.py
│ ├── nvbit_PatternConfig.py
│ ├── nvbit_Metadata.py
├── perf/
│ ├── perf_profilers.py
│ ├── perf_PatternConfig.py
│ ├── perf_Metadata.py
...
Each profiler module should include:
*_profilers.py – Defines the FrontendInterface subclass.
*_PatternConfig.py – Defines the pattern modeling behavior.
*_Metadata.py – Extracts runtime system information.
4.4 Best Practices for Development
Directory Isolation: Keep each profiler’s implementation self-contained within its subdirectory.
Fail Gracefully: Ensure each module handles FileNotFoundError, PermissionError, or unsupported environments cleanly.
Avoid Hardcoding Paths: Use os.path to determine paths dynamically from the script location.
Test Incrementally: Run profiling and extraction in isolation before integrating.
Update the Registry: Add your profiler to PROFILER_REGISTRY in registry.py to integrate with the dynamic loader.
4.5 Further Reading
For a step-by-step guide to implementing your own FrontendInterface, visit:
Developer Tutorials
By following this registry-based structure, you ensure a clean separation of concerns, reduce boilerplate, and streamline extensibility for future memory technologies.