Giter Site home page Giter Site logo

henrikbengtsson / future.batchtools Goto Github PK

View Code? Open in Web Editor NEW
83.0 4.0 10.0 1.24 MB

:rocket: R package future.batchtools: A Future API for Parallel and Distributed Processing using batchtools

Home Page: https://future.batchtools.futureverse.org

Makefile 11.28% R 84.01% Shell 4.70%
r package hpc parallel distributed-computing torque slurm sge job-scheduler pbs

future.batchtools's Introduction

CRAN check status R CMD check status future.tests checks status Coverage Status

future.batchtools: A Future API for Parallel and Distributed Processing using 'batchtools'

Introduction

The future package provides a generic API for using futures in R. A future is a simple yet powerful mechanism to evaluate an R expression and retrieve its value at some point in time. Futures can be resolved in many different ways depending on which strategy is used. There are various types of synchronous and asynchronous futures to choose from in the future package.

This package, future.batchtools, provides a type of futures that utilizes the batchtools package. This means that any type of backend that the batchtools package supports can be used as a future. More specifically, future.batchtools will allow you or users of your package to leverage the compute power of high-performance computing (HPC) clusters via a simple switch in settings - without having to change any code at all.

For instance, if batchtools is properly configures, the below two expressions for futures x and y will be processed on two different compute nodes:

> library("future.batchtools")
> plan(batchtools_torque)
>
> x %<-% { Sys.sleep(5); 3.14 }
> y %<-% { Sys.sleep(5); 2.71 }
> x + y
[1] 5.85

This is just a toy example to illustrate what futures look like and how to work with them.

A more realistic example comes from the field of cancer research where very large data FASTQ files, which hold a large number of short DNA sequence reads, are produced. The first step toward a biological interpretation of these data is to align the reads in each sample (one FASTQ file) toward the human genome. In order to speed this up, we can have each file be processed by a separate compute node and each node we can use 24 parallel processes such that each process aligns a separate chromosome. Here is an outline of how this nested parallelism could be implemented using futures.

library("future")
library("listenv")
## The first level of futures should be submitted to the
## cluster using batchtools.  The second level of futures
## should be using multisession, where the number of
## parallel processes is automatically decided based on
## what the cluster grants to each compute node.
plan(list(batchtools_torque, multisession))

## Find all samples (one FASTQ file per sample)
fqs <- dir(pattern = "[.]fastq$")

## The aligned results are stored in BAM files
bams <- listenv()

## For all samples (FASTQ files) ...
for (ss in seq_along(fqs)) {
  fq <- fqs[ss]

  ## ... use futures to align them ...
  bams[[ss]] %<-% {
    bams_ss <- listenv()
	## ... and for each FASTQ file use a second layer
	## of futures to align the individual chromosomes
    for (cc in 1:24) {
      bams_ss[[cc]] %<-% htseq::align(fq, chr = cc)
    }
	## Resolve the "chromosome" futures and return as a list
    as.list(bams_ss)
  }
}
## Resolve the "sample" futures and return as a list
bams <- as.list(bams)

Note that a user who do not have access to a cluster could use the same script processing samples sequentially and chromosomes in parallel on a single machine using:

plan(list(sequential, multisession))

or samples in parallel and chromosomes sequentially using:

plan(list(multisession, sequential))

For an introduction as well as full details on how to use futures, please consult the package vignettes of the future package.

Choosing batchtools backend

The future.batchtools package implements a generic future wrapper for all batchtools backends. Below are the most common types of batchtools backends.

Backend Description Alternative in future package
batchtools_torque Futures are evaluated via a TORQUE / PBS job scheduler N/A
batchtools_slurm Futures are evaluated via a Slurm job scheduler N/A
batchtools_sge Futures are evaluated via a Sun/Oracle Grid Engine (SGE) job scheduler N/A
batchtools_lsf Futures are evaluated via a Load Sharing Facility (LSF) job scheduler N/A
batchtools_openlava Futures are evaluated via an OpenLava job scheduler N/A
batchtools_custom Futures are evaluated via a custom batchtools configuration R script or via a set of cluster functions N/A
batchtools_multicore parallel evaluation by forking the current R process plan(multicore)
batchtools_local sequential evaluation in a separate R process (on current machine) plan(cluster, workers = "localhost")

Examples

Below is an examples illustrating how to use batchtools_torque to configure the batchtools backend. For further details and examples on how to configure batchtools, see the batchtools configuration wiki page.

To configure batchtools for job schedulers we need to setup a *.tmpl template file that is used to generate the script used by the scheduler. This is what a template file for TORQUE / PBS may look like:

#!/bin/bash

## Job name:
#PBS -N <%= if (exists("job.name", mode = "character")) job.name else job.hash %>

## Direct streams to logfile:
#PBS -o <%= log.file %>

## Merge standard error and output:
#PBS -j oe

## Email on abort (a) and termination (e), but not when starting (b)
#PBS -m ae

## Resources needed:
<% if (length(resources) > 0) {
  opts <- unlist(resources, use.names = TRUE)
  opts <- sprintf("%s=%s", names(opts), opts)
  opts <- paste(opts, collapse = ",") %>
#PBS -l <%= opts %>
<% } %>

## Launch R and evaluated the batchtools R job
Rscript -e 'batchtools::doJobCollection("<%= uri %>")'

If this template is saved to file batchtools.torque.tmpl (without period) in the working directory or as .batchtools.torque.tmpl (with period) the user's home directory, then it will be automatically located by the batchtools framework and loaded when doing:

> plan(batchtools_torque)

Resource parameters can be specified via argument resources which should be a named list and is passed as is to the template file. For example, to request that each job would get alloted 12 cores (one a single machine) and up to 5 GiB of memory, use:

> plan(batchtools_torque, resources = list(nodes = "1:ppn=12", vmem = "5gb"))

To specify the resources argument at the same time as using nested future strategies, one can use tweak() to tweak the default arguments. For instance,

plan(list(
  tweak(batchtools_torque, resources = list(nodes = "1:ppn=12", vmem = "5gb")),
  multisession
))

causes the first level of futures to be submitted via the TORQUE job scheduler requesting 12 cores and 5 GiB of memory per job. The second level of futures will be evaluated using multisession using the 12 cores given to each job by the scheduler.

A similar filename format is used for the other types of job schedulers supported. For instance, for Slurm the template file should be named ./batchtools.slurm.tmpl or ~/.batchtools.slurm.tmpl in order for

> plan(batchtools_slurm)

to locate the file automatically. To specify this template file explicitly, use argument template, e.g.

> plan(batchtools_slurm, template = "/path/to/batchtools.slurm.tmpl")

For further details and examples on how to configure batchtools per se, see the batchtools configuration wiki page.

Demos

The future package provides a demo using futures for calculating a set of Mandelbrot planes. The demo does not assume anything about what type of futures are used. The user has full control of how futures are evaluated. For instance, to use local batchtools futures, run the demo as:

library("future.batchtools")
plan(batchtools_local)
demo("mandelbrot", package = "future", ask = FALSE)

Installation

R package future.batchtools is available on CRAN and can be installed in R as:

install.packages("future.batchtools")

Pre-release version

To install the pre-release version that is available in Git branch develop on GitHub, use:

remotes::install_github("HenrikBengtsson/future.batchtools", ref="develop")

This will install the package from source.

Contributing

To contribute to this package, please see CONTRIBUTING.md.

future.batchtools's People

Contributors

gara-z avatar henrikbengtsson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

future.batchtools's Issues

Socket timed out on send/recv operation

Im unsure if this issue should be posted here since I would guess that it is probably an issue with batchtools but since I am getting the error via future.batchtools I will start here....

Background and details:

I am currently developing a package which includes a function that uses future_lapply. I have a script that performs some testing (i.e. loads packages and data, plans the future, and calls the function in my package that utilises future_lapply). I run the script on the log-in node of the remote HPC as follows:

Rscript --vanilla my_script.R &> logs.txt &

Within my_script.R the future is planned with the following:

future::plan(
  future.batchtools::batchtools_slurm,
  template = "/crex/proj/snic2018-8-151/private/batchtools.slurm.tmpl",
  resources = list(
    account = "snic2018-8-151", partition = "core", ntasks = 1L,
    time = "24:00:00", jobname = "testingPoissonSorted",
    modules = "R_packages/3.5.0", R = "R/3.5.0", log.file = file.path(currPath, "logs/slurm.txt")
 ))

And my batchtools template includes:

\#!/bin/bash                                                                                                                                                                                                                                                    

\#SBATCH --job-name=<%= resources$jobname %>                                                                                                                                                                                                                    
\#SBATCH --time=<%= resources$time %>                                                                                                                                                                                                                           
\#SBATCH --ntasks=<%= resources$ntasks %>                                                                                                                                                                                                                       
\#SBATCH --account=<%= resources$account %>                                                                                                                                                                                                                     
\#SBATCH --partition=<%= resources$partition %>                                                                                                                                                                                                                 
\#SBATCH --output=<%= resources$log.file %>                                                                                                                                                                                                                     
                                                                                                                                                                                                                     
source /etc/profile                                                                                                                                                                                  
module add <%= paste(resources$modules, resources$R) %>                                                                                                                                        
Rscript -e 'batchtools::doJobCollection("<%= uri %>")'

Error and "expected" response:

While testing the package on a Slurm-based system I get the following error (reported in logs.txt):

Error in OSError("Listing of jobs failed", res) :
Listing of jobs failed (exit code 1);
cmd: 'squeue --user=$USER --states=R,S,CG --noheader --format=%i -r'
output:
slurm_load_jobs error: Socket timed out on send/recv operation
Calls: spSwarm ... unique -> -> listJobs -> OSError -> stopf
Execution halted

It seems that this arises when the schedular is "busy" and, I am guessing, the communication between batchtools and slurm times out. Since the jobs have already started, they continue to run until completion although, because of the apparent "disconnection" between batchtools and slurm, the output from the run (saved downstream in the script after the call to future_lapply) is never generated. This is somewhat painful for those of us working on a limited number of core hours per month as the hours get "spent" without any "result" being generated.

After a bit of looking around it would seem that the sysadmins may be able to help prevent this (bug report) but, in my humble opinion, it would also be ideal if a) the user can do something to increase the time that future/batchtools waits for a response from the schedular or b) that the jobs are automatically canceled if batchtools looses contact with the schedular (potentially problematic since contact is lost).

For the sake of completeness the output from batchtools (?) is included below:

WARNING: ignoring environment value of R_HOME
[bt]: This is batchtools v0.9.10
[bt]: Starting calculation of 1 jobs
[bt]: Setting working directory to '/crex/proj/snic2018-8-151/private/CIMseq/testingPoissonMouse'
Loading required package: sp.scRNAseq
[bt]: Memory measurement disabled
[bt]: Starting job [batchtools job.id=1]
[bt]: Setting seed to 1 ...

[bt]: Job terminated successfully [batchtools job.id=1]
[bt]: Calculation finished!

[bt]: Job terminated successfully [batchtools job.id=1]
[bt]: Calculation finished!

Disclaimer:

I wouldn't consider myself an experienced HPC/future/batchtools user and this could be potentially "all my fault" and painfully obvious to more experienced users and, if that is the case, hopefully submitting this issue will guide others of a similar experience level in the right direction in the future .

Kind Regards,
Jason

Jobs are submitted succesfully, but only runs on head node

I am trying to get the future.batchtools and doFuture to run on my Rocks 7 cluster, but it is only running the jobs on the head node. I can see the submitted jobs and all of the allocations in sview, but nothing is running on the nodes..
Got any pointers?

setting strategy to mimic rmpi/dompi

is there an analogous setting in future::plan for rmpi?

library(parallel) 
hello_world <- function() { 
## Print the hostname and MPI worker rank. 
paste(Sys.info()["nodename"],Rmpi::mpi.comm.rank(), sep = ":") 
} 

cl <- makeCluster(Sys.getenv()["SLURM_NTASKS"], type = "MPI") 
clusterCall(cl, hello_world) 
stopCluster(cl)

where the plan is set on the workers and the call to slurm/grid is done via bash template.

WISH: Try to report on scheduler-specific errors (e.g. 'PBS: job killed')

For instance, a PBS job with -l vmem=1gb gave:

$ tail /home/henrik/projects/tests/.future/20170626_111627-54Dsqf/sample_1_38265500/logs/joba810736cd1202b8e75d829f18ca5d611.log
[...]
 Chromosome 'M'...done
pileup2seqz...done
=>> PBS: job killed: vmem 1076252672 exceeded limit 1073741824

Finding underlying PBS errors like this one requires inspecting the output logs. Can we add some ad hoc inspection up errors that picks this up?

BUG in future.batchtools (= 0.7.0): Error in readLog(id, reg = reg)

I introduced a bug in future.batchtools (= 0.7.0) released on 2018-05-04. I can reproduce it on a Torque/PBS cluster, but not on an SGE cluster although I expect that it could/should appear everywhere. Example:

library(future.batchtools)
plan(batchtools_torque)
y <- future.apply::future_lapply(1:3, FUN = identity)
# Error in readLog(id, reg = reg) :
#   Log file for job with id 1 not available

This should have been caught by my local pre-release tests, but due to a mistake of mine I've disabled the tests that actually run future.batchtools on HPC schedulers. The only tests running was relying on the batchtools_local backend.

"Submission rate too high" with a large future_lapply

My SLURM system got upset when submitting a large number of jobs:

Error in batchtools::submitJobs(reg = reg, ids = jobid, resources = resources) :
  Fatal error occurred: 101. Command 'sbatch' produced exit code 1. Output: 'sbatch: error: Submission rate too high, suggest using job arrays
sbatch: error: Batch job submission failed: Unspecified error'

Perhaps one could solve this with an interface to the sleep option in batchtools::submitJobs?

steps to speed up job submission?

I'm using future.batchtools via drake, and just got my first plan running on the cluster. It seems to take about one minute for each job submitted, and since I'm trying to submit several hundred jobs, that's not ideal (although it's not a deal-breaker, because I expect each job to take many hours to finish). I'm not sure what I might be able to change in order to speed this up. I haven't dived into the code, but my idea of what needs to happen to start a worker is:

  1. analyse the code to find dependencies
  2. submit the job to the scheduler (SLURM in my case)
  3. wait for the job to be allocated
  4. wait for the worker to start up (and load libraries?)
  5. send data to the worker (and libraries?)

Is this basically accurate?

Does the worker load libraries already installed on its node, or are all libraries sent to the worker by the master? If the latter, then reducing library dependencies seems like a potential avenue to try.

rscript object missing under nested future topology (login->cluster->session)

I'm trying to do a nested future topology with torque cluster. However, when I run the code I'm getting the error of:

Error: Error brewing template: Error in cat(rscript) : object 'rscript' not found

I've modified the example here:

https://cran.r-project.org/web/packages/future/vignettes/future-3-topologies.html

With information given in the future.batchtools vignette:

https://cran.r-project.org/web/packages/future.batchtools/vignettes/future.batchtools.html

In particular, I'm using:

library("future")
library("future.batchtools")
library("listenv")

## Specify future topology
## login node -> { cluster nodes } -> { multiple cores }
plan(
  list(
    tweak(remote, workers = c("[email protected]")),
    batchtools_torque,
    multiprocess
    )
)

## (a) This will be evaluated on the cluster login computer
x %<-% {
  thost <- Sys.info()[["nodename"]]
  tpid <- Sys.getpid()
  y <- listenv()
  for (task in 1:4) {
    
    ## (b) This will be evaluated on a compute node on the cluster
    y[[task]] %<-% {
      mhost <- Sys.info()[["nodename"]]
      mpid <- Sys.getpid()
      z <- listenv()
      for (jj in seq_len(availableCores())) {
        ## (c) These will be evaluated in separate processes on the same compute node
        z[[jj]] %<-% data.frame(task = task,
                                top.host = thost, top.pid = tpid,
                                mid.host = mhost, mid.pid = mpid,
                                host = Sys.info()[["nodename"]],
                                pid = Sys.getpid())
      }
      Reduce(rbind, z)
    }
  }
  Reduce(rbind, y)
}

# Check to see if the job is done and display values if so:
if( resolved(futureOf(x)) ) print(x)

I've used the template ~/.batchtools.torque.tmpl:

## Job name:
#PBS -N <%= job.name %>

## Merge standard error and output:
#PBS -j oe

## Resource parameters:
<% for (name in names(resources)) { %>
#PBS -l <%= name %>=<%= resources[[name]] %>
<% } %>

## Run R:
R CMD BATCH --no-save --no-restore "<%= rscript %>" /dev/stdout

Within the last line, I don't think that rscript variable is being set. Is future generating an R script with the topology and then executing? This is also different from the .pbs template configuration shipping with batchtools:

https://github.com/mllg/batchtools/blob/fc896b349e86456506387b1a5cabba7e09f1a09f/inst/templates/torque-lido.tmpl#L76-L77

Loading back results from workers to the master process

Hello @HenrikBengtsson when I use the slurm backend and generate tables (data.frame) as a result I have the impression that getting back the results is very slow and that this is due to how data is "ingested" back to the master process. By looking at the .future dir ectory I see .RDS files which might be a reason.

If I am not totally wrong:

In case of data.frame I think reading/writing fst files would give us at least a order of magnitude speed up.

  • would you consider using fst in cases of data.frame outputs ?
  • if yes would you point me to the code and I'll try to write a pull request

Collect MaxRSS/Elapsed from sacct when using SLURM?

I imagine a wide problem in using HPC systems is not knowing how much memory or walltime to allocate. I imagine this not knowing the right amounts (of memory especially) causes huge amounts of wasted resources on HPC systems. I know it does in my workflow.

SLURM returns MaxRSS/Elapsed value for each job after completion which future.batchtools could store in .future/20171118_083108-ebBlfz/.

I'm eventually imagining a function exported from drake that could report on these somehow.

Add support for controlling the submission rate of jobs

Add support for controlling the submission rate of jobs, by exposing the sleep argument of batchtools::submitJobs() in one way or the other, e.g. plan(batchtools_slurm, sleep = 5) for 5 seconds between each job submission.

It's possible that this should/could be implemented in the Future API (HenrikBengtsson/future#172) and if so, then maybe the default should be controllable via ?future.options.

Related to Issue #13.

Future ('<none>') expired

Hey Henrik,

I'm using future.batchtools to submit jobs to a HPC with LSF. When only submitting a rather small amount of jobs everything is running smoothly, however, if I increase the number of submitted jobs I get the following error:

Error: BatchtoolsExpiration: Future ('<none>') expired (registry path /home/uni08/hesselbarth3/.future/20180901_172706-Dvm4Cm/batchtools_1849950729).. The last few lines of the logged output:
    Max Swap :                                   -
    Max Processes :                              1
    Max Threads :                                1
    Run time :                                   9 sec.
    Turnaround time :                            14 sec.
The output (if any) follows:

When looking into the .future - folder many jobs seem to be alright, but still at least one job is failing with the following log

TERM_EXTERNAL_SIGNAL: job killed by a signal external to LSF.
Exited with signal termination: Killed.

Resource usage summary:

    CPU time :                                   0.07 sec.
    Max Memory :                                 15 MB
    Average Memory :                             15.00 MB
    Total Requested Memory :                     -
    Delta Memory :                               -
    Max Swap :                                   -
    Max Processes :                              1
    Max Threads :                                1
    Run time :                                   9 sec.
    Turnaround time :                            14 sec.

The output (if any) follows:

I use future.batchtools_0.7.1-9000, future_1.9.0 and furrr_0.1.0.

Add batchtools_custom

Add batchtools_custom(), cf. Add batchjobs_custom(). With this, it should be possible to do:

  • plan(batchtools_custom) - locates a configuration file using the rules of batchtools.
  • plan(batchtools_custom, pathname = pn) - specific configuration file.

Should 'workers = <character>' be allowed?

Hmm... It's possible to do

> library(future.batchtools)
> plan(batchtools_local, workers = c("a", "b"))
> nbrOfWorkers()
> f <- future(42)
> value(f)
[1] 42

Is this a cut'n'paste mistake? Should mode(workers) == "character" be supported?

Comment: This was detected thanks to the future.tests package.

array.jobs supported for SLURM systems?

I'm trying to use future.batchtools with a SLURM system that heavily suggests using array jobs: e.g. makeClusterFunctionsSlurm(...,array.jobs=T) but I can't seem to figure out how to pass that option via future.batchtools. Any ideas?

Odd problem running on SGE cluster

Running a simple test script (shown below), I get the following traceback that I struggle to understand given that batchtools is installed and loads as every relevant user (the one I run on, the one that cluster is installed as, and even as the superuser):

Error: BatchtoolsExpiration: Future ('doFuture-1') expired (registry path /home/ubuntu/.future\
/20200402_130544-NJ8uMS/doFuture-1_26047096).. The last few lines of the logged output:
/var/spool/sge/ip-172-31-131-71/job_scripts/22: 14: /var/spool/sge/ip-172-31-131-71/job_scripts/22: $: not found
Error in loadNamespace(name) : there is no package called โ€˜batchtoolsโ€™
Calls: :: ... tryCatch -> tryCatchList -> tryCatchOne -> <Anonymous>
Execution halted

I'd be really grateful for any pointers in terms of what to check. I've tried reinstalling every single one of the future/doFuture/future.batchtools packages, by the way.

The test script follows:

library("doFuture")
registerDoFuture()
library("future.batchtools")
plan(batchtools_sge(template = "sge.tmpl", workers=2, resources=list(
                                                          queue="all.q")))

##foo = makeClusterFunctionsSGE(template = "sge.tmpl", nodename = "ec2-34-227-92-59.compute-1.amazonaws.com", scheduler.latency = 1, fs.latency = 65)                                                        
mu <- 1.0
sigma <- 2.0
cat(Sys.info())
x <- foreach(i = 1:3, .export = c("mu", "sigma")) %dopar% {
    system('hostname')
}

Setting export compression

I was wondering if there was any update on incorporating user defined registry compression in future.batchools (mllg/batchtools#245). It seems like batchtools wants the compression type to be specified in an external configuration file, which is passed as an argument during registry creation. Is it possible for future.batchtools to readily interface with this type of setup or is additional development needed on batchtools?

Error: BatchtoolsExpiration: Future ('<none>')

I'm getting the following error:

Error: BatchtoolsExpiration: Future ('<none>') expired (registry path /ebio/abt3_projects/Georg_animal_feces/notebooks/metagenome/HiSeqRuns126-133-0138/wOutVertebrata/.future/20190618_182726-1H71fL/batchtools_929120591).. The last few lines of the logged output:
### [bt]: Setting working directory to '/ebio/abt3_projects/Georg_animal_feces/notebooks/metagenome/HiSeqRuns126-133-0138/wOutVertebrata'
Loading required package: methods
### [bt]: Memory measurement disabled
### [bt]: Starting job [batchtools job.id=1]
### [bt]: Setting seed to 1 ...
rmdir: failed to remove '/dev/cpuset/': Device or resource busy
Traceback:

1. future_lapply(as.list(cmds), FUN = function(x) bash_job(x, conda_env = conda_env))
2. values(fs)
3. values.list(fs)
4. value(tmp, ...)
5. value.Future(tmp, ...)
6. result(future)
7. result.BatchtoolsFuture(future)
8. await(future, cleanup = FALSE)
9. await.BatchtoolsFuture(future, cleanup = FALSE)

My resources are set as:

# job resources
resources = list(h_rt = '00:59:00',
                 h_vmem = '10G',
                 threads = 12,
                 conda.env = 'py3_physeq')     # conda env with batchtools installed
plan(batchtools_sge, resources=resources, workers=30)

It appears that 320 of the 340 jobs failed. Re-running is easiest, but what a waste to re-run so many jobs...

I see that a similar issue has been reported (#31 ), but the suggested solution was to reduce the number of workers. I'm only running 30 workers.

conda env

_r-mutex                  1.0.0               anacondar_1
appdirs                   1.4.3                      py_1    conda-forge
asn1crypto                0.24.0                     py_1    conda-forge
attrs                     18.1.0                     py_1    conda-forge
automat                   0.7.0                    py36_0    conda-forge
backcall                  0.1.0                      py_0    conda-forge
bioconductor-biobase      2.38.0                 r3.4.1_0    bioconda
bioconductor-biocgenerics 0.24.0                 r3.4.1_0    bioconda
bioconductor-biomformat   1.6.0                  r3.4.1_0    bioconda
bioconductor-biostrings   2.46.0                 r3.4.1_0    bioconda
bioconductor-iranges      2.12.0                 r3.4.1_0    bioconda
bioconductor-multtest     2.34.0                 r3.4.1_0    bioconda
bioconductor-phyloseq     1.22.3                 r3.4.1_0    bioconda
bioconductor-rhdf5        2.22.0                 r3.4.1_0    bioconda
bioconductor-s4vectors    0.16.0                 r3.4.1_0    bioconda
bioconductor-xvector      0.18.0                 r3.4.1_0    bioconda
bioconductor-zlibbioc     1.24.0                 r3.4.1_0    bioconda
blas                      1.1                    openblas    conda-forge
bleach                    2.1.3                      py_0    conda-forge
bzip2                     1.0.6                h470a237_2    conda-forge
ca-certificates           2019.3.9             hecc5488_0    conda-forge
cairo                     1.14.12              he56eebe_3    conda-forge
certifi                   2019.3.9                 py36_0    conda-forge
cffi                      1.11.5           py36h5e8e0c9_1    conda-forge
constantly                15.1.0                     py_0    conda-forge
cryptography              2.3              py36hdffb7b8_0    conda-forge
cryptography-vectors      2.3                      py36_1    conda-forge
curl                      7.61.0               h93b3f91_1    conda-forge
decorator                 4.3.0                      py_0    conda-forge
entrypoints               0.2.3                    py36_1    conda-forge
fontconfig                2.13.0               h0c61d53_4    conda-forge
freetype                  2.8.1                hfa320df_1    conda-forge
gettext                   0.19.8.1                      0    conda-forge
glib                      2.55.0               h464dc38_2    conda-forge
gmp                       6.1.2                hfc679d8_0    conda-forge
graphite2                 1.3.11               hfc679d8_0    conda-forge
gsl                       2.2.1           blas_openblas_4  [blas_openblas]  conda-forge
harfbuzz                  1.8.5                h2bb21d5_0    conda-forge
html5lib                  1.0.1                      py_0    conda-forge
hyperlink                 17.3.1                     py_0    conda-forge
icu                       58.2                 hfc679d8_0    conda-forge
idna                      2.7                      py36_2    conda-forge
incremental               17.5.0                     py_0    conda-forge
ipykernel                 4.8.2                    py36_0    conda-forge
ipython                   6.5.0                    py36_0    conda-forge
ipython_genutils          0.2.0                      py_1    conda-forge
jedi                      0.12.1                   py36_0    conda-forge
jinja2                    2.10                       py_1    conda-forge
jpeg                      9c                   h470a237_0    conda-forge
jsonschema                2.6.0                    py36_1    conda-forge
jupyter_client            5.2.3                      py_1    conda-forge
jupyter_core              4.4.0                      py_0    conda-forge
krb5                      1.14.6                        0    conda-forge
libffi                    3.2.1                         3    conda-forge
libgcc                    7.2.0                h69d50b8_2
libgcc-ng                 7.2.0                hdf63c60_3
libgfortran               3.0.0                         1
libgfortran-ng            7.2.0                hdf63c60_3
libiconv                  1.15                 h470a237_1    conda-forge
libopenblas               0.2.20               h9ac9557_7
libpng                    1.6.35               ha92aebf_0    conda-forge
libsodium                 1.0.16                        0    conda-forge
libssh2                   1.8.0                h5b517e9_2    conda-forge
libstdcxx-ng              7.2.0                hdf63c60_3
libtiff                   4.0.9                he6b73bb_1    conda-forge
libuuid                   1.0.3                         1    conda-forge
libxcb                    1.13                 h470a237_2    conda-forge
libxml2                   2.9.8                h422b904_2    conda-forge
markupsafe                1.0                      py36_0    conda-forge
mistune                   0.8.3            py36h470a237_2    conda-forge
nb_conda                  2.2.1                    py36_0    conda-forge
nb_conda_kernels          2.1.1                    py36_1    conda-forge
nbconvert                 5.3.1                      py_1    conda-forge
nbformat                  4.4.0                      py_1    conda-forge
ncurses                   6.1                  hfc679d8_1    conda-forge
notebook                  5.6.0                    py36_0    conda-forge
numpy                     1.15.0          py36_blas_openblashd3ea46f_200  [blas_openblas]  conda-forge
openblas                  0.2.20                        8    conda-forge
openssl                   1.0.2p               h470a237_2    conda-forge
pandas                    0.23.4           py36hf8a1672_0    conda-forge
pandoc                    2.2.2                         1    conda-forge
pandocfilters             1.4.2                      py_1    conda-forge
pango                     1.40.14              h9105a7a_2    conda-forge
parso                     0.3.1                      py_0    conda-forge
pcre                      8.41                 h470a237_2    conda-forge
pexpect                   4.6.0                    py36_0    conda-forge
pickleshare               0.7.4                    py36_0    conda-forge
pip                       18.0                     py36_1    conda-forge
pixman                    0.34.0                        2    conda-forge
prometheus_client         0.3.0                      py_0    conda-forge
prompt_toolkit            1.0.15                   py36_0    conda-forge
pthread-stubs             0.4                  h470a237_1    conda-forge
ptyprocess                0.6.0                    py36_0    conda-forge
pyasn1                    0.4.4                      py_0    conda-forge
pyasn1-modules            0.2.1                      py_0    conda-forge
pycparser                 2.18                       py_1    conda-forge
pygments                  2.2.0                      py_1    conda-forge
pyhamcrest                1.9.0                      py_2    conda-forge
pyopenssl                 18.0.0                   py36_0    conda-forge
python                    3.6.6                h5001a0f_0    conda-forge
python-dateutil           2.7.3                      py_0    conda-forge
pytz                      2018.5                     py_0    conda-forge
pyzmq                     17.1.0           py36hae99301_0    conda-forge
r-ade4                    1.7_11           r341hc070d10_0    conda-forge
r-ape                     5.1              r341hfc679d8_1    conda-forge
r-assertthat              0.2.0                  r3.4.1_0    conda-forge
r-backports               1.1.2            r341hc070d10_1    conda-forge
r-base                    3.4.1                h4fe35fd_8    conda-forge
r-base64enc               0.1_3            r341h470a237_1    conda-forge
r-base64url               1.4              r341hc070d10_1    conda-forge
r-batchtools              0.9.11           r341hc070d10_0    conda-forge
r-bh                      1.66.0_1               r3.4.1_0    conda-forge
r-bindr                   0.1.1                  r3.4.1_0    conda-forge
r-bindrcpp                0.2.2            r341h9d2a408_0    conda-forge
r-bit                     1.1_12           r341h470a237_1    conda-forge
r-bit64                   0.9_5            r341h470a237_1    conda-forge
r-blob                    1.1.1                  r3.4.1_0    conda-forge
r-brew                    1.0_6            r341h6115d3f_1    conda-forge
r-broom                   0.5.0            r341h6115d3f_2    conda-forge
r-cellranger              1.1.0            r341h6115d3f_1    conda-forge
r-checkmate               1.8.5            r341hc070d10_2    conda-forge
r-cli                     1.0.0                  r3.4.1_0    conda-forge
r-cluster                 2.0.6                  r3.4.1_0    conda-forge
r-codetools               0.2_15                 r3.4.1_0    conda-forge
r-colorspace              1.3_2            r341h470a237_1    conda-forge
r-crayon                  1.3.4                  r3.4.1_0    conda-forge
r-curl                    3.2              r341hc070d10_2    conda-forge
r-data.table              1.11.4           r341hc070d10_0    conda-forge
r-dbi                     1.0.0                    r341_0    conda-forge
r-dbplyr                  1.2.2                    r341_0    conda-forge
r-dichromat               2.0_0                  r3.4.1_0    conda-forge
r-digest                  0.6.15           r341h470a237_1    conda-forge
r-doparallel              1.0.11                 r3.4.1_0    conda-forge
r-dplyr                   0.7.6            r341h9d2a408_0    conda-forge
r-evaluate                0.10.1                 r3.4.1_0    conda-forge
r-foreach                 1.4.4                  r3.4.1_0    conda-forge
r-fs                      1.2.6            r341h9d2a408_0    conda-forge
r-future                  1.9.0            r341h6115d3f_1    conda-forge
r-future.apply            1.0.0                    r341_0    conda-forge
r-future.batchtools       0.7.1            r341h6115d3f_0    conda-forge
r-gdtools                 0.1.7            r341h6843883_0    conda-forge
r-ggally                  1.4.0            r341h6115d3f_0    conda-forge
r-ggplot2                 3.0.0            r341h6115d3f_0    conda-forge
r-globals                 0.12.2           r341h6115d3f_0    conda-forge
r-glue                    1.3.0            r341h470a237_1    conda-forge
r-gridbase                0.4_7                  r3.4.1_0    conda-forge
r-gtable                  0.2.0                  r3.4.1_0    conda-forge
r-hexbin                  1.27.2           r341ha44fe06_1    conda-forge
r-hms                     0.4.2            r341h6115d3f_0    conda-forge
r-htmltools               0.3.6            r341hfc679d8_1    conda-forge
r-igraph                  1.2.1            r341h26a2512_1    conda-forge
r-irdisplay               0.4.4                  r3.4.1_0    conda-forge
r-irkernel                0.8.12                   r341_0    conda-forge
r-irlba                   2.3.2            r341h470a237_1    conda-forge
r-iterators               1.0.10                   r341_0    conda-forge
r-jsonlite                1.5              r341h470a237_1    conda-forge
r-labeling                0.3                    r3.4.1_0    conda-forge
r-lattice                 0.20_34                r3.4.1_0    conda-forge
r-lazyeval                0.2.1            r341h470a237_1    conda-forge
r-listenv                 0.7.0            r341h6115d3f_1    conda-forge
r-magrittr                1.5                    r3.4.1_0    conda-forge
r-maps                    3.3.0            r341h470a237_1    conda-forge
r-mass                    7.3_50           r341hc070d10_1    conda-forge
r-matrix                  1.2_14           r341h470a237_1    conda-forge
r-memoise                 1.1.0                  r3.4.1_0    conda-forge
r-mgcv                    1.8_24           r341h470a237_1    conda-forge
r-munsell                 0.5.0                    r341_0    conda-forge
r-nlme                    3.1_131          r341ha44fe06_1    conda-forge
r-nmf                     0.21.0           r341hfc679d8_1    conda-forge
r-pbdzmq                  0.3_2                  r3.4.1_0    conda-forge
r-permute                 0.9_4                  r3.4.1_1    conda-forge
r-pillar                  1.2.2            r341h6115d3f_1    conda-forge
r-pkgconfig               2.0.1                  r3.4.1_0    conda-forge
r-pkgmaker                0.22                   r3.4.1_0    conda-forge
r-plogr                   0.2.0            r341h6115d3f_0    conda-forge
r-plyr                    1.8.4            r341hfc679d8_1    conda-forge
r-prettyunits             1.0.2                  r3.4.1_0    conda-forge
r-progress                1.2.0            r341h6115d3f_2    conda-forge
r-purrr                   0.2.4            r341h470a237_1    conda-forge
r-r6                      2.2.2                  r3.4.1_0    conda-forge
r-rappdirs                0.3.1            r341hc070d10_2    conda-forge
r-rcolorbrewer            1.1_2                  r3.4.1_0    conda-forge
r-rcpp                    0.12.17          r341h9d2a408_1    conda-forge
r-readxl                  1.1.0            r341h9d2a408_2    conda-forge
r-registry                0.5                    r3.4.1_0    conda-forge
r-rematch                 1.0.1            r341h6115d3f_1    conda-forge
r-repr                    0.15                     r341_0    conda-forge
r-reshape                 0.8.7            r341hc070d10_2    conda-forge
r-reshape2                1.4.3            r341hfc679d8_1    conda-forge
r-rlang                   0.2.1            r341h470a237_1    conda-forge
r-rngtools                1.3.1                    r341_0    conda-forge
r-rsqlite                 2.0              r341hfc679d8_1    conda-forge
r-scales                  0.5.0            r341hfc679d8_1    conda-forge
r-stringi                 1.2.3            r341hfc679d8_1    conda-forge
r-stringr                 1.3.1                    r341_0    conda-forge
r-survival                2.42_6                   r341_0    conda-forge
r-svglite                 1.2.1            r341h9d2a408_0    conda-forge
r-tibble                  1.4.2            r341h470a237_1    conda-forge
r-tidyr                   0.8.1            r341hfc679d8_1    conda-forge
r-tidyselect              0.2.4            r341hfc679d8_1    conda-forge
r-utf8                    1.1.3            r341h470a237_1    conda-forge
r-uuid                    0.1_2                    r341_0    conda-forge
r-vegan                   2.4_3                  r3.4.1_0    conda-forge
r-viridislite             0.3.0                  r3.4.1_0    conda-forge
r-withr                   2.1.1                  r3.4.1_0    conda-forge
r-xtable                  1.8_2                  r3.4.1_0    conda-forge
readline                  7.0                  haf1bffa_1    conda-forge
rpy2                      2.9.4           py36r341h24bf2e0_0    conda-forge
send2trash                1.5.0                      py_0    conda-forge
service_identity          17.0.0                     py_0    conda-forge
setuptools                40.0.0                   py36_1    conda-forge
simplegeneric             0.8.1                      py_1    conda-forge
six                       1.11.0                   py36_1    conda-forge
sqlite                    3.24.0               h2f33b56_0    conda-forge
terminado                 0.8.1                    py36_0    conda-forge
testpath                  0.3.1                    py36_0    conda-forge
tk                        8.6.8                         0    conda-forge
tornado                   5.1              py36h470a237_1    conda-forge
traitlets                 4.3.2                    py36_0    conda-forge
twisted                   18.7.0           py36h14c3975_1
tzlocal                   1.5.1                      py_0    conda-forge
wcwidth                   0.1.7                      py_1    conda-forge
webencodings              0.5                      py36_0    conda-forge
wheel                     0.31.1                   py36_1    conda-forge
xorg-kbproto              1.0.7                h470a237_2    conda-forge
xorg-libice               1.0.9                h470a237_4    conda-forge
xorg-libsm                1.2.2                h470a237_5    conda-forge
xorg-libx11               1.6.5                h470a237_2    conda-forge
xorg-libxau               1.0.8                h470a237_6    conda-forge
xorg-libxdmcp             1.1.2                h470a237_7    conda-forge
xorg-libxext              1.3.3                h470a237_4    conda-forge
xorg-libxrender           0.9.10               h470a237_2    conda-forge
xorg-libxt                1.1.5                h470a237_2    conda-forge
xorg-renderproto          0.11.1               h470a237_2    conda-forge
xorg-xextproto            7.3.0                h470a237_2    conda-forge
xorg-xproto               7.0.31               h470a237_7    conda-forge
xz                        5.2.4                h470a237_1    conda-forge
zeromq                    4.2.5                hfc679d8_5    conda-forge
zlib                      1.2.11               h470a237_3    conda-forge
zope.interface            4.5.0            py36h470a237_0    conda-forge

Request: add support for preemption

For schedulers like SLURM, preemptible jobs are really nice. Many University computing resources have a lot of spare computing power for preemptible jobs and having functionality from future.batchtools to support them (and re-schedule them if anything went wrong) would be fantastic.

WISH: Limit default number of workers (instead of +Inf)

The default number of workers for HPC schedulers is +Inf. This treats the job queue and the compute resources as infinite. It's an ok choice by design.

However, because of this, there is the risk that one submits 1000's of jobs by mistake, which brings a lot of overhead to some schedulers.

An alternative is to set a default, say, 500, which can then be controlled by an R option as well as an environment variable;

workers = as.integer(getOption("future.batchtools.workers = Sys.getenv("R_FUTURE_BATCHTOOLS_WORKERS", 500L)))

The env var allows sys adms to limit this further, if needed.

BUG: Argument 'workers' cannot be a function

> library(future.batchtools)
> f <- batchtools_local(42L, workers = function() 1L)
Error in !res_ii : invalid argument type

> traceback()
3: stop_if_not("Argument 'workers' should be either numeric or character: ", 
       mode(workers))
2: BatchtoolsFuture(expr = expr, envir = envir, substitute = FALSE, 
       globals = globals, label = label, workers = workers, cluster.functions = cf, 
       ...)
1: batchtools_local(42L, workers = function() 1L)

as well as:

> library(future.batchtools)
> plan(batchtools_local, workers = function() 1L)
Error in nbrOfWorkers.batchtools(plan("next")) : 
 Invalid data type of 'workers': function

Turns out there are several bugs here, but should be easy to fix.

Comment: This was detected thanks to the future.tests package.

setting the finalize option in tweak [options future.delete = FALSE]

looking at the documentation of batchtools_template there is the dots argument which passes additional arguments passed toย BatchtoolsFuture(). which in there there is a finalize argument which If TRUE, any underlying registries are deleted when this object is garbage collected, otherwise not. I want to use this argument to keep future from removing the files after a call to a sungrid is complete.

I have tried to use the options below, but can not toggle the garbage collection off.

library(future)
library(batchtools)
library(future.batchtools)
library(future.apply)

options(future.finalize = FALSE)  
options(future.delete = FALSE)

my_sge <- future::tweak(
  future.batchtools::batchtools_sge,
  label = 'test2',
  template = 'batchtools.sge-new.tmpl',
  workers = 3,
  resources = list(slots = 4))

future::plan(list(multiprocess, my_sge))

Y1 %<-% future.apply::future_lapply(rep(800, 20),
                      FUN = function(nr){
                        solve( matrix(rnorm(nr^2), nrow=nr, ncol=nr))
                      })

if i try to set it in tweak i get the following warning, which makes sense too

> future::tweak(
+   future.batchtools::batchtools_sge,
+   label = 'test2',
+   template = 'batchtools.sge-new.tmpl',
+   workers = 3,
+   resources = list(slots = 4),
+   finalize = FALSE)
batchtools_sge:
- args: function (expr, envir = parent.frame(), substitute = TRUE, globals = TRUE, label = "test2", template = "batchtools.sge-new.tmpl", resources = list(slots = 4), workers = 3, ...)
- tweaked: TRUE
- call: NULL
Warning message:
In tweak.future(future.batchtools::batchtools_sge, label = "test2",  :
  Ignored 1 unknown arguments: โ€˜finalizeโ€™

where is the correct place to set this argument in the code?

TESTS: Don't use local temp folder for HPC backends

Since compute nodes often don't share tempdir(), testing batchtools_<hpc_scheduler>() backends on an HPC environment with often fail; the create batchools registry created on the main host (e.g. /scratch/hb/RtmpQPiu9M/.future) is not available from the compute node(s) resulting in failed jobs.

Solution/workaround: Detect when testing an HPC backend and make sure to use a network-wide folder for the batchtools registry. Alternatively, make it possible to specify the root registry folder (defaults to ./.future/) via an environment variable. This is related to Issue #30.

singularity support?

I was just wondering whether there are any plans to support running jobs within singularity containers?
My HPC experience is limited (slurm only) but if I am not completely off, one would only have to modify the sbatch command slightly, right? Would that go in the template file?

Listing of jobs failed (exit code 127); qstat command not found

Error
Error in OSError("Listing of jobs failed", res) : 
  Listing of jobs failed (exit code 127);
cmd: 'qstat -u $USER -s rs'
output:
command not found
Code that I'm running
library(future)
library(future.batchtools)
options(future.wait.interval = 2.0)

resources = list(h_rt = '00:59:00',
                 h_vmem = '5G',
                 threads = '1',
                 conda.env = 'py3_physeq_test')
plan(batchtools_sge, resources=resources, workers=20)  
 
# set functions (packages added with `%packages%`)
x %<-% { Sys.sleep(2); 3.14 } %packages% c("data.table", "ggplot2")
y %<-% { Sys.sleep(2); 2.71 } %packages% c("data.table", "ggplot2")
z %<-% { Sys.sleep(2); 10.71 } %packages% c("data.table", "ggplot2")
 
# conduct calculation
x + y + z
~/.batchtools.tmpl
#!/bin/bash
 
## The name of the job, can be anything, simply used when displaying the list of running jobs
#$ -N <%= job.name %>
 
## Combining output/error messages into one file
#$ -j y
 
## Giving the name of the output log file
#$ -o <%= log.file %>
 
## One needs to tell the queue system to use the current directory as the working directory
## Or else the script may fail as it will execute in your top level home directory /home/username
#$ -cwd
 
## Use environment variables
#$ -V
 
## Number of threads
#$ -pe parallel <%= resources$threads %>
 
## time
#$ -l h_rt=<%= resources$h_rt %>
 
## memory
#$ -l h_vmem=<%= resources$h_vmem %>
 
 
. ~/.bashrc
conda activate <%= resources$conda.env %>
 
## Export value of DEBUGME environemnt var to slave
export DEBUGME=<%= Sys.getenv("DEBUGME") %>
 
<%= sprintf("export OMP_NUM_THREADS=%i", resources$omp.threads) -%>
<%= sprintf("export OPENBLAS_NUM_THREADS=%i", resources$blas.threads) -%>
<%= sprintf("export MKL_NUM_THREADS=%i", resources$blas.threads) -%>
 
Rscript -e 'batchtools::doJobCollection("<%= uri %>")'
exit 0
~/.batchtools.conf.R
default.resources = list(h_rt = '00:59:00',
                         h_vmem = '4G',
                         threads = '1',
                         conda.env = "py3")
cluster.functions = makeClusterFunctionsSGE(template = "~/.batchtools.tmpl")
temp.dir = "/ebio/abt3_projects/temp_data/"
sessionInfo
R version 3.5.1 (2018-07-02)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS

Matrix products: default
BLAS: /opt/microsoft/ropen/3.5.1/lib64/R/lib/libRblas.so
LAPACK: /opt/microsoft/ropen/3.5.1/lib64/R/lib/libRlapack.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
 [4] LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
[10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] future.apply_1.0.0      future.batchtools_0.7.1 future_1.9.0           
[4] dplyr_0.7.6             RevoUtils_11.0.1        RevoUtilsMath_11.0.0   

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.18      pillar_1.3.0      compiler_3.5.1    bindr_0.1.1      
 [5] prettyunits_1.0.2 progress_1.2.0    base64enc_0.1-3   tools_3.5.1      
 [9] digest_0.6.15     packrat_0.4.9-3   jsonlite_1.5      evaluate_0.11    
[13] tibble_1.4.2      checkmate_1.8.5   pkgconfig_2.0.1   rlang_0.2.1      
[17] yaml_2.2.0        parallel_3.5.1    bindrcpp_0.2.2    withr_2.1.2      
[21] stringr_1.3.1     knitr_1.20        fs_1.2.5          rappdirs_0.3.1   
[25] hms_0.4.2         globals_0.12.1    rprojroot_1.3-2   tidyselect_0.2.4 
[29] glue_1.3.0        data.table_1.11.4 listenv_0.7.0     R6_2.2.2         
[33] base64url_1.4     rmarkdown_1.10    purrr_0.2.5       magrittr_1.5     
[37] backports_1.1.2   codetools_0.2-15  batchtools_0.9.10 htmltools_0.3.6  
[41] assertthat_0.2.0  brew_1.0-6        stringi_1.2.4     crayon_1.3.4  

Implement batchtools_config

Currently you have to set up the cluster twice:

  1. For batchtools where you create a configuration file + a template file; the config file calls the cluster function constructor and possibly sets additional cluster-specific options like default resources or the temp directory.
  2. For future.batchtools where you select the scheduler via batchtools_[scheduler] and re-use the template file. future.batchtools then calls the appropriate cluster function constructor. Unsure if you can set additional options via tweak()?

A batchtools_config plan could just rely on batchtools to be configured. In other words, future.batchtools could just call makeRegistry() and not overwrite the cluster functions backend.

Result of nested {remote} -> {batchtools_slurm} -> {multicore} not distributed back to local machine

Hi Henrik,
thanks for your great package. It works basically fine, I only run into an issue when submitting a multicore job to a cluster and I wonder if I am doing anything wrong or whether this might be related to the HPC I am using.

Consider the following example code I am executing from my local machine:

library(future.batchtools) 
library(listenv)

plan(list(tweak(remote, workers = "[email protected]"),
          tweak(batchtools_slurm, resources = list(walltime = 600, ncpus=8)),
          tweak(multicore, workers = 8)
) )

# run at remote
dat_f <- future({
  # job at the cluster
  dat %<-% {
    dat_t <- listenv()
    cores <- availableCores()
    for(f in 1:8) {
      # multicore processes within job
      dat_t[[f]] %<-% {
        Sys.sleep(20)
        data.frame(pid = Sys.getpid(),
                   node = Sys.info()[["nodename"]],
                   ncoresa = cores,
                   ncoresb = availableCores(),
                   stringsAsFactors = F)
      }
    }
    Reduce(rbind, dat_t)
  }
})

dat_all <- value(dat_f)

What is happening is that executing the dat_t <- future(...) lines starts a job on the cluster. This is running fine and without problems, however the last line dat_all <- value(dat_f) does not return the results, i.e. dat_all is an environment object. When I start an R session on the cluster and load the results of the job with batchtools::loadRegistry() and batchtools::loadResult() everything is as expected and from the runtime of the job I am certain that the 8 processes were running in parallel.

Running the {batchtools_slurm} -> {multicore} futures within an R session directly on the remote cluster works fine.

Note that when I run from my local machine only two nested futures, i.e.

plan(list(tweak(remote, workers = "[email protected]"),
          tweak(batchtools_slurm, resources = list(walltime = 600))
))

dat_f <- future({
    dat_t <- listenv()
    cores <- availableCores()
    for(f in 1:8) {
      dat_t[[f]] %<-% {
        Sys.sleep(20)
        data.frame(pid = Sys.getpid(),
                   node = Sys.info()[["nodename"]],
                   ncoresa = cores,
                   ncoresb = availableCores(),
                   stringsAsFactors = F)
      }
    }
    Reduce(rbind, dat_t)
})
dat_all <- value(dat_f)

everything works as expected, i.e. there are 8 jobs created running on the cluster and dat_all contains the expected data.frame.

Do you have any ideas why the results of the multicore future are not correctly distributed to my local machine?

Cannot get toy example to work, could you kindly guide me for config ?

Hello, I am trying to work a toy example using slurm

plan(batchtools_slurm, template = system.file("templates", "slurm-simple.tmpl", package = "batchtools"))
x %<-% { Sys.sleep(5); 3.14 }

Error: Fatal error occurred: 101. Command 'sbatch' produced exit code 1. Output: 'sbatch: error: Invalid numeric value "" for cpus-per-task.'
I am probably missing something obvious, is there a document that could guide me to make this toy example work ?

config for batchtools_sge?

Sorry if this is in the docs and I can't find it, but is there a way to specify default resources for the template? When just using batchtools, default resources can be set with a ~/.batchtools.conf.R file. However, this file doesn't seem to work with future.batchtools::plan().

setting 1 job per worker core after chunking the elements

I am using an sge template.

Is there a native way in future plan to have elements of a list be allocated to each available core in preset number of workers (ie chunking the list)?

ie if i have a workers with 8 cores and a vector (x) of length 16, i want future to send each element to a core on the workers to run in parallel. (assuming i am sending out jobs from the remote master)

sge <- future::tweak(
    future.batchtools::batchtools_sge,
    template = 'batchtools.sge-mrg.tmpl',
    workers = 2,
    resources = list(slots = 1)
  )
  
  future::plan(list(sge))
  
  x <- vector('list',16)

  ret <- furrr::future_map(x, .f = foo)
  
#!/bin/bash

## The name of the job, can be anything, simply used when displaying the list of running jobs
#$ -N <%= job.name %>

## Combining output/error messages into one file
#$ -j y

## Giving the name of the output log file
#$ -o <%= log.file %>

## One needs to tell the queue system to use the current directory as the working directory
## Or else the script may fail as it will execute in your top level home directory /home/username
#$ -cwd

## Use environment variables
#$ -V

## Use correct queue
##$ -q all.q

#$ -pe smp <%= resources[["slots"]] %>

## Export value of DEBUGME environemnt var to slave
export DEBUGME=<%= Sys.getenv("DEBUGME") %>

<%= sprintf("export OMP_NUM_THREADS=%i", resources$omp.threads) -%>
<%= sprintf("export OPENBLAS_NUM_THREADS=%i", resources$blas.threads) -%>
<%= sprintf("export MKL_NUM_THREADS=%i", resources$blas.threads) -%>


Rscript -e 'batchtools::doJobCollection("<%= uri %>")'
exit 0

cc @wlandau

Add option to control how number of logged output lines display in error messages

Background

Related to Issue #31, the error message:

Error: BatchtoolsExpiration: Future ('<none>') expired (registry path /home/uni08/hesselbarth3/.future/20180901_172706-Dvm4Cm/batchtools_1849950729).. The last few lines of the logged output:
    Max Swap :                                   -
    Max Processes :                              1
    Max Threads :                                1
    Run time :                                   9 sec.
    Turnaround time :                            14 sec.
The output (if any) follows:

is produces my displaying tail(log, n = 6L) last lines of the logged output, which is not enough to see that:

TERM_EXTERNAL_SIGNAL: job killed by a signal external to LSF.
Exited with signal termination: Killed.

Resource usage summary:

    CPU time :                                   0.07 sec.
    Max Memory :                                 15 MB
    Average Memory :                             15.00 MB
    Total Requested Memory :                     -
    Delta Memory :                               -
    Max Swap :                                   -
    Max Processes :                              1
    Max Threads :                                1
    Run time :                                   9 sec.
    Turnaround time :                            14 sec.

The output (if any) follows:

Suggestion

Some thoughs:

  • Add option for controlling the number of lines displayed
  • Not only mention the path to the registry in the error message, but also the path to the logged output file (plus info on number of lines, file size in bytes, last modified, ...)

WISH: Polling frequency

Background

Currently, the package uses batchtools::waitForJobs() every second (getOption("future.wait.delay", 1.0)) to poll the scheduler to see when jobs are finished. Polling the scheduler to check when jobs are ready can but a heavy burden on the scheduler if there are lots of simultaneous requests.

Suggestion

The future.BatchJobs package had a similar approach, but it slowly increased the waiting time between each poll such that for very long running jobs we didn't keep checking every minute. This should be implemented in future.batchjobs too. This requires to implement our own batchtools::waitForJobs() version (or fix it upstream).

.future folder

Hi Henrik,

do you think it would be possible/worth having auxiliary functions giving more control over the .future folder? The problem in my case was/is that I only have a certain quota on our HPC and if .futures is located in my personal drive and I work with spatial data - I reach this quota quite fast.

I was not able to figure out how to control this with future.batchtools directly and just relied on .Rprofile to set my working directory to /scratch while loading R. This ensured that the default call of makeRegistry from batchtools chooses this directory for the .future folder. However, a more reproducible workflow for that would be nice.

Or did I just miss a way to do this with future.batchtools?

Cheers
Marco

Problem with slurm backend when calling scancel

Hello,
When I call scancel to cancel all tasks submitted to a slurm cluster by future.batchtools then hit CTRL-C to get the terminal back, R displays an error per task and is painfully slow to come back.

Make jobname match number in batchtools_XXXXXXXXXX by default when using SLURM?

When I want to peek at what's going on on a future-powered slurm job I look at, for example:

.future/20171118_083108-ebBlfz/batchtools_492448437/logs/job9622adcaff15f092fcb3ed1f0d6221bd.log

I have to get in to the final filename to match up the job (here job9622ad) to a log. It would be a little easier to get to the job I want if the jobname was also after the batchtools_ bit. Is there a reason this doesn't make sense?

Resolving a batchtools_slurm-related error, probably a configuration problem

See ropensci/drake#115, particularly here. @kendonB and I have been trying to debug his drake/SLURM powered project, and we are running into trouble. The following assumes development drake 8a3558a3fa9269f2c19c98e1a6404603486d5c3a.

library(drake)
example_drake("slurm")
setwd("slurm")
source("run.R")

On my Debian 9.2 VM with a toy installation of SLURM, this runs perfectly. But on his serious SLURM cluster, @kendonB gets the following.

Error: BatchtoolsExpiration: Future ('<none>') expired (registry path ~/.future/20171030_104404-sArxEt/batchtools_1079708388).. The last few lines of the logged output:
46: try(execJob(job))
47: doJobCollection.JobCollection(obj, output = output)
48: doJobCollection.character("~/.future/20171030_104404-sArxEt/batchtools_1079708388/jobs/jobcf9a9c87902b62125af3a0a1d9e37a56.rds")
49: batchtools::doJobCollection("~/.future/20171030_104404-sArxEt/batchtools_1079708388/jobs/jobcf9a9c87902b62125af3a0a1d9e37a56.rds")
An irrecoverable exception occurred. R is aborting now ...
/var/spool/slurmd/job65957677/slurm_script: line 22:  5660 Illegal instruction     (core dumped) Rscript -e 'batchtools::doJobCollection("~...
In addition: Warning message:
In waitForJobs(ids = jobid, timeout = timeout, sleep = sleep_fcn,  :
  Some jobs disappeared from the system

I suspect a configuration error that could be resolved with the right template file. I would rather not have to implement a special slurm_apply backend, especially since drake already has two different ways to talk to SLURM already.

TORQUE trouble

I am having a problem similar to #11 with TORQUE (on Ubuntu 16.04). I also posted on Stack Overflow. A test.pbs script seems to work just fine.

#PBS -N test
#PBS -l nodes=1:ppn=1
#PBS -l walltime=0:01:00

cd $PBS_O_WORKDIR
touch done.txt
echo "done"
qsub test.pbs

But my jobs hang for future_lapply() via future.batchtools.

library(future.batchtools)
plan(batchtools_torque(template = "torque.tmpl"))
future_lapply(1:2, cat)

With torque.tmpl:

## Job name:
#PBS -N <%= if (exists("job.name", mode = "character")) job.name else job.hash %>

## Direct streams to logfile:
#PBS -o <%= log.file %>

## Merge standard error and output:
#PBS -j oe

## Launch R and evaluated the batchtools R job
#Rscript -e 'batchtools::doJobCollection("<%= uri %>")'

My qstat shows

Job id                    Name             User            Time Use S Queue
------------------------- ---------------- --------------- -------- - -----
65.localhost              ...0f2c92668271a wlandau         00:00:00 E batch          
66.localhost              ...a920933c92e31 wlandau         00:00:00 E batch  

And tracejob -n2 65:

/var/spool/torque/server_priv/accounting/20171029: No matching job records located
/var/spool/torque/server_logs/20171029: No matching job records located
/var/spool/torque/mom_logs/20171029: No matching job records located
/var/spool/torque/sched_logs/20171029: No matching job records located

Job: 65.localhost

10/30/2017 17:27:25  S    enqueuing into batch, state 1 hop 1
10/30/2017 17:27:25  S    Job Queued at request of wlandau@localhost, owner =
                          wlandau@localhost, job name = job9b479ac148b11cd2e300f2c92668271a,
                          queue = batch
10/30/2017 17:27:25  S    Job Modified at request of Scheduler@Haggunenon
10/30/2017 17:27:25  S    Exit_status=0 resources_used.cput=00:00:00 resources_used.mem=0kb
                          resources_used.vmem=0kb resources_used.walltime=00:00:00
10/30/2017 17:27:25  L    Job Run
10/30/2017 17:27:25  S    Job Run at request of Scheduler@Haggunenon
10/30/2017 17:27:25  S    Not sending email: User does not want mail of this type.
10/30/2017 17:27:25  S    Not sending email: User does not want mail of this type.
10/30/2017 17:27:25  M    job was terminated
10/30/2017 17:27:25  M    obit sent to server
10/30/2017 17:27:25  A    queue=batch
10/30/2017 17:27:25  M    scan_for_terminated: job 65.localhost task 1 terminated, sid=11430
10/30/2017 17:27:25  A    user=wlandau group=wlandau
                          jobname=job9b479ac148b11cd2e300f2c92668271a queue=batch
                          ctime=1509398845 qtime=1509398845 etime=1509398845 start=1509398845
                          owner=wlandau@localhost exec_host=localhost/0 Resource_List.ncpus=1
                          Resource_List.neednodes=1 Resource_List.nodect=1
                          Resource_List.nodes=1 Resource_List.walltime=01:00:00 
10/30/2017 17:27:25  A    user=wlandau group=wlandau
                          jobname=job9b479ac148b11cd2e300f2c92668271a queue=batch
                          ctime=1509398845 qtime=1509398845 etime=1509398845 start=1509398845
                          owner=wlandau@localhost exec_host=localhost/0 Resource_List.ncpus=1
                          Resource_List.neednodes=1 Resource_List.nodect=1
                          Resource_List.nodes=1 Resource_List.walltime=01:00:00 session=11430
                          end=1509398845 Exit_status=0 resources_used.cput=00:00:00
                          resources_used.mem=0kb resources_used.vmem=0kb
                          resources_used.walltime=00:00:00

and qstat -f:

Job Id: 65.localhost
    Job_Name = job9b479ac148b11cd2e300f2c92668271a
    Job_Owner = wlandau@localhost
    resources_used.cput = 00:00:00
    resources_used.mem = 0kb
    resources_used.vmem = 0kb
    resources_used.walltime = 00:00:00
    job_state = E
    queue = batch
    server = haggunenon
    Checkpoint = u
    ctime = Mon Oct 30 17:27:25 2017
    Error_Path = localhost:/home/wlandau/Desktop/torque/job9b479ac148b11cd2e30
        0f2c92668271a.e65
    exec_host = localhost/0
    Hold_Types = n
    Join_Path = oe
    Keep_Files = n
    Mail_Points = a
    mtime = Mon Oct 30 17:27:25 2017
    Output_Path = Haggunenon:/home/wlandau/Desktop/torque/.future/20171030_172
        725-6xjpT8/batchtools_516383701/logs/job9b479ac148b11cd2e300f2c9266827
        1a.log
    Priority = 0
    qtime = Mon Oct 30 17:27:25 2017
    Rerunable = True
    Resource_List.ncpus = 1
    Resource_List.nodect = 1
    Resource_List.nodes = 1
    Resource_List.walltime = 01:00:00
    session_id = 11430
    Variable_List = PBS_O_QUEUE=batch,PBS_O_HOST=localhost,
        PBS_O_HOME=/home/wlandau,PBS_O_LANG=en_US.UTF-8,PBS_O_LOGNAME=wlandau,
        PBS_O_PATH=/home/wlandau/bin:/home/wlandau/.local/bin:/usr/local/sbin
        :/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/ga
        mes:/snap/bin,PBS_O_SHELL=/bin/bash,PBS_SERVER=localhost,
        PBS_O_WORKDIR=/home/wlandau/Desktop/torque
    comment = Job started on Mon Oct 30 at 17:27
    etime = Mon Oct 30 17:27:25 2017
    exit_status = 0
    submit_args = /tmp/Rtmp6xjpT8/job9b479ac148b11cd2e300f2c92668271a.job
    start_time = Mon Oct 30 17:27:25 2017
    Walltime.Remaining = 3548
    start_count = 1
    fault_tolerant = False

Job Id: 66.localhost
    Job_Name = jobe0c18b35ffbe546515ea920933c92e31
    Job_Owner = wlandau@localhost
    resources_used.cput = 00:00:00
    resources_used.mem = 0kb
    resources_used.vmem = 0kb
    resources_used.walltime = 00:00:00
    job_state = E
    queue = batch
    server = haggunenon
    Checkpoint = u
    ctime = Mon Oct 30 17:27:27 2017
    Error_Path = localhost:/home/wlandau/Desktop/torque/jobe0c18b35ffbe546515e
        a920933c92e31.e66
    exec_host = localhost/1
    Hold_Types = n
    Join_Path = oe
    Keep_Files = n
    Mail_Points = a
    mtime = Mon Oct 30 17:27:27 2017
    Output_Path = Haggunenon:/home/wlandau/Desktop/torque/.future/20171030_172
        725-6xjpT8/batchtools_344093744/logs/jobe0c18b35ffbe546515ea920933c92e
        31.log
    Priority = 0
    qtime = Mon Oct 30 17:27:27 2017
    Rerunable = True
    Resource_List.ncpus = 1
    Resource_List.nodect = 1
    Resource_List.nodes = 1
    Resource_List.walltime = 01:00:00
    session_id = 11455
    Variable_List = PBS_O_QUEUE=batch,PBS_O_HOST=localhost,
        PBS_O_HOME=/home/wlandau,PBS_O_LANG=en_US.UTF-8,PBS_O_LOGNAME=wlandau,
        PBS_O_PATH=/home/wlandau/bin:/home/wlandau/.local/bin:/usr/local/sbin
        :/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/ga
        mes:/snap/bin,PBS_O_SHELL=/bin/bash,PBS_SERVER=localhost,
        PBS_O_WORKDIR=/home/wlandau/Desktop/torque
    comment = Job started on Mon Oct 30 at 17:27
    etime = Mon Oct 30 17:27:27 2017
    exit_status = 0
    submit_args = /tmp/Rtmp6xjpT8/jobe0c18b35ffbe546515ea920933c92e31.job
    start_time = Mon Oct 30 17:27:27 2017
    Walltime.Remaining = 3550
    start_count = 1
    fault_tolerant = False

Failed to load package error

Hello, I am trying to use to future.bachtools with a slurm cluster.
I can make this work with the toy example from documentation. But when I use a more advanced example

library(doFuture)                                                                                                                                  
library(future.batchtools)                                                                                                                         
registerDoFuture()                                                                                                                                 
plan(                                                                                                                                              
     batchtools_slurm,                                                                                                                             
     template = system.file("templates", "slurm-simple.tmpl", package = "batchtools"),                                                             
     resources = list(ncpus = 8L, memory = "40G", walltime = 1) 
     )                                                                                                                                             
                                                                                                                                                                                                                                                                                                      
profiles <- foreach(month = month_list[1:2], .errorhandling = "pass", .packages = "sp.services") %dopar%                           
{                                                                                                                                                  
    f(month) 
}     

I get the following:
Error: BatchtoolsError in BatchtoolsFuture ('<none>'): 'Error loading registry dependencies: Error : Failed to load packages: sp.services'
The sp.services package is my package, it basically runs queries against an internal DB. I tried to use library(sp.services) withing the function f but that's not working either.

Another question (that would be usefull for debug) is: running this line of code is blocking, I did not find documentation in the future.batchtools context that shows how to use a registry, build job list and submit it, find logs.
How would I do that in this %dopar% context ?

max.concurrent.jobs interface?

I have a case where I want to submit a large number of jobs but limit the amount running at once. The I/O ends up being limiting so there's no apparent benefit (and possibly some cost) of going from 100 to 200 jobs at a time.

In batchtools, it looks like this is achieved at the registry level, and future.batchtools seems to create a single registry per future so future.batchtools might have to implement it's own limiter?

The workers argument to plan doesn't work as I'd like to keep the jobs small so I can get load balancing working.

setting .future as defaultRegistery

is there a wrapper in future.batchtools to setdefaultRegister() the .future subdirectory. this would open up the possibility of using getStatus.

the analogues in batchtools are

batchtools::setDefaultRegistry(tmp)
batchtools::getStatus()

retrieve future expression on local machine

Hi Henrik,

maybe that's utterly basic and the wrong place to ask, but I thought it might be of interest for more people:

Is there a way you can retrieve a future expressions in the following setup:

login <- tweak(remote, workers = "remote@remote")
bsub <- tweak(batchtools_lsf, ...)
plan(list(
    login,
    bsub,
    multiprocess
))

and I submit the following job (just an example):

y %<-% furrr::future_map_dfr(1:5, function(x){
    cores <- availableCores()
    furrr::future_map_dfr(1:5, function(x){
        tibble::tibble(x = x, 
                       nodename = Sys.info()['nodename'],
                       Sys.getpid = Sys.getpid(), 
                       availableCores = cores) 
    })
}) 

... let's imagine this takes an considerable amount of time and I would close my local r session in between submitting the job and its being finished.

After a login then (and rerunning the same plan again) I can't access y, neither can I access y on the remote machine in an R session. Is that possible in general?

If not, we wondered if you can save R objects somehow in an future_apply, submitted from a local machine and evaluated an a remote one?

Sorry for the very basic questions, just started to fiddle around with future.batchtools.

Cheers
Marco

BUG: Odd interaction with BatchJobs package

So, although this is unlikely to happen, here it goes:

This works:

library(future)
plan(future.batchtools::batchtools_local)
options(future.debug = TRUE)
f <- future(42)

But not this:

library(future)
loadNamespace("BatchJobs")
plan(future.batchtools::batchtools_local)
options(future.debug = TRUE)
f <- future(42)

which gives:

[12:10:52.163] getGlobalsAndPackages() ...
[12:10:52.164] Searching for globals...
[12:10:52.165] 
[12:10:52.166] Searching for globals ... DONE
[12:10:52.166] - globals: [0] <none>
[12:10:52.166] getGlobalsAndPackages() ... DONE
No readable configuration file found
Created registry in '/home/hb/repositories/future.batchtools/.future/20190622_121007-qn0hej/batchtools_978006181' using cluster functions 'Interactive'
Error in dbDoQuery(reg, query) : 
  Error while etablishing the connection: Error in do.call(reg$db.driver, list()) : 
  'what' must be a function or character string
[12:10:52.431] batchtools::waitForJobs() ...
[12:10:52.447] - batchtools::waitForJobs(): TRUE
[12:10:52.461] - status(): 'defined', 'finished', 'started', 'submitted'
[12:10:52.462] batchtools::waitForJobs() ... done
[12:10:52.462] Results:
[12:10:52.484] List of 7
[12:10:52.484]  $ value         : num 42
[12:10:52.484]  $ stdout        : chr ""
[12:10:52.484]  $ conditions    : list()
[12:10:52.484]  $ started       : POSIXct[1:1], format: "2019-06-22 12:10:09"
[12:10:52.484]  $ finished      : POSIXct[1:1], format: "2019-06-22 12:10:09"
[12:10:52.484]  $ version       : chr "1.8"
[12:10:52.484]  $ batchtools_log: chr [1:9] "### [bt]: This is batchtools v0.9.11" "### [bt]: Starting calculation of 1 jobs" "### [bt]: Setting working directory to '/home/hb/repositories/future.batchtools'" "### [bt]: Memory measurement disabled" ...
[12:10:52.484]  - attr(*, "class")= chr "FutureResult"
[12:10:52.497] delete(): Option 'future.delete = '<NULL>'
Removing 1 jobs ...
Removing user function ...
Removing 1 obsolete result files ...
Removing 1 obsolete log files ...
Recursively removing files in '/home/hb/repositories/future.batchtools/.future/20190622_121007-qn0hej/batchtools_607848383' ...
[12:10:52.543] delete(): batchtools registry deleted: '/home/hb/repositories/future.batchtools/.future/20190622_121007-qn0hej/batchtools_607848383'

Enter a frame number, or 0 to exit   

 1: future(42)
 2: .makeFuture(expr, substitute = FALSE, envir = envir, globals = globals, pac
 3: makeFuture(...)
 4: BatchtoolsFuture(expr = expr, envir = envir, substitute = FALSE, globals = 
 5: mprint(reg)
 6: message(paste(now(), capture.output(print(...)), sep = "", collapse = "\n")
 7: paste(now(), capture.output(print(...)), sep = "", collapse = "\n")
 8: capture.output(print(...))
 9: evalVis(expr)
10: withVisible(eval(expr, pf))
11: eval(expr, pf)
12: eval(expr, pf)
13: print(...)
14: print.Registry(...)
15: cat("  Number of jobs: ", dbGetJobCount(x), "\n")
16: dbGetJobCount(x)
17: dbDoQuery(reg, query)
18: stopf("Error while etablishing the connection: %s", as.character(con))
19: stop(obj)
20: (function () 
{
    replicate(sink.number(), sink(NULL))
    if (interactiv

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.