I'm trying to test variations of CPU and memory for a specific process (samtools sort
) to measure computational efficiency (measured only by time). To do this, I'd like to set the CPU and memory for a Nextflow
process
dynamically.
Ultimate question: How can I dynamically set CPU and memory for many instances of a single Nextflow
process definition?
Attempt 1
The most obvious solution was to submit distinct Nextflow
workflows for each combination of CPU and memory by specifying the CPU and memory on the command line (i.e., when calling nextflow run ...
), where my Nextflow
workflow has global parameters params.samtools_total_threads
and params.samtools_mem_per_thread
.
This didn't work perfectly because there appeared to be 'collisions' between parent Nextflow
instances trying to lock the history file. I got the following error:
Can't lock file: /path/to/project/.nextflow/history -- Nextflow needs to run in a file system that supports file locks
I could try delaying submissions, but I suspect that will still result in collisions.
Here's the SLURM
script that I'm using:
TOTAL_THREADS=$1
MEM_PER_THREAD=$2
nextflow run 02-SAMTOOLS_SORT.nf \
-with-report "reports/report.${TOTAL_THREADS}_threads.${MEM_PER_THREAD}_GB_per_thread.html" \
-with-trace "traces/trace.${TOTAL_THREADS}_threads.${MEM_PER_THREAD}_GB_per_thread.txt" \
--samtools_total_threads $TOTAL_THREADS \
--samtools_mem_per_thread $MEM_PER_THREAD
My workflow had the following global parameters:
/*
* Make this pipeline a nextflow 2 implementation
*/
nextflow.enable.dsl=2
...
params.samtools_total_threads = '4'
params.samtools_mem_per_thread = '8'
...
Attempt 2
After Attempt 1 failed, I figured the most 'Nextflow-like way' would be to generate tuples for each combination of CPU and memory that I want to test. Unfortunately, it doesn't appear that it's possible to set CPU and memory directives using parameters passed into the process
, but only with global variables.
I get the following No such variable
error with the below code (note: most of this code is courtesy of @Steve):
N E X T F L O W ~ version 21.04.3
Launching `02-SAMTOOLS_SORT.nf` [desperate_aryabhata] - revision: fb9e79055a
No such variable: total_threads
-- Check script '02-SAMTOOLS_SORT.nf' at line: 33 or see '.nextflow.log' file for more details
Process code
process samtools_coordinate_sort_proc {
tag { "${bam.baseName}" }
executor='slurm'
queue = 'normal'
cpus = total_threads
memory = total_mem.GB
clusterOptions = "--time 5:00:00 --account <account>"
/* delete files upon completion (I think) */
cleanup = true
input:
path(bam)
val(total_threads)
val(total_mem)
output:
path("${bam.baseName}.csorted.bam")
script:
def additional_threads = task.cpus - 1
def avail_mem = task.memory ? task.memory.toGiga().intdiv(task.cpus) : 0
println "avail_mem: $avail_mem"
def mem_per_thread = avail_mem ? "${avail_mem}G" : ''
println "mem_per_thread: $mem_per_thread"
"""
samtools sort \\
-@ "${additional_threads}" \\
-m ${mem_per_thread} \\
-o "${bam.baseName}.csorted.bam" \\
-T "${bam.baseName}.csorted" \\
--write-index \\
"${bam}"
"""
}
Possible attempt 3
Of course, it would be super easy to do this with a couple of bash
scripts, but I'm trying to do it in Nextflow
for two reasons:
- To learn
Nextflow
better - Because the traces provided by
Nextflow
are super convenient (though I could get this information fromSLURM
, too).