Skip to content

Conversation

@tafk7
Copy link

@tafk7 tafk7 commented Nov 6, 2025

Replaces FINN's fragmented subprocess management with unified Python logging. All Xilinx tool invocations (Vivado, Vitis, HLS, xsim, g++) now use direct subprocess calls with structured logging, eliminating bash script wrappers and stdout redirection.

Problems solved:

  • Lost subprocess output (warnings/errors captured but discarded)
  • No granular verbosity control (single verbose flag for everything)
  • Limited library integration (couldn't suppress console output)
  • Bash script overhead and inconsistent logging patterns

Key Changes

1. Centralized Subprocess Execution

New launch_process_helper() in src/finn/util/basic.py provides:

  • Thread-safe non-blocking I/O capture
  • Environment variable expansion ($FINN_ROOT)
  • Pattern-based log level detection (ERROR:, WARNING:)
  • Flexible error handling

All 10+ subprocess invocation sites now use this unified interface.

2. Hierarchical Logger Design

finn.builder.*     → Build progress (independent)
finn.*             → Tool output (vivado, hls, vitis, gcc, xsim)

Both hierarchies write to file; console output independently controlled.

3. Multi-Level Verbosity Control

New config fields:

show_progress: bool = True              # Builder progress messages
subprocess_log_levels: dict = None      # Per-tool file log levels
subprocess_console_levels: dict = None  # Per-tool console levels (when verbose=True)

Operation modes:

verbose show_progress Console Use Case
False False Silent Library/batch
False True Progress only Default
True True Everything Debug

Example - filter Vivado spam:

cfg = DataflowBuildConfig(
    verbose=True,
    subprocess_console_levels={'vivado': 'WARNING', 'hls': 'ERROR'},
    subprocess_log_levels={'vivado': 'DEBUG', 'hls': 'DEBUG'},
)

Defaults: console ERROR, file DEBUG when not specified.

4. Code Simplification

Before:

# Generate bash wrapper
make_project_sh = proj_dir + "/make_project.sh"
with open(make_project_sh, "w") as f:
    f.write("#!/bin/bash\ncd {}\nvivado -mode batch -source make_project.tcl\n".format(proj_dir))
subprocess.Popen(["bash", make_project_sh], stdout=subprocess.PIPE).communicate()

After:

launch_process_helper(
    ["vivado", "-mode", "batch", "-source", "make_project.tcl"],
    cwd=proj_dir,
    logger=logging.getLogger("finn.vivado.stitch_ip"),
)

Removed:

  • StreamToLogger class (stdout redirection)
  • use_logging parameter (always enabled)
  • Bash script generation throughout codebase
  • ~135 lines dead code

File Changes

Core Implementation:

  • src/finn/util/basic.py (+257/-22) - launch_process_helper(), CppBuilder refactor
  • src/finn/builder/build_dataflow.py (+91/-38) - Logger configuration, removed stdout redirection
  • src/finn/builder/build_dataflow_config.py (+15) - New config fields

Subprocess Call Sites (8 files):

  • src/finn/util/hls.py, src/finn/util/vivado.py, src/finn/core/rtlsim_exec.py
  • src/finn/transformation/fpgadataflow/*.py - IP generation, Zynq synthesis, Vitis build

Tests:

  • tests/util/test_launch_process_helper.py (+266) - 26 unit tests

Benefits

  1. Complete subprocess coverage - all tool output captured
  2. Fine-grained control - per-tool log levels (file + console)
  3. Library-friendly - silent mode for external applications
  4. Cleaner codebase - no bash wrappers, no stdout redirection
  5. Better debugging - structured logs with logger names and timestamps

Backward Compatibility

Breaking:

  • verbose=False now silent (was progress visible). Migration: use show_progress=True, verbose=False (new default)
  • Log format: [timestamp] [logger] level: message (was [timestamp] message)

Non-breaking:

  • verbose=True unchanged
  • All existing builds work without modification
  • File logging more comprehensive (captures previously lost output)

Testing

Unit Tests (34 total):

  • test_launch_process_helper.py (26 tests) - Subprocess execution, streaming, log level detection, environment handling
  • test_logging_config.py (8 tests) - Configuration behavior verification:
    • show_progress flag controls progress console output
    • verbose flag controls subprocess console output
    • subprocess_log_levels filters file logging per tool
    • subprocess_console_levels filters console output per tool (when verbose=True)
    • JSON serialization of new config fields
    • Backwards compatibility with old verbose-only configs
    • Fixed bug: Logger level calculation now respects verbose flag (prevents console_level from affecting file logging when console is disabled)

Integration:

  • Existing end-to-end tests validate backward compatibility (bnn sanity)

tafk7 added 7 commits November 6, 2025 00:56
  Enable users to control Xilinx tool output verbosity (Vivado, xsim, HLS)
  through Python logging instead of accepting all console spam.

  Implementation:
  - Enhanced launch_process_helper() with dual-mode operation (legacy/logging)
  - Added pattern-based log level detection for Xilinx tool output
  - Migrated internal call sites to use logging mode (vivado.py, rtlsim_exec.py)
  - Added comprehensive unit tests (26 tests, all passing)

  Usage:
    logging.getLogger('finn.vivado').setLevel(logging.ERROR)  # Suppress spam

  Backward compatible (opt-in design, legacy mode default).
- Configure finn logger hierarchy to respect verbose flag in build_dataflow
- Rename rtlsim subprocess loggers to finn.gcc and finn.xsim for clarity
- Enable console output in verbose mode, warnings-only in quiet mode
- Remove StreamToLogger class and stream redirection logic from build_dataflow.py
- Replace all print() calls with logger.info/warning/error in builder and steps
- Remove no_stdout_redirect config option as it's no longer needed
- Add logger instances to make_driver transformation
- Remove debug print statement from vivado.py resource parsing

Build output now uses Python logging throughout instead of redirecting
stdout/stderr streams, enabling better integration with terminal-aware
libraries and structured logging.
Replace intermediate .sh script generation with direct process invocation
using launch_process_helper for Vivado, Vitis, HLS, and g++ workflows.
Update build_dataflow.py verbose mode to prevent log duplication.
Add environment variable expansion in launch_process_helper for consistency
with shell behavior. Add glob pattern support in CppBuilder for *.cpp files.
Makes logging mode the default behavior by removing the use_logging flag and legacy tuple return mode. All callers now use the unified logging interface with integer exit codes.
…ontrol

Separate finn.builder logger hierarchy from tool loggers to enable
independent control of progress messages vs tool output. Add show_progress
config field (default True) to control builder console output while
verbose flag controls tool logger console output.

Changes:
- Add show_progress field to DataflowBuildConfig (default True)
- Configure finn.builder with independent console/file handlers
- Configure finn.builder.propagate=False to prevent cross-hierarchy leakage
- Set finn tool loggers to always propagate to file regardless of verbose
- Update root logger format to include logger name and level for audit trail
- Console formats: builder uses clean format, tools use bracketed format

Behavior matrix:
- show_progress=True, verbose=False: progress on console, tools to file (default)
- show_progress=False, verbose=False: completely silent console (library mode)
- show_progress=True, verbose=True: all output on console (debug mode)
@tafk7 tafk7 changed the title Python Logging Integration for Subprocess Execution Unified Logging Integration for FINN Build Pipeline Nov 6, 2025
tafk7 added 2 commits November 6, 2025 15:04
Adds subprocess_log_levels parameter to DataflowBuildConfig allowing library
users to customize log levels for specific tool categories (e.g., hls, vivado).
Build flow now applies these overrides after logger initialization.
Splits subprocess_log_levels into two independent configs:
- subprocess_console_levels: controls console output (when verbose=True)
- subprocess_log_levels: controls file logging (always active)

Console output defaults to WARNING, file logging defaults to DEBUG.
Each subprocess logger gets its own console handler to prevent
duplication. Parent finn logger excludes configured children via filter.
@tafk7 tafk7 changed the title Unified Logging Integration for FINN Build Pipeline Python Logging Integration for FINN Build Flow Nov 6, 2025
@tafk7 tafk7 marked this pull request as ready for review November 7, 2025 01:17
tafk7 and others added 18 commits November 6, 2025 17:17
- Standardize logger naming hierarchy (finn.compile.*, finn.vivado.*, finn.vitis.*)
- Add generate_script parameter to launch_process_helper for automatic debug script creation
- Implement _generate_shell_script to produce standalone executable scripts with proper quoting and environment capture
- Modify _detect_log_level to strip redundant level prefixes from messages
- Simplify rtlsim_exec by delegating script generation to launch_process_helper
- Remove manual shell script creation in favor of automated generation
- Add comprehensive test coverage for script generation and message cleaning
- Reorder step_hw_codegen to run PrepareIP before prepare_loop_ops_fifo_sizing
  so loop body nodes have correct initializer data during code generation
- Add mlo_input_type metadata to FINNLoop input tensors for FIFO sizing
- Generate unique FIFO names in InsertFIFO to prevent collisions
- Skip standard ONNX nodes in FINNLoop cycle estimation
- Use get_output_datatype() instead of direct nodeattr access for Thresholding
- Preserve node names in SpecializeLayers and GiveUniqueNodeNames
- Use real parameter data in FIFO depth setting when available
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant