7zinst fix bin-packing vs concurrent behavior for max CPU and RAM allocation
This commit is contained in:
@@ -19562,7 +19562,6 @@ _**Agent (model default, mode Agent)**_
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Updating the logic to cap workers at the number of sequences to zip. Checking how `max_workers` is called:
|
Updating the logic to cap workers at the number of sequences to zip. Checking how `max_workers` is called:
|
||||||
|
|
||||||
|
|
||||||
@@ -19599,8 +19598,6 @@ Output mode: content
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
@@ -19617,15 +19614,12 @@ Output mode: content
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Updating `max_workers` to cap workers at the number of work items:
|
Updating `max_workers` to cap workers at the number of work items:
|
||||||
|
|
||||||
|
|
||||||
@@ -19643,7 +19637,6 @@ Updating `max_workers` to cap workers at the number of work items:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Capping workers at the number of work items:
|
Capping workers at the number of work items:
|
||||||
|
|
||||||
|
|
||||||
@@ -19692,7 +19685,6 @@ Lines added: 1, lines removed: 1
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Updating the configured `MAX_7Z_INSTANCES` case to also cap at the number of work items:
|
Updating the configured `MAX_7Z_INSTANCES` case to also cap at the number of work items:
|
||||||
|
|
||||||
|
|
||||||
@@ -19742,7 +19734,6 @@ Lines added: 1, lines removed: 1
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Updating the default case when RAM detection fails:
|
Updating the default case when RAM detection fails:
|
||||||
|
|
||||||
|
|
||||||
@@ -19809,15 +19800,12 @@ Lint results
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
Updated the code to cap worker count at the number of sequences to zip. Changes:
|
Updated the code to cap worker count at the number of sequences to zip. Changes:
|
||||||
|
|
||||||
1. **Auto-calculate mode (`Max7zInst=0`)**: Caps workers at the number of work items
|
1. **Auto-calculate mode (`Max7zInst=0`)**: Caps workers at the number of work items
|
||||||
@@ -19832,3 +19820,828 @@ The script still uses aggressive RAM allocation when there are many sequences, b
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
_**User (2025-11-12 16:48Z)**_
|
||||||
|
|
||||||
|
pulled from HOME again.@2025-11-12_01-02Z-compression-failure-and-memory-allocation-issues.md the RAM estimate is far higher than the actual result.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PS P:\250827_FestivalTurf\Renders> & P:\250827_FestivalTurf\Renders\ZipSeqArchv.bat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[init] Loading configuration sources...
|
||||||
|
|
||||||
|
[init] Reading project config at P:\250827_FestivalTurf\.config\config.json
|
||||||
|
|
||||||
|
[init] Configuration loaded from project
|
||||||
|
|
||||||
|
[init] zip_sequences starting up...
|
||||||
|
|
||||||
|
[init] Working directory: P:\250827_FestivalTurf
|
||||||
|
|
||||||
|
[init] Mode: zip, zipper: 7z, jobs arg: auto
|
||||||
|
|
||||||
|
[init] 7z executable: C:\ProgramData\chocolatey\bin\7z.EXE, Max7zInst: auto
|
||||||
|
|
||||||
|
[init] Scanning sequences under \\NEXUS\proj\250827_FestivalTurf\Renders
|
||||||
|
|
||||||
|
[scan] [1] Inspecting 01 Develop Your Turf Plan\01_Blueprint
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\01_Blueprint metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [2] Inspecting 01 Develop Your Turf Plan\01_Blueprint_insert
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\01_Blueprint_insert metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [3] Inspecting 01 Develop Your Turf Plan\02_Roll Sizes
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\02_Roll Sizes metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [4] Inspecting 01 Develop Your Turf Plan\03_Window
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\03_Window metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [5] Inspecting 01 Develop Your Turf Plan\04_Dog
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\04_Dog metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [10] Inspecting 02 Preparing the Base\01_intro
|
||||||
|
|
||||||
|
[scan] [20] Inspecting 02 Preparing the Base\10_FT_Talking
|
||||||
|
|
||||||
|
[scan] [30] Inspecting 03 Roll Out And Stretch\05_diagram
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\02_FT talking (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\02_FT talking_Pt2 (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] [40] Inspecting 04 Securing Your Seam\02_S seam insert
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\04_holding nails (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] [50] Inspecting 04 Securing Your Seam\Nail_dimpling_example
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\01_intro for compression (~1.10GB) [1 total]
|
||||||
|
|
||||||
|
[scan] Skipping 05 Stretch Cut Nail\02_kicker insert (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\02_talking for compression (~0.81GB) [2 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle for compression (~0.70GB) [3 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle_dance_only for compression (~0.38GB) [4 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle_Intro for compression (~0.46GB) [5 total]
|
||||||
|
|
||||||
|
[scan] [60] Inspecting 05 Stretch Cut Nail\Visual 10
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\Visual 11 for compression (~1.17GB) [10 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\Visual 9 for compression (~0.37GB) [15 total]
|
||||||
|
|
||||||
|
[zip] RAM: 102.2GB available (80% of total), 97.1GB for compression (95%)
|
||||||
|
|
||||||
|
[zip] Estimated RAM per sequence: 181.6GB total across 15 sequences
|
||||||
|
|
||||||
|
[zip] Bin-packing: 2 workers, bin sizes: ['97.1GB', '84.5GB']
|
||||||
|
|
||||||
|
[zip] Final worker count: 2 (requested: None)
|
||||||
|
|
||||||
|
[init] Preparing to compress 15 sequence(s) with 2 worker(s)
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\01_intro -> Renders\_zipped\05 Stretch Cut Nail\01_intro.7z
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\02_talking -> Renders\_zipped\05 Stretch Cut Nail\02_talking.7z
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\03_FT Shuffle -> Renders\_zipped\05 Stretch Cut Nail\03_FT Shuffle.7z
|
||||||
|
|
||||||
|
[zip] 1/15 05 Stretch Cut Nail\02_talking
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Agent (model default, mode Agent)**_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
The RAM estimate is too high. The image shows 7z processes using ~7–10GB each, but the estimate is ~12GB per sequence. Updating the estimation to match actual usage:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="read" data-tool-name="read_file">
|
||||||
|
<details><summary>Tool use: **read_file** • Read file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="read" data-tool-name="read_file">
|
||||||
|
<details><summary>Tool use: **read_file** • Read file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Updating the RAM estimate to match actual usage (~7–10GB per 7z process). The current estimate is too high:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="write" data-tool-name="search_replace">
|
||||||
|
|
||||||
|
<details><summary>Tool use: **code_edit** • Edit file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 12, lines removed: 17
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -214,23 +214,18 @@
|
||||||
|
FIXED_DICT_SIZE_BYTES = FIXED_DICT_SIZE_MB * 1024 * 1024
|
||||||
|
|
||||||
|
- # Dictionary RAM: ~11x dictionary size (1GB dict = 11GB RAM for dictionary operations)
|
||||||
|
- # This is the main memory consumer for 7z LZMA compression
|
||||||
|
- dict_ram = FIXED_DICT_SIZE_BYTES * 11 # 11GB for 1GB dictionary
|
||||||
|
+ # Dictionary RAM: ~8x dictionary size (1GB dict = 8GB RAM)
|
||||||
|
+ # Based on actual observed usage: 7z processes use ~7-10GB with 1GB dictionary
|
||||||
|
+ dict_ram = FIXED_DICT_SIZE_BYTES * 8 # 8GB for 1GB dictionary
|
||||||
|
|
||||||
|
- # Input buffer: 7z processes in chunks, but for very large sequences needs more RAM
|
||||||
|
- # For sequences >100GB, use a larger buffer factor to handle file metadata and processing
|
||||||
|
- if total_bytes > 500 * 1024 * 1024 * 1024: # >500GB (extremely large)
|
||||||
|
- # Extremely large sequences: use 8% of size, capped at 64GB
|
||||||
|
- # This accounts for file metadata, directory structures, and processing overhead
|
||||||
|
- input_buffer = min(int(total_bytes * 0.08), 64 * 1024 * 1024 * 1024)
|
||||||
|
- overhead = 8 * 1024 * 1024 * 1024 # 8GB overhead for extremely large sequences
|
||||||
|
- elif total_bytes > 100 * 1024 * 1024 * 1024: # >100GB
|
||||||
|
- # Very large sequences: use 5% of size, capped at 32GB
|
||||||
|
- input_buffer = min(int(total_bytes * 0.05), 32 * 1024 * 1024 * 1024)
|
||||||
|
- overhead = 4 * 1024 * 1024 * 1024 # 4GB for large sequences
|
||||||
|
+ # Input buffer: 7z processes files in chunks, minimal buffer needed
|
||||||
|
+ # For most sequences, a small fixed buffer is sufficient
|
||||||
|
+ if total_bytes > 100 * 1024 * 1024 * 1024: # >100GB
|
||||||
|
+ # Very large sequences: use 1% of size, capped at 4GB
|
||||||
|
+ input_buffer = min(int(total_bytes * 0.01), 4 * 1024 * 1024 * 1024)
|
||||||
|
+ overhead = 1 * 1024 * 1024 * 1024 # 1GB overhead
|
||||||
|
else:
|
||||||
|
- # Smaller sequences: use 15% of size, capped at 2GB
|
||||||
|
- input_buffer = min(int(total_bytes * 0.15), 2 * 1024 * 1024 * 1024)
|
||||||
|
- overhead = 1 * 1024 * 1024 * 1024 # 1GB for smaller sequences
|
||||||
|
+ # Normal sequences: use small fixed buffer
|
||||||
|
+ input_buffer = 512 * 1024 * 1024 # 512MB buffer
|
||||||
|
+ overhead = 512 * 1024 * 1024 # 512MB overhead
|
||||||
|
|
||||||
|
# Total RAM estimate
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="generic" data-tool-name="read_lints">
|
||||||
|
<details>
|
||||||
|
<summary>Tool use: **read_lints** • Read lints for 1 file</summary>
|
||||||
|
|
||||||
|
Lint paths:
|
||||||
|
|
||||||
|
- `zip_sequences.py`
|
||||||
|
|
||||||
|
Lint results
|
||||||
|
|
||||||
|
|
||||||
|
**No lint errors found**
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Updated the RAM estimation to match observed usage. Changes:
|
||||||
|
|
||||||
|
1. **Reduced dictionary RAM multiplier**: From 11x to 8x (8GB instead of 11GB for a 1GB dictionary), matching observed 7–10GB usage
|
||||||
|
2. **Reduced input buffer**: From 15% of sequence size (capped at 2GB) to a fixed 512MB for normal sequences
|
||||||
|
3. **Reduced overhead**: From 1GB to 512MB for normal sequences
|
||||||
|
|
||||||
|
**New estimate for a 1GB sequence**: 8GB + 512MB + 512MB = **9GB** (down from ~12GB)
|
||||||
|
|
||||||
|
This aligns with observed usage and allows more concurrent workers since the bin-packing algorithm can fit more jobs into the available RAM. For your 15 sequences totaling ~12GB, the estimate should be around 135GB total (15 × 9GB) instead of 181.6GB, allowing more workers to run concurrently.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**User (2025-11-12 16:48Z)**_
|
||||||
|
|
||||||
|
It's still only giving 2 instances that are allocating around 2gb. We should be more aggressive or tighten our estimation.
|
||||||
|
|
||||||
|
PS P:\250827_FestivalTurf\Renders> & P:\250827_FestivalTurf\Renders\ZipSeqArchv.bat
|
||||||
|
|
||||||
|
[init] Loading configuration sources...
|
||||||
|
|
||||||
|
[init] Reading project config at P:\250827_FestivalTurf\.config\config.json
|
||||||
|
|
||||||
|
[init] Configuration loaded from project
|
||||||
|
|
||||||
|
[init] zip_sequences starting up...
|
||||||
|
|
||||||
|
[init] Working directory: P:\250827_FestivalTurf
|
||||||
|
|
||||||
|
[init] Mode: zip, zipper: 7z, jobs arg: auto
|
||||||
|
|
||||||
|
[init] 7z executable: C:\ProgramData\chocolatey\bin\7z.EXE, Max7zInst: auto
|
||||||
|
|
||||||
|
[init] Scanning sequences under \\NEXUS\proj\250827_FestivalTurf\Renders
|
||||||
|
|
||||||
|
[scan] [1] Inspecting 01 Develop Your Turf Plan\01_Blueprint
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\01_Blueprint metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [2] Inspecting 01 Develop Your Turf Plan\01_Blueprint_insert
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\01_Blueprint_insert metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [3] Inspecting 01 Develop Your Turf Plan\02_Roll Sizes
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\02_Roll Sizes metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [4] Inspecting 01 Develop Your Turf Plan\03_Window
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\03_Window metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [5] Inspecting 01 Develop Your Turf Plan\04_Dog
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\04_Dog metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [10] Inspecting 02 Preparing the Base\01_intro
|
||||||
|
|
||||||
|
[scan] [20] Inspecting 02 Preparing the Base\10_FT_Talking
|
||||||
|
|
||||||
|
[scan] [30] Inspecting 03 Roll Out And Stretch\05_diagram
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\02_FT talking (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\02_FT talking_Pt2 (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] [40] Inspecting 04 Securing Your Seam\02_S seam insert
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\04_holding nails (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] [50] Inspecting 04 Securing Your Seam\Nail_dimpling_example
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\01_intro for compression (~1.10GB) [1 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\02_kicker insert for compression (~0.24GB) [2 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\02_talking for compression (~0.81GB) [3 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle for compression (~0.70GB) [4 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle_dance_only for compression (~0.38GB) [5 total]
|
||||||
|
|
||||||
|
[scan] [60] Inspecting 05 Stretch Cut Nail\Visual 10
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\Visual 10 for compression (~1.28GB) [10 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\Visual 8 for compression (~0.94GB) [15 total]
|
||||||
|
|
||||||
|
[zip] RAM: 102.2GB available (80% of total), 97.1GB for compression (95%)
|
||||||
|
|
||||||
|
[zip] Estimated RAM per sequence: 144.0GB total across 16 sequences
|
||||||
|
|
||||||
|
[zip] Bin-packing: 2 workers, bin sizes: ['90.0GB', '54.0GB']
|
||||||
|
|
||||||
|
[zip] Final worker count: 2 (requested: None)
|
||||||
|
|
||||||
|
[init] Preparing to compress 16 sequence(s) with 2 worker(s)
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\01_intro -> Renders\_zipped\05 Stretch Cut Nail\01_intro.7z
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\02_kicker insert -> Renders\_zipped\05 Stretch Cut Nail\02_kicker insert.7z
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\02_talking -> Renders\_zipped\05 Stretch Cut Nail\02_talking.7z
|
||||||
|
|
||||||
|
[zip] 1/16 05 Stretch Cut Nail\02_kicker insert
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Agent (model default, mode Agent)**_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Updating the RAM estimate to match actual usage (~2GB per process) so we can run more workers:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="read" data-tool-name="read_file">
|
||||||
|
<details><summary>Tool use: **read_file** • Read file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Tightening the RAM estimate to match actual usage (~2GB per process):
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="write" data-tool-name="search_replace">
|
||||||
|
|
||||||
|
<details><summary>Tool use: **code_edit** • Edit file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 10, lines removed: 19
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -211,24 +211,15 @@
|
||||||
|
if ZIPPER_TYPE == "7z":
|
||||||
|
# Fixed dictionary size: 1GB (1024MB)
|
||||||
|
- FIXED_DICT_SIZE_MB = 1024
|
||||||
|
- FIXED_DICT_SIZE_BYTES = FIXED_DICT_SIZE_MB * 1024 * 1024
|
||||||
|
-
|
||||||
|
- # Dictionary RAM: ~8x dictionary size (1GB dict = 8GB RAM)
|
||||||
|
- # Based on actual observed usage: 7z processes use ~7-10GB with 1GB dictionary
|
||||||
|
- dict_ram = FIXED_DICT_SIZE_BYTES * 8 # 8GB for 1GB dictionary
|
||||||
|
-
|
||||||
|
- # Input buffer: 7z processes files in chunks, minimal buffer needed
|
||||||
|
- # For most sequences, a small fixed buffer is sufficient
|
||||||
|
- if total_bytes > 100 * 1024 * 1024 * 1024: # >100GB
|
||||||
|
- # Very large sequences: use 1% of size, capped at 4GB
|
||||||
|
- input_buffer = min(int(total_bytes * 0.01), 4 * 1024 * 1024 * 1024)
|
||||||
|
- overhead = 1 * 1024 * 1024 * 1024 # 1GB overhead
|
||||||
|
+ # Actual observed usage: ~2GB per process regardless of sequence size
|
||||||
|
+ # Use a tight estimate to allow maximum concurrency
|
||||||
|
+ # Estimate 3GB per job (50% safety margin over observed ~2GB)
|
||||||
|
+ base_ram = 3 * 1024 * 1024 * 1024 # 3GB base estimate
|
||||||
|
+
|
||||||
|
+ # For very large sequences (>50GB), add small buffer
|
||||||
|
+ if total_bytes > 50 * 1024 * 1024 * 1024: # >50GB
|
||||||
|
+ # Add 1GB for very large sequences
|
||||||
|
+ estimated_ram = base_ram + (1 * 1024 * 1024 * 1024)
|
||||||
|
else:
|
||||||
|
- # Normal sequences: use small fixed buffer
|
||||||
|
- input_buffer = 512 * 1024 * 1024 # 512MB buffer
|
||||||
|
- overhead = 512 * 1024 * 1024 # 512MB overhead
|
||||||
|
-
|
||||||
|
- # Total RAM estimate
|
||||||
|
- estimated_ram = dict_ram + input_buffer + overhead
|
||||||
|
+ estimated_ram = base_ram
|
||||||
|
|
||||||
|
return estimated_ram
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="generic" data-tool-name="read_lints">
|
||||||
|
<details>
|
||||||
|
<summary>Tool use: **read_lints** • Read lints for 1 file</summary>
|
||||||
|
|
||||||
|
Lint paths:
|
||||||
|
|
||||||
|
- `zip_sequences.py`
|
||||||
|
|
||||||
|
Lint results
|
||||||
|
|
||||||
|
|
||||||
|
**No lint errors found**
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Updated the RAM estimate to match actual usage:
|
||||||
|
|
||||||
|
**Changes:**
|
||||||
|
1. **Reduced estimate from 9GB to 3GB per job** — based on observed ~2GB usage with a 50% safety margin
|
||||||
|
2. **Simplified calculation** — removed the dictionary multiplier; using a fixed 3GB base estimate
|
||||||
|
3. **Only add buffer for very large sequences** — sequences >50GB get +1GB
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
- **Before**: 16 sequences × 9GB = 144GB estimated → 2 workers
|
||||||
|
- **After**: 16 sequences × 3GB = 48GB estimated → ~32 workers possible
|
||||||
|
|
||||||
|
With 97GB available for compression and 3GB per job, bin-packing should allow many more concurrent workers. The estimate is tighter while still leaving headroom for actual usage variations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**User (2025-11-12 16:48Z)**_
|
||||||
|
|
||||||
|
with this estimate, it should be able to work on all of them concurrently. why is it only doing one?
|
||||||
|
|
||||||
|
PS P:\250827_FestivalTurf\Renders> & P:\250827_FestivalTurf\Renders\ZipSeqArchv.bat
|
||||||
|
|
||||||
|
[init] Loading configuration sources...
|
||||||
|
|
||||||
|
[init] Reading project config at P:\250827_FestivalTurf\.config\config.json
|
||||||
|
|
||||||
|
[init] Configuration loaded from project
|
||||||
|
|
||||||
|
[init] zip_sequences starting up...
|
||||||
|
|
||||||
|
[init] Working directory: P:\250827_FestivalTurf
|
||||||
|
|
||||||
|
[init] Mode: zip, zipper: 7z, jobs arg: auto
|
||||||
|
|
||||||
|
[init] 7z executable: C:\ProgramData\chocolatey\bin\7z.EXE, Max7zInst: auto
|
||||||
|
|
||||||
|
[init] Scanning sequences under \\NEXUS\proj\250827_FestivalTurf\Renders
|
||||||
|
|
||||||
|
[scan] [1] Inspecting 01 Develop Your Turf Plan\01_Blueprint
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\01_Blueprint metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [2] Inspecting 01 Develop Your Turf Plan\01_Blueprint_insert
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\01_Blueprint_insert metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [3] Inspecting 01 Develop Your Turf Plan\02_Roll Sizes
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\02_Roll Sizes metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [4] Inspecting 01 Develop Your Turf Plan\03_Window
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\03_Window metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [5] Inspecting 01 Develop Your Turf Plan\04_Dog
|
||||||
|
|
||||||
|
[scan] 01 Develop Your Turf Plan\04_Dog metadata unchanged; archive up to date
|
||||||
|
|
||||||
|
[scan] [10] Inspecting 02 Preparing the Base\01_intro
|
||||||
|
|
||||||
|
[scan] [20] Inspecting 02 Preparing the Base\10_FT_Talking
|
||||||
|
|
||||||
|
[scan] [30] Inspecting 03 Roll Out And Stretch\05_diagram
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\02_FT talking (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\02_FT talking_Pt2 (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] [40] Inspecting 04 Securing Your Seam\02_S seam insert
|
||||||
|
|
||||||
|
[scan] Skipping 04 Securing Your Seam\04_holding nails (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] [50] Inspecting 04 Securing Your Seam\Nail_dimpling_example
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\01_intro for compression (~1.10GB) [1 total]
|
||||||
|
|
||||||
|
[scan] Skipping 05 Stretch Cut Nail\02_kicker insert (unchanged since archive)
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\02_talking for compression (~0.81GB) [2 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle for compression (~0.70GB) [3 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle_dance_only for compression (~0.38GB) [4 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\03_FT Shuffle_Intro for compression (~0.46GB) [5 total]
|
||||||
|
|
||||||
|
[scan] [60] Inspecting 05 Stretch Cut Nail\Visual 10
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\Visual 11 for compression (~1.17GB) [10 total]
|
||||||
|
|
||||||
|
[scan] Queued 05 Stretch Cut Nail\Visual 9 for compression (~0.37GB) [15 total]
|
||||||
|
|
||||||
|
[zip] RAM: 102.2GB available (80% of total), 97.1GB for compression (95%)
|
||||||
|
|
||||||
|
[zip] Estimated RAM per sequence: 45.0GB total across 15 sequences
|
||||||
|
|
||||||
|
[zip] Bin-packing: 1 workers, bin sizes: ['45.0GB']
|
||||||
|
|
||||||
|
[zip] Final worker count: 1 (requested: None)
|
||||||
|
|
||||||
|
[init] Preparing to compress 15 sequence(s) with 1 worker(s)
|
||||||
|
|
||||||
|
[zip] Renders\05 Stretch Cut Nail\01_intro -> Renders\_zipped\05 Stretch Cut Nail\01_intro.7z
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Agent (model default, mode Agent)**_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
The bin-packing algorithm is packing all sequences into a single bin. With 97GB available and 3GB per sequence, we should run all 15 concurrently. Checking the bin-packing logic:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="read" data-tool-name="read_file">
|
||||||
|
<details><summary>Tool use: **read_file** • Read file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
The bin-packing minimizes bins (workers), so it packs all sequences into one bin. For maximum concurrency, we should run one worker per sequence when they all fit. Updating the logic:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="write" data-tool-name="search_replace">
|
||||||
|
|
||||||
|
<details><summary>Tool use: **code_edit** • Edit file: zip_sequences.py</summary>
|
||||||
|
|
||||||
|
**Chunk 1**
|
||||||
|
Lines added: 2, lines removed: 2
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -299,11 +299,11 @@
|
||||||
|
|
||||||
|
# Auto-calculate based on RAM if Max7zInst not configured
|
||||||
|
- # Use bin-packing algorithm with size-aware RAM estimation
|
||||||
|
+ # Prioritize maximum concurrency: one worker per sequence when possible
|
||||||
|
if available_ram is not None:
|
||||||
|
# available_ram is already 80% of total (20% reserved for system)
|
||||||
|
# Use 95% of available RAM for compression jobs
|
||||||
|
compression_ram = int(available_ram * 0.95)
|
||||||
|
|
||||||
|
- # Estimate RAM for each work item and create list with (seq_dir, estimated_ram, work_item)
|
||||||
|
+ # Estimate RAM for each work item
|
||||||
|
work_items_with_ram: list[tuple[Path, int, tuple[Path, Path, Path, dict]]] = []
|
||||||
|
ram_limits_dict: dict[Path, int] = {}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Chunk 2**
|
||||||
|
Lines added: 36, lines removed: 27
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -315,36 +315,45 @@
|
||||||
|
ram_limits_dict[seq_dir] = estimated_ram
|
||||||
|
except Exception:
|
||||||
|
- # If estimation fails, use a safe default (12GB minimum for 1GB dict)
|
||||||
|
- default_ram = 12 * 1024 * 1024 * 1024 # 12GB
|
||||||
|
+ # If estimation fails, use a safe default (3GB)
|
||||||
|
+ default_ram = 3 * 1024 * 1024 * 1024 # 3GB
|
||||||
|
work_items_with_ram.append((seq_dir, default_ram, (seq_dir, zip_path, state_path, seq_state)))
|
||||||
|
ram_limits_dict[seq_dir] = default_ram
|
||||||
|
|
||||||
|
- # Sort by estimated RAM (largest first) for bin-packing
|
||||||
|
- work_items_with_ram.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
-
|
||||||
|
- # Bin-packing algorithm: pack largest items first
|
||||||
|
- bins: list[list[tuple[Path, int, tuple[Path, Path, Path, dict]]]] = []
|
||||||
|
- bin_remaining: list[int] = []
|
||||||
|
-
|
||||||
|
- for seq_dir, estimated_ram, work_item in work_items_with_ram:
|
||||||
|
- # Try to fit in existing bin
|
||||||
|
- placed = False
|
||||||
|
- for i, remaining in enumerate(bin_remaining):
|
||||||
|
- if remaining >= estimated_ram:
|
||||||
|
- bins[i].append((seq_dir, estimated_ram, work_item))
|
||||||
|
- bin_remaining[i] -= estimated_ram
|
||||||
|
- placed = True
|
||||||
|
- break
|
||||||
|
-
|
||||||
|
- # If doesn't fit, create new bin
|
||||||
|
- if not placed:
|
||||||
|
- bins.append([(seq_dir, estimated_ram, work_item)])
|
||||||
|
- bin_remaining.append(compression_ram - estimated_ram)
|
||||||
|
-
|
||||||
|
- # Worker count is number of bins
|
||||||
|
- worker_count = len(bins)
|
||||||
|
+ num_work_items = len(work_items) if work_items else 0
|
||||||
|
+
|
||||||
|
+ # Calculate total estimated RAM
|
||||||
|
+ total_estimated_ram = sum(ram for _, ram, _ in work_items_with_ram)
|
||||||
|
+
|
||||||
|
+ # If all sequences fit in available RAM, use one worker per sequence (maximum concurrency)
|
||||||
|
+ if total_estimated_ram <= compression_ram:
|
||||||
|
+ worker_count = num_work_items
|
||||||
|
+ else:
|
||||||
|
+ # Not all fit - use bin-packing to minimize workers
|
||||||
|
+ # Sort by estimated RAM (largest first) for bin-packing
|
||||||
|
+ work_items_with_ram.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
+
|
||||||
|
+ # Bin-packing algorithm: pack largest items first
|
||||||
|
+ bins: list[list[tuple[Path, int, tuple[Path, Path, Path, dict]]]] = []
|
||||||
|
+ bin_remaining: list[int] = []
|
||||||
|
+
|
||||||
|
+ for seq_dir, estimated_ram, work_item in work_items_with_ram:
|
||||||
|
+ # Try to fit in existing bin
|
||||||
|
+ placed = False
|
||||||
|
+ for i, remaining in enumerate(bin_remaining):
|
||||||
|
+ if remaining >= estimated_ram:
|
||||||
|
+ bins[i].append((seq_dir, estimated_ram, work_item))
|
||||||
|
+ bin_remaining[i] -= estimated_ram
|
||||||
|
+ placed = True
|
||||||
|
+ break
|
||||||
|
+
|
||||||
|
+ # If doesn't fit, create new bin
|
||||||
|
+ if not placed:
|
||||||
|
+ bins.append([(seq_dir, estimated_ram, work_item)])
|
||||||
|
+ bin_remaining.append(compression_ram - estimated_ram)
|
||||||
|
+
|
||||||
|
+ # Worker count is number of bins
|
||||||
|
+ worker_count = len(bins)
|
||||||
|
|
||||||
|
# Cap at number of actual work items (can't have more workers than jobs)
|
||||||
|
- num_work_items = len(work_items) if work_items else 0
|
||||||
|
if num_work_items > 0:
|
||||||
|
worker_count = min(worker_count, num_work_items)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Chunk 3**
|
||||||
|
Lines added: 1, lines removed: 1
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -357,5 +366,5 @@
|
||||||
|
ram_gb = available_ram / (1024 ** 3)
|
||||||
|
compression_ram_gb = compression_ram / (1024 ** 3)
|
||||||
|
- total_estimated_gb = sum(ram for _, ram, _ in work_items_with_ram) / (1024 ** 3)
|
||||||
|
+ total_estimated_gb = total_estimated_ram / (1024 ** 3)
|
||||||
|
log(
|
||||||
|
"zip",
|
||||||
|
```
|
||||||
|
|
||||||
|
**Chunk 4**
|
||||||
|
Lines added: 9, lines removed: 3
|
||||||
|
|
||||||
|
```diff
|
||||||
|
@@ -370,12 +379,18 @@
|
||||||
|
verbose=verbose
|
||||||
|
)
|
||||||
|
- if len(bins) > 0:
|
||||||
|
- bin_sizes = [sum(ram for _, ram, _ in bin_items) / (1024 ** 3) for bin_items in bins]
|
||||||
|
+ if total_estimated_ram <= compression_ram:
|
||||||
|
log(
|
||||||
|
"zip",
|
||||||
|
- f"Bin-packing: {worker_count} workers, bin sizes: {[f'{s:.1f}GB' for s in bin_sizes[:5]]}{'...' if len(bin_sizes) > 5 else ''}",
|
||||||
|
+ f"All sequences fit in RAM → using {worker_count} workers (one per sequence)",
|
||||||
|
verbose_only=True,
|
||||||
|
verbose=verbose
|
||||||
|
)
|
||||||
|
+ else:
|
||||||
|
+ log(
|
||||||
|
+ "zip",
|
||||||
|
+ f"Using bin-packing: {worker_count} workers needed",
|
||||||
|
+ verbose_only=True,
|
||||||
|
+ verbose=verbose
|
||||||
|
+ )
|
||||||
|
log(
|
||||||
|
"zip",
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<tool-use data-tool-type="generic" data-tool-name="read_lints">
|
||||||
|
<details>
|
||||||
|
<summary>Tool use: **read_lints** • Read lints for 1 file</summary>
|
||||||
|
|
||||||
|
Lint paths:
|
||||||
|
|
||||||
|
- `zip_sequences.py`
|
||||||
|
|
||||||
|
Lint results
|
||||||
|
|
||||||
|
|
||||||
|
**No lint errors found**
|
||||||
|
</details>
|
||||||
|
</tool-use>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
Updated the logic to prioritize maximum concurrency. Changes:
|
||||||
|
|
||||||
|
1. **Check if all sequences fit**: If total estimated RAM (45GB) ≤ available compression RAM (97GB), use one worker per sequence.
|
||||||
|
2. **Use bin-packing only when needed**: Only when sequences don't all fit in RAM.
|
||||||
|
|
||||||
|
**Result:**
|
||||||
|
- **Before**: Bin-packing minimized bins → 1 worker for all 15 sequences
|
||||||
|
- **After**: All sequences fit → 15 workers (one per sequence), all running concurrently
|
||||||
|
|
||||||
|
With 45GB total estimated RAM and 97GB available, all 15 sequences will run concurrently instead of sequentially.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**User (2025-11-12 16:48Z)**_
|
||||||
|
|
||||||
|
what is bin packing?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_**Agent (model default, mode Agent)**_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
**Bin packing** is an optimization problem: given items of different sizes and bins of fixed capacity, pack all items using as few bins as possible.
|
||||||
|
|
||||||
|
## In Your Code Context
|
||||||
|
|
||||||
|
In the compression script, bin packing is used to:
|
||||||
|
- **Items**: Sequences to compress (each estimated at ~3GB RAM)
|
||||||
|
- **Bins**: Workers (each can use up to 97GB RAM)
|
||||||
|
- **Goal**: Minimize the number of workers needed
|
||||||
|
|
||||||
|
### Example:
|
||||||
|
If you have 15 sequences (each ~3GB) and 97GB available per worker:
|
||||||
|
- **Without bin packing**: Could create 15 workers (one per sequence)
|
||||||
|
- **With bin packing**: Packs sequences into as few workers as possible
|
||||||
|
- Worker 1: Sequences 1-32 (96GB total)
|
||||||
|
- Worker 2: Sequences 33-64 (96GB total)
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
## Why It Was a Problem
|
||||||
|
|
||||||
|
Bin packing minimizes the number of workers, which can reduce concurrency. With 15 sequences totaling 45GB and 97GB available, bin packing put all 15 into one worker, so they ran sequentially.
|
||||||
|
|
||||||
|
## The Fix
|
||||||
|
|
||||||
|
The code now checks if all sequences fit in available RAM:
|
||||||
|
- If yes: Use one worker per sequence (maximum concurrency)
|
||||||
|
- If no: Use bin packing to minimize workers
|
||||||
|
|
||||||
|
This prioritizes speed when possible, and efficiency when needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -210,31 +210,17 @@ def estimate_ram_per_job(seq_dir: Path, seq_state: dict) -> int:
|
|||||||
|
|
||||||
if ZIPPER_TYPE == "7z":
|
if ZIPPER_TYPE == "7z":
|
||||||
# Fixed dictionary size: 1GB (1024MB)
|
# Fixed dictionary size: 1GB (1024MB)
|
||||||
FIXED_DICT_SIZE_MB = 1024
|
# Actual observed usage: ~2GB per process regardless of sequence size
|
||||||
FIXED_DICT_SIZE_BYTES = FIXED_DICT_SIZE_MB * 1024 * 1024
|
# Use a tight estimate to allow maximum concurrency
|
||||||
|
# Estimate 3GB per job (50% safety margin over observed ~2GB)
|
||||||
|
base_ram = 3 * 1024 * 1024 * 1024 # 3GB base estimate
|
||||||
|
|
||||||
# Dictionary RAM: ~11x dictionary size (1GB dict = 11GB RAM for dictionary operations)
|
# For very large sequences (>50GB), add small buffer
|
||||||
# This is the main memory consumer for 7z LZMA compression
|
if total_bytes > 50 * 1024 * 1024 * 1024: # >50GB
|
||||||
dict_ram = FIXED_DICT_SIZE_BYTES * 11 # 11GB for 1GB dictionary
|
# Add 1GB for very large sequences
|
||||||
|
estimated_ram = base_ram + (1 * 1024 * 1024 * 1024)
|
||||||
# Input buffer: 7z processes in chunks, but for very large sequences needs more RAM
|
|
||||||
# For sequences >100GB, use a larger buffer factor to handle file metadata and processing
|
|
||||||
if total_bytes > 500 * 1024 * 1024 * 1024: # >500GB (extremely large)
|
|
||||||
# Extremely large sequences: use 8% of size, capped at 64GB
|
|
||||||
# This accounts for file metadata, directory structures, and processing overhead
|
|
||||||
input_buffer = min(int(total_bytes * 0.08), 64 * 1024 * 1024 * 1024)
|
|
||||||
overhead = 8 * 1024 * 1024 * 1024 # 8GB overhead for extremely large sequences
|
|
||||||
elif total_bytes > 100 * 1024 * 1024 * 1024: # >100GB
|
|
||||||
# Very large sequences: use 5% of size, capped at 32GB
|
|
||||||
input_buffer = min(int(total_bytes * 0.05), 32 * 1024 * 1024 * 1024)
|
|
||||||
overhead = 4 * 1024 * 1024 * 1024 # 4GB for large sequences
|
|
||||||
else:
|
else:
|
||||||
# Smaller sequences: use 15% of size, capped at 2GB
|
estimated_ram = base_ram
|
||||||
input_buffer = min(int(total_bytes * 0.15), 2 * 1024 * 1024 * 1024)
|
|
||||||
overhead = 1 * 1024 * 1024 * 1024 # 1GB for smaller sequences
|
|
||||||
|
|
||||||
# Total RAM estimate
|
|
||||||
estimated_ram = dict_ram + input_buffer + overhead
|
|
||||||
|
|
||||||
return estimated_ram
|
return estimated_ram
|
||||||
else:
|
else:
|
||||||
@@ -312,13 +298,13 @@ def max_workers(
|
|||||||
return (final_limit, ram_limits_dict)
|
return (final_limit, ram_limits_dict)
|
||||||
|
|
||||||
# Auto-calculate based on RAM if Max7zInst not configured
|
# Auto-calculate based on RAM if Max7zInst not configured
|
||||||
# Use bin-packing algorithm with size-aware RAM estimation
|
# Prioritize maximum concurrency: one worker per sequence when possible
|
||||||
if available_ram is not None:
|
if available_ram is not None:
|
||||||
# available_ram is already 80% of total (20% reserved for system)
|
# available_ram is already 80% of total (20% reserved for system)
|
||||||
# Use 95% of available RAM for compression jobs
|
# Use 95% of available RAM for compression jobs
|
||||||
compression_ram = int(available_ram * 0.95)
|
compression_ram = int(available_ram * 0.95)
|
||||||
|
|
||||||
# Estimate RAM for each work item and create list with (seq_dir, estimated_ram, work_item)
|
# Estimate RAM for each work item
|
||||||
work_items_with_ram: list[tuple[Path, int, tuple[Path, Path, Path, dict]]] = []
|
work_items_with_ram: list[tuple[Path, int, tuple[Path, Path, Path, dict]]] = []
|
||||||
ram_limits_dict: dict[Path, int] = {}
|
ram_limits_dict: dict[Path, int] = {}
|
||||||
|
|
||||||
@@ -328,11 +314,21 @@ def max_workers(
|
|||||||
work_items_with_ram.append((seq_dir, estimated_ram, (seq_dir, zip_path, state_path, seq_state)))
|
work_items_with_ram.append((seq_dir, estimated_ram, (seq_dir, zip_path, state_path, seq_state)))
|
||||||
ram_limits_dict[seq_dir] = estimated_ram
|
ram_limits_dict[seq_dir] = estimated_ram
|
||||||
except Exception:
|
except Exception:
|
||||||
# If estimation fails, use a safe default (12GB minimum for 1GB dict)
|
# If estimation fails, use a safe default (3GB)
|
||||||
default_ram = 12 * 1024 * 1024 * 1024 # 12GB
|
default_ram = 3 * 1024 * 1024 * 1024 # 3GB
|
||||||
work_items_with_ram.append((seq_dir, default_ram, (seq_dir, zip_path, state_path, seq_state)))
|
work_items_with_ram.append((seq_dir, default_ram, (seq_dir, zip_path, state_path, seq_state)))
|
||||||
ram_limits_dict[seq_dir] = default_ram
|
ram_limits_dict[seq_dir] = default_ram
|
||||||
|
|
||||||
|
num_work_items = len(work_items) if work_items else 0
|
||||||
|
|
||||||
|
# Calculate total estimated RAM
|
||||||
|
total_estimated_ram = sum(ram for _, ram, _ in work_items_with_ram)
|
||||||
|
|
||||||
|
# If all sequences fit in available RAM, use one worker per sequence (maximum concurrency)
|
||||||
|
if total_estimated_ram <= compression_ram:
|
||||||
|
worker_count = num_work_items
|
||||||
|
else:
|
||||||
|
# Not all fit - use bin-packing to minimize workers
|
||||||
# Sort by estimated RAM (largest first) for bin-packing
|
# Sort by estimated RAM (largest first) for bin-packing
|
||||||
work_items_with_ram.sort(key=lambda x: x[1], reverse=True)
|
work_items_with_ram.sort(key=lambda x: x[1], reverse=True)
|
||||||
|
|
||||||
@@ -359,7 +355,6 @@ def max_workers(
|
|||||||
worker_count = len(bins)
|
worker_count = len(bins)
|
||||||
|
|
||||||
# Cap at number of actual work items (can't have more workers than jobs)
|
# Cap at number of actual work items (can't have more workers than jobs)
|
||||||
num_work_items = len(work_items) if work_items else 0
|
|
||||||
if num_work_items > 0:
|
if num_work_items > 0:
|
||||||
worker_count = min(worker_count, num_work_items)
|
worker_count = min(worker_count, num_work_items)
|
||||||
|
|
||||||
@@ -370,7 +365,7 @@ def max_workers(
|
|||||||
if verbose:
|
if verbose:
|
||||||
ram_gb = available_ram / (1024 ** 3)
|
ram_gb = available_ram / (1024 ** 3)
|
||||||
compression_ram_gb = compression_ram / (1024 ** 3)
|
compression_ram_gb = compression_ram / (1024 ** 3)
|
||||||
total_estimated_gb = sum(ram for _, ram, _ in work_items_with_ram) / (1024 ** 3)
|
total_estimated_gb = total_estimated_ram / (1024 ** 3)
|
||||||
log(
|
log(
|
||||||
"zip",
|
"zip",
|
||||||
f"RAM: {ram_gb:.1f}GB available (80% of total), {compression_ram_gb:.1f}GB for compression (95%)",
|
f"RAM: {ram_gb:.1f}GB available (80% of total), {compression_ram_gb:.1f}GB for compression (95%)",
|
||||||
@@ -383,11 +378,17 @@ def max_workers(
|
|||||||
verbose_only=True,
|
verbose_only=True,
|
||||||
verbose=verbose
|
verbose=verbose
|
||||||
)
|
)
|
||||||
if len(bins) > 0:
|
if total_estimated_ram <= compression_ram:
|
||||||
bin_sizes = [sum(ram for _, ram, _ in bin_items) / (1024 ** 3) for bin_items in bins]
|
|
||||||
log(
|
log(
|
||||||
"zip",
|
"zip",
|
||||||
f"Bin-packing: {worker_count} workers, bin sizes: {[f'{s:.1f}GB' for s in bin_sizes[:5]]}{'...' if len(bin_sizes) > 5 else ''}",
|
f"All sequences fit in RAM → using {worker_count} workers (one per sequence)",
|
||||||
|
verbose_only=True,
|
||||||
|
verbose=verbose
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
log(
|
||||||
|
"zip",
|
||||||
|
f"Using bin-packing: {worker_count} workers needed",
|
||||||
verbose_only=True,
|
verbose_only=True,
|
||||||
verbose=verbose
|
verbose=verbose
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user