Skip to content

fix: enable unbuffered Python output in Docker#10

Open
mkhnsn wants to merge 32 commits intomrv777:mainfrom
mkhnsn:fix/unbuffered-python-output
Open

fix: enable unbuffered Python output in Docker#10
mkhnsn wants to merge 32 commits intomrv777:mainfrom
mkhnsn:fix/unbuffered-python-output

Conversation

@mkhnsn
Copy link

@mkhnsn mkhnsn commented Feb 5, 2026

Summary

  • Adds ENV PYTHONUNBUFFERED=1 to the Dockerfile so container logs appear in real-time
  • Without this, Python fully buffers stdout when not connected to a TTY, causing docker logs -f to show nothing until the container exits

Depends on

Test plan

  • Build the Docker image and run the container
  • Verify docker logs -f <container> shows output in real-time during benchmarking

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added "--set-values" apply-only mode and richer CLI controls (IP, max-temp, output-dir).
    • Expanded output metrics: hashrate standard deviation, average power, and average fan speed.
    • Results files now include timestamped filenames and selectable output directory.
  • Bug Fixes / Reliability

    • Improved runtime stability and safer benchmarking with restart/retry handling and better stabilization checks.
  • Documentation

    • Major README overhaul with detailed CLI, Docker, configuration, and usage examples.
  • Chores

    • Docker: streaming logs enabled and default /results directory exposed as a volume.

Co1nB3e and others added 30 commits June 17, 2025 19:52
Couple of changes:
- color not working in windows terminal
- suffix in filename in case of voltage/frequency argument
- limited (1 successive) retries in case of overheat (previously any chip overheat reached ended the benchmark)
Couple of changes:
- color not working in windows terminal
- timestamp in filename
- suffix in filename in case of voltage/frequency argument
- filename computation refactored (called twice)
- limited (1 successive) retries in case of overheat (previously any chip overheat reached ended the benchmark)
…solve API mapping and initial state issues

This commit introduces significant enhancements to the Bitaxe Hashrate Benchmark script, focusing on collecting more comprehensive performance data and resolving key issues related to API data retrieval and script robustness.

**Key Features Added:**

* **Average Power Consumption (Watts):** The benchmark now calculates and includes the average power consumption for each voltage/frequency combination in the final JSON results and the terminal summary. This provides a direct metric for power efficiency analysis.
* **Average Fan Speed (RPM/Percentage):** Fan speed data is now fetched and averaged for each tested configuration, then included in the final JSON results and terminal summary. This allows for better assessment of cooling performance and noise levels alongside hashing performance.
* **Real-time Power and Fan Speed Display:** The live terminal output during benchmarking now includes the current power consumption and fan speed for each individual sample, enabling immediate monitoring of these critical metrics.

**Major Fixes and Improvements:**

* **Resolved `asic_count` API Mapping:** The script previously defaulted `asic_count` to 0 because the Bitaxe's `/api/system/info` endpoint does not expose this key. `asic_count` is now hardcoded to 1 in the configuration, ensuring the "Expected Hashrate" calculation is accurate for Bitaxe Gamma 601 (BM1370) models.
* **Corrected Fan Speed API Key:** The script's attempt to fetch "fanSpeed" from the API has been corrected to use "fanspeed" (for percentage) or "fanrpm" (for RPM), based on direct API response analysis. This ensures fan speed data is correctly retrieved.
* **Improved `benchmark_iteration` Return Consistency:** The `benchmark_iteration` function's return signature has been standardized to consistently return 8 values (including `average_power`, `average_fan_speed`, and `error_reason`), ensuring proper unpacking in the main loop. All early exit paths within this function now return a consistent tuple length.
* **Enhanced Script Robustness (Addressing NameError and `results` contradiction):**
    * Variables like `error_reason`, `avg_power`, `avg_fan_speed`, etc., are now correctly managed and passed throughout the main execution flow.
    * Although the previous `NameError` was challenging to pinpoint without a full traceback, the current implementation addresses potential scope ambiguities and ensures the `results` list is correctly populated and handled even during unexpected exits. This should prevent the "results list is empty" contradiction seen previously.
* **Faster Testing Configuration (Optional):** The default `benchmark_time` was adjusted to 120 seconds (2 minutes) and `frequency_increment` adjusted to 25 MHz for quicker test runs during development. (These can be reverted to original for more exhaustive testing).

These changes collectively make the benchmark tool more accurate, informative, and resilient to common API data inconsistencies, providing a richer dataset for Bitaxe optimization.#
This commit introduces a new command-line option to directly set the core voltage and frequency on the Bitaxe miner, bypassing the full benchmarking process.

**Motivation:**
Previously, applying specific desired settings required either temporarily modifying the script or running a full benchmark starting at those settings. This new functionality provides a quick, convenient, and direct way to configure the miner to a known good state or a specific operating point without needing to run an entire benchmark cycle. This is particularly useful for fine-tuning after initial benchmarks, or for quickly re-applying optimal settings.

**Implementation:**
A new command-line flag, -sor--set-values, has been added using argparse. When this flag is detected, the script will:
1.  Parse the provided core voltage (-v) and frequency (-f) as the target settings.
2.  Call the existing set_system_settings() function to apply these parameters to the Bitaxe.
3.  Print confirmation messages.
4.  Exit immediately using sys.exit(0), preventing the benchmark loop from initiating.

**Usage:** To use this new mode, run the script with the --set-values flag, specifying your desired voltage and frequency: python bitaxe_hasrate_benchmark.py <bitaxe_ip> --set-values -v <desired_voltage_mV> -f <desired_frequency_MHz> Example: python bitaxe_hasrate_benchmark.py 192.168.1.136 --set-values -v 1150 -f 780 This enhancement streamlines the process of applying specific configurations to the Bitaxe miner.#
Enhanced the script's command-line help message to be more user-friendly and informative.

Key improvements include:
* **Clearer Descriptions:** Detailed explanations for each argument, including their dual purpose for benchmarking and setting values.
* **Usage Examples:** Added explicit command examples for both benchmark and set-only modes in the help message's epilog.
* **Improved Formatting:** Utilized a custom formatter to preserve multi-line text, add default values, and incorporate color for better readability.#
Resolved rendering issues in argument lists by correctly applying single backticks for inline code, ensuring proper display on GitHub.
Resolved rendering issues in argument lists by correctly applying single backticks for inline code, ensuring proper display on GitHub.
Without PYTHONUNBUFFERED=1, Python fully buffers stdout when not
connected to a TTY, causing docker logs to appear empty until the
container exits.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Adds an unbuffered Python setting and a default /results volume in the Dockerfile, expands README with CLI/Docker usage and details, and significantly enhances bitaxe_hashrate_benchmark.py with a new --set-values mode, richer metrics (hashrate stddev, power, fan speed), dynamic timestamped result filenames, and stabilization/retry logic.

Changes

Cohort / File(s) Summary
Docker Configuration
Dockerfile
Adds PYTHONUNBUFFERED=1, creates /results directory, marks it as a volume, and updates the entrypoint to pass --output-dir /results.
Documentation
README.md
Comprehensive rewrite: expanded CLI/docs, Docker usage examples, new --set-values documentation, revised defaults (timings, steps, limits), and extended output/configuration/safety/benchmarking guidance.
Benchmark Application
bitaxe_hashrate_benchmark.py
Large functional changes: new --set-values mode, custom help formatter, dynamic result_filename() with timestamp suffix, running_stddev() streaming metric, extended benchmark_iteration() returns (adds hashrateStdDev, averagePower, averageFanSpeed), set_system_settings()/restart_system() now return status and include stabilization monitoring and retry-on-overheat logic, enhanced result payloads and save behavior, and richer runtime guards and status output.

Sequence Diagrams

sequenceDiagram
    actor User
    participant CLI as CLI Parser
    participant Device as Bitaxe Device
    participant FS as Result File

    User->>CLI: Run with --set-values + voltage/frequency
    CLI->>CLI: Validate inputs
    CLI->>Device: set_system_settings(voltage, frequency)
    Device->>Device: Apply settings & restart
    Device-->>CLI: Return status (success/fail)
    CLI->>FS: Optionally log/apply result_filename()
    CLI->>User: Exit with status
Loading
sequenceDiagram
    actor User
    participant Bench as Benchmark Loop
    participant Device as Bitaxe Device
    participant Monitor as Stabilization Monitor
    participant Results as Result Storage

    User->>Bench: Start benchmark run
    Bench->>Device: set_system_settings(voltage, frequency)
    Bench->>Device: restart_system()
    Device-->>Monitor: Emit streaming metrics (hashrate, temp, power, fan)
    Monitor->>Monitor: Evaluate stabilization (variance, temp, retries)
    alt Stabilized
        Bench->>Bench: Compute running_stddev, averages
        Bench->>Results: Save JSON via result_filename()
    else Overheat / Unstable
        Bench->>Bench: Adjust voltage/frequency and retry
        Bench->>Device: Re-apply adjusted settings
    end
    Bench-->>User: Return enriched result payload
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 In my burrow I tweak volts and tune,
I watch stddev shimmer beneath the moon,
Docker unbuffered, logs streaming bright,
Results stamped with timestamps through the night,
I hop with joy — power, fan, and hash take flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: enable unbuffered Python output in Docker' is specific and clearly related to the main Dockerfile change, but the PR also includes significant changes to README.md and bitaxe_hashrate_benchmark.py introducing new features (--output-dir flag, standardization metrics, enhanced CLI controls).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@bitaxe_hashrate_benchmark.py`:
- Around line 46-58: The help/epilog text in the ArgumentParser (where parser =
argparse.ArgumentParser(...)) contains a typo in the script name
("bitaxe_hasrate_benchmark.py" missing the "h"); update all example lines in the
epilog that reference that filename to the correct
"bitaxe_hashrate_benchmark.py" so the usage examples match the actual script
name and avoid user confusion.
- Around line 339-363: The stabilization loop that calls get_system_info()
currently swallows all exceptions and can treat repeated telemetry failures as a
successful stabilization; update the loop in bitaxe_hashrate_benchmark.py to
track consecutive read errors (e.g., add a failure_counter initialized before
the while, increment on exception or when info is falsy, and reset on a
successful read), log the failure reason via print or a logger when an error
occurs, and if the failure_counter exceeds a small threshold (e.g., 3
consecutive failures) exit the function with False to fail stabilization; keep
the existing temperature/power/vr checks (temp, vr_temp, power) and only reset
the counter when a valid info dict is returned.

In `@README.md`:
- Around line 132-133: Update the README description of the benchmark output
filename to match the actual behavior: change the static name
"bitaxe_benchmark_results_<ip_address>.json" to the runtime filename pattern
that includes the timestamp/suffix (e.g.,
"bitaxe_benchmark_results_<ip_address>_<timestamp>.json" or similar), and ensure
any surrounding text or examples reference that updated filename format so docs
match the code that writes the timestamped files.

mkhnsn and others added 2 commits February 5, 2026 10:11
Results are written to /results inside the container by default,
making them accessible on the host via a bind mount:
  docker run -v $(pwd)/results:/results bitaxe-benchmark ...

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix script name typo in help examples (hasrate -> hashrate)
- Track consecutive failures during stabilization instead of silently ignoring them
- Update README output filename to reflect timestamp pattern

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bitaxe_hashrate_benchmark.py (1)

508-513: ⚠️ Potential issue | 🟠 Major

Guard VR-temp trimming to avoid ZeroDivisionError on short series.

trimmed_vr_temps can be empty when fewer than 7 VR temp samples are available, causing division by zero. Consider trimming only when enough samples exist, otherwise average the available values or skip VR temp.

🛠️ Suggested fix
-        if vr_temps:
-            sorted_vr_temps = sorted(vr_temps)
-            trimmed_vr_temps = sorted_vr_temps[6:]  # Remove first 6 elements only
-            average_vr_temp = sum(trimmed_vr_temps) / len(trimmed_vr_temps)
+        if vr_temps:
+            sorted_vr_temps = sorted(vr_temps)
+            if len(sorted_vr_temps) > 6:
+                trimmed_vr_temps = sorted_vr_temps[6:]  # Remove first 6 elements only
+            else:
+                trimmed_vr_temps = sorted_vr_temps
+            average_vr_temp = sum(trimmed_vr_temps) / len(trimmed_vr_temps)

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.

5 participants