-
Notifications
You must be signed in to change notification settings - Fork 0
Parallelize and right-size the sequence-properties compute step #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
PaulNewling
wants to merge
6
commits into
main
Choose a base branch
from
chore/deterministic-threads
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
5cba59f
perf: parallelize and right-size the sequence-properties compute step
PaulNewling f16911a
perf: row-parallelize the pI bisection and vectorize the CDR3-length …
PaulNewling 3cb51b9
fix: size memFormula on max(lineCount, input bytes) to prevent long-s…
PaulNewling aace463
refactor: dedupe Fv 10**ph and derive the AA regex from STANDARD_AAS
PaulNewling f9037b2
fix: set POLARS_MAX_THREADS to the granted cores via {system.cpu}, no…
PaulNewling 947befb
docs: tighten changeset and code comments (clear-writing pass)
PaulNewling File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| --- | ||
| '@platforma-open/milaboratories.sequence-properties.software': patch | ||
| '@platforma-open/milaboratories.sequence-properties.workflow': patch | ||
| --- | ||
|
|
||
| Parallelize the compute step and size its resources to the input, keeping output byte-identical. | ||
|
|
||
| Memory now scales with the input: `memFormula(clamp(max(lineCount * perRow, size * 64), 2GiB, 64GiB))` replaces the flat `mem("12GiB")`. The two terms cover two cost sources — a row-scaled term for per-clone structures (count matrix, output columns, aa_fraction; measured ~3 KiB/row peptide, ~4.3 KiB/row antibody), and a residue-scaled term (`size` ≈ total residues) for the O(residues) cleaning transients. The size term keeps long-sequence/low-row inputs (amplicon variants) off the 2 GiB floor, where a `lineCount`-only formula would OOM them. Large datasets get the RAM they need; small ones stop over-reserving. A `fallback: "12GiB"` preserves the old behavior on backends that cannot evaluate formulas. | ||
|
|
||
| CPU scales with the input too: both modes request up to 4 cores (`cpuFormula`), matching their measured thread speedups (peptide ~1.7x, antibody ~1.5x). `POLARS_MAX_THREADS` — which sizes both the polars pool and the numpy pI-bisection workers — takes the cores the backend actually grants, via the `{system.cpu}` command expression, so a sub-cap allocation never oversubscribes its quota. A static `env` covers backends without command expressions. | ||
|
|
||
| Determinism holds regardless of core count. Polars parallelizes only order-stable work (CSV read, chain reconstruction, aa_fraction reshape, the unique-key sort, CSV write), and `main.py` pins the BLAS/OpenMP intra-op threads to 1 so the one order-sensitive step — the `counts @ weights` reduction — never splits across threads. The emitted bytes, and the resource CID, stay identical. | ||
|
|
||
| Compute-engine optimizations, all output-preserving: | ||
|
|
||
| - `_charge_raw` computes `10**ph` once and reuses it via scalar factors instead of a per-amino-acid `10**(ph±pk)` — ~2.4x faster on the charge/pI path (FP drift ~1e-15, absorbed by the 3-dp quantization). | ||
| - Peptide mode cleans its column once, sharing the intermediate between the count substrate and the instability index instead of cleaning twice. | ||
| - The count and instability scatters use `np.bincount` instead of the slower unbuffered `np.add.at` — bit-identical, ~3x faster. | ||
| - The per-chain median-CDR3-length stat uses a vectorized polars `count_matches` instead of one Python `effective_length` call per row. | ||
| - Peptide `aa_fraction` uses a polars unpivot instead of a 20×N Python-list explosion, cutting peak memory on the peptide path. | ||
| - The pI bisection (`isoelectric_point` / `fv_isoelectric_point`) runs row-parallel across threads — contiguous, data-independent blocks, each depending only on its own rows, so the result is bit-identical regardless of worker count. | ||
|
|
||
| Together these cut peptide compute ~2.3x and make antibody scale from ~1.1x to ~1.5x on 4 cores (10.0s → 4.6s at 1M rows). | ||
|
|
||
| Output stays within the quantized-equal contract, verified byte-for-byte between 1 and 4 threads by an extended determinism test and against the pre-change implementation (peptide and antibody, including edge cases). |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of
np.ascontiguousarrayhere is redundant. Since_na_to_nulliterates over the elements of the column slice to convertNaNvalues toNone(resulting in a Python list or object array), the memory contiguity of the input numpy array does not provide any performance benefit. Callingnp.ascontiguousarraycreates an unnecessary intermediate copy of the float array slice for each of the 20 columns, which wastes CPU cycles and memory allocations.