Changelog
prego 0.0.12
-
Fix: PWM scoring no longer needs
OMP_NUM_THREADS=1in the environment to avoid the thread explosion. 0.0.11 pinned the OpenMP thread count from R, which helped but could not finish the job:omp_set_num_threads()writes the calling thread’s libgomp ICV, while the workers that actually run the BLAS call are separate threads that inherit the untouched global one. The count is now pinned inside each worker thread itself, inPWMWorker::operator(), resolved viadlsymso prego still does not need to be built with OpenMP (and is a no-op where no OpenMP runtime is loaded).Measured standalone against the OpenBLAS conda ships (which links libgomp despite the
pinlibopenblasp-*.so), 16 threads each running adgemm: unpinned 54.91s at 2,034 OS threads; pinned per worker 0.08s at 1 thread - matchingOMP_NUM_THREADS=1set before the process starts (0.09s). End to end throughextract_pwm()over 20,000 x 500bp sequences and 20 motifs atset_parallel(16), on an idle 128-core node: 8.28s at 2,049 threads before, 2.03s at 17 threads after. The gap is far larger on a loaded machine, which is where this bites.Results are unchanged apart from floating-point reassociation inside
dgemm(max absolute difference 3.6e-15 over a 5,000 x 20 energy matrix, identical NA pattern), which is inherent to changing a BLAS thread count.
prego 0.0.11
-
Fix: the thread-explosion guard added in 0.0.10 did not actually work on an OpenMP-linked OpenBLAS - the
libopenblas-*-openmpbuild conda ships, and therefore what most lab environments run.RhpcBLASctl::blas_set_num_threads(1)reports success there while changing nothing:openblas_set_num_threads()is a no-op for that build andomp_get_max_threads()is what sizes the thread team.local_serial_blas()now pins the OpenMP thread count as well. Measured on a 128-core node,extract_pwm()over 3,000 x 500bp sequences and 20 motifs atset_parallel(16): unguarded and blas-pin-only both exceeded 600s at 2,049 OS threads and ~11,000% CPU (~80% of it system time); with the OpenMP pin, 4.8s.This does not close the gap completely.
omp_set_num_threads()writes the calling thread’s libgomp ICV, while the parallel workers that actually run the BLAS call are separate threads which still inherit the untouched global one. The same benchmark runs in 0.47s with 17 threads whenOMP_NUM_THREADS=1is set in the environment before R starts, so on a many-core machine that is still worth setting:OMP_NUM_THREADS=1 Rscript your_script.R. Note thatSys.setenv(OMP_NUM_THREADS = 1)inside the script cannot work - libgomp reads the variable in an ELF constructor at process load, long before R runs line 1. Pinning the count from inside the worker threads themselves would remove the need for the variable; that is worth doing but needs validating on a machine where the affected BLAS can be rebuilt against.
prego 0.0.10
- Fix:
compute_pwm()scoredN(and the*wildcard) inconsistently between strands - the forward strand used the column’s average log-probability while the reverse strand used a flatlog(0.25). Withbidirect = TRUEthis made a sequence and its reverse-complement score differently whenever anNfell on an informative position. Both strands now use the column average (get_avg_log_prob()), matching the other likelihood routines, so scoring is strand-symmetric again. Only affects sequences containingN/*. - Fix:
calc_seq_pwm()/extract_pwm()now error clearly when given sequences of unequal length instead of silently recycling the shorter ones (viarbind) and returning wrong scores. These functions build a single rectangular one-hot matrix and require equal-length sequences; for variable lengths usecompute_pwm(). - Fix: PWM scoring no longer opens thousands of threads / fails on core-limited machines.
compute_pwm(),compute_local_pwm()andcalc_seq_pwm()(henceextract_pwm()) run a small per-sequence BLASdgemminside an RcppParallel/TBBparallelFor. With a multi-threaded BLAS (MKL, OpenBLAS) each TBB worker spawned its own BLAS thread team, so one call openedn_threads * n_blas_threadsOS threads (thousands on a many-core node) - which oversubscribed the machine and could fail outright on a cluster job with a thread/process (cgroup pids) limit. The inner BLAS is now pinned to a single thread for the duration of these calls (the TBB loop over sequences is the parallelism layer), and the previous BLAS thread count is restored afterwards. Results are unchanged; throughput is the same or better. Adds a dependency on theRhpcBLASctlpackage. - Fix:
compute_pwm()gave a sequence a different score depending on the other sequences in the batch. The motif-scan window was capped to the length of the first sequence for the whole batch, so a longer sequence sitting behind a shorter one was only scanned over its firstnchar(sequences[1])positions and missed motif hits further along. Each sequence is now scored on its own full length, independently of its batch companions. - Added
return_allparameter toregress_pwm(multi-kmer path). When TRUE, returns every candidate-kmer regression (sorted by validation score) instead of just the best one - useful for getting N independent motifs without the residual-rounds approach used bymotif_num > 1. Whensample_for_kmers = TRUE, each candidate is refit on the full data. - Improved docs for
regress_pwm(clarified the three operating modes, fixedn_motifs/comb_modletypos in the return-value section).
prego 0.0.6
- Added
screen_local_pwmto find positions in sequences that match a PSSM. - Added
return_listparameter tocompute_local_pwm.
prego 0.0.5
- Faster pssm correlation computation using
RcppParallel. -
pssm_matchwhenbest=FALSEnow returns ascorefield instead ofcor. - Implemented computation of KL divergence between two PSSMs. Note that spearman correlation is still the best way to match PSSMs.