# Theta ADSP Allocation ###### tags: `general` `theta` `adsp` `allocation` `quota` ## Quotas Storage directory (Lustre): `/grand/neutrino_osc_ADSP/`. To list disk quota: ```bash=0 myquota Name Type Filesystem GB_Used GB_Quota Grace =============================================================================================== deltutto User mira-home 0.00 100.00 none ``` ```bash=0 myprojectquotas Lustre : Current Project Quota information for projects you re a member of: Name Type Filesystem Used Quota Grace =============================================================================================== neutrino_osc_ADSP Project grand 4k 240T - ``` To list the project allocation quota: ```bash=0 sbank-list-allocations -p neutrino_osc_ADSP Allocation Suballocation Start End Resource Project Jobs Charged Available Balance ---------- ------------- ---------- ---------- -------- ----------------- ---- ------- ----------------- 7141 7009 2021-05-01 2022-05-01 thetagpu neutrino_osc_ADSP 0 0.0 2,000.0 7142 7010 2021-05-01 2022-05-01 theta neutrino_osc_ADSP 0 0.0 72,000.0 ``` # :memo: LArSoft Lustre is basically parallel IO, each file gets chunked and written to a bunch of different high performance drives. The idea is that when everyone is reading and writing, the actual work isn’t bottlenecked and everyone gets good performance. In reality, there is a metadata server that knows where the files actually live (file A chunked on drives 1, 2 ….50…). Sometimes that server gets overwhelmed, but `/grand` is a brand new system with more servers I think. The number of servers that files get written to is called the `stripe count`. ```bash=0 cd /grand/neutrino_osc_ADSP mkdir sbndcode chmod g+w sbndcode/ # Set number of severs files in sbndcode are written to lfs setstripe -c 40 sbndcode/ # Pull products ./pullProducts ./sbndcode/ slf7 sbnd-v09_24_02 e20 prof ``` ## Singularity Corey built a singularity image from a docker image made by [FNAL](https://hub.docker.com/r/fermilab/fnal-wn-sl7/): `singularity build fnal-wn-sl7.sing docker://fermilab/fnal-wn-sl7:latest`. Then we run (from `/grand/neutrino_osc_ADSP`): ```bash=0 singularity exec -B /grand fnal-wn-sl7.sing bash Singularity> source sbndcode/setup Singularity> setup sbndcode v09_24_02 -q e20:prof Singularity> Singularity> lar -c prodsingle_mu_bnblike.fcl -n 10 ``` ## Balsam - Get Started Balsam instructions: https://balsam.readthedocs.io/en/latest/index.html To test that we can run some simple test job, create a balsam site and submit a couple of test jobs. This is taken from the Balsam tutorial itself, with some modifications. ```bash=0 balsam site init balsam_testsite [Select the default configuration for Theta-KNL] cd balsam_testsite/ balsam site start ``` Balsam login doesn't work, but Misha can generate a token. I had to put the following block in `~/.balsam/client.yml`: ``` api_root: https://balsam-dev.alcf.anl.gov client_class: balsam.client.BasicAuthRequestsClient connect_timeout: 6.2 read_timeout: 120.0 retry_count: 3 token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE1LCJleHAiOjE2MjcyNDE3MDgsInVzZXJuYW1lIjoiZGVsdHV0dG8ifQ.3eyACjKc_6hwStfWLuZjyraNQDxSba4iB8g9QPaDU50 token_expiry: '2021-07-25T19:35:08.727143' username: deltutto ``` Then, need to uncomment this line in the `job-template.sh` script: ``` # export https_proxy=http://theta-proxy.tmi.alcf.anl.gov:3128 ``` This is needed because the jobs are living in that external database and we can interact with them on the login nodes since login nodes since they have outbound network access. But compute nodes don’t have this network access, and the server (which used to be internal to ALCF and is now public) is unreachable. This export tunnels outbound traffic through a proxy server to let compute nodes reach the bigger world. Now the Balsam site is running, and we can create a couple of test jobs: ```bash=0 balsam app create > Application Name (of the form MODULE.CLASS): test.Hello > Application Template [e.g. 'echo Hello {{ name }}!']: echo hello {{ name }} && sleep {{ sleeptime }} && echo goodbye balsam job create --app test.Hello --workdir test/1 --param name="world" --param sleeptime=2 balsam job create --app test.Hello --workdir test/2 --param name="balsam" --param sleeptime=1 balsam queue submit -q debug-cache-quad -A neutrino_osc_ADSP -n 1 -t 10 -j mpi ``` Can be monitored with: ```bash=0 watch "qstat -u $USER && balsam queue ls" ``` and can be seen here: https://status.alcf.anl.gov/theta/activity. The output is placed in the `data/` directory. ## LArSoft Test Job with Balsam Create a new app in the Balsam site that will run a prodsingle LArSoft job: ```bash=0 balsam app create > Application Name (of the form MODULE.CLASS): prodtest.ProdSingle > Application Template [e.g. 'echo Hello {{ name }}!']: to_be_written ``` Then open the file `apps/prodtest.py` and modify the `command_template` attribute to: ```python=0 command_template = ''' singularity run -B /lus/grand/projects/neutrino_osc_ADSP:/lus/grand/projects/neutrino_osc_ADSP:rw /lus/grand/projects/neutrino_osc_ADSP/fnal-wn-sl7.sing <<EOF #setup SBNDCODE: source /lus/grand/projects/neutrino_osc_ADSP/sbndcode/setup setup sbndcode v09_24_02 -q e20:prof lar -c prodsingle_mu_bnblike.fcl ls EOF echo "\nJob finished in: $(pwd)" echo "Available files:" ls ''' ``` Save it and run `balsam sync app` to sync the newly modified app. Create a new job: ```bash= balsam job create --app prodtest.ProdSingle --workdir prodtest_single/0 ``` And check that the job has been created with: ```bash= balsam job ls ``` Now let's run it: ```bash= balsam queue submit -q debug-cache-quad -A neutrino_osc_ADSP -n 1 -t 10 -j mpi watch "qstat -u $USER && balsam queue ls" ``` If it is successful, the output files will be in `data/prodtest_single/0`. ## LArSoft Production Workflow ### Introduction Up to now we’ve been running jobs in `mpi` mode, in which balsam runs on the `mom` node. This mode runs the balsam executable and launches a bunch of `aprun` calls (which is the Theta version of `mpirun`) and those go onto the compute nodes. In serial mode, it’s a bit inverted: balsam runs on each compute node (via `aprun`) and does POpen calls without `aprun` involved. So this is a direct fork of the process onto compute nodes. The advantage here is that we can use a portion of the compute node, per balsam-job, instead of granularity of one node or higher. With 64 cores, we have been running the larsoft jobs with 64 lar calls per node, and scaling out onto hundreds of nodes For this, we end up packing in a ton of larsoft jobs, launching a big balsam job, and they all run together. We want to have several stages, though, which requires a workflow. When `serial` mode (or `mpi` mode, too) is asking the database for jobs, it uses the list of jobs that are `PREPROCESSED`. Jobs can have parents and children too, which will prevent them from running right away Check out the diagram down the page here: https://balsam.readthedocs.io/en/master/userguide/app.html We can have a job (say, prodsingle) that is a parent to a geant job, which is a parent to a detsim job, etc. We can break societal norms too: jobs can have unlimited numbers of parents or children One optimization that was found helps is to do something like: - Job 1: `lar -c prodsingle.fcl -n 25` - Jobs 2-26: `lar -c g4.fcl -n 1 -nskip {JOB_INDEX} -i singles.root`, each has Job 1 as a parent - Job 27-52: `lar -c detsim.fcl -n 1 -i singles_g4_JOB_INDEX.root`, each has exactly 1 parent from the previous step - Job 53: `lar -c merge.fcl -i {all detsim outputs}`, this job has every job from 27 to 52 as it’s parent This gives a graph of jobs that balsam will take, and dynamically run every job with it’s parents finished and keep going until no more jobs You can also slice between workflows with `tags`, so one could be `sbnd:g4` and one could be `uboone:prodsingle` and one could be `sbnd:detsim` and you can select only `sbnd`, only `detsim`, only whatever. ### Creating a Workflow The following shows an example on how we can create a prodsingle job, followed by several geant4 jobs which have the prodsingle one as the parent. First, we need to make two apps, one for prodsingle, and one for Geant4. This is done similarly to the example above, but now we need to pass some arguments. For prodsingle, the `command_template` should look something like: ```python= command_template = ''' singularity run -B /lus/grand/projects/neutrino_osc_ADSP:/lus/grand/projects/neutrino_osc_ADSP:rw /lus/grand/projects/neutrino_osc_ADSP/fnal-wn-sl7.sing <<EOF #setup SBNDCODE: source /lus/grand/projects/neutrino_osc_ADSP/sbndcode/setup setup sbndcode v09_24_02 -q e20:prof lar -c prodsingle_mu_bnblike.fcl --nevts {{nevts}} --output {{output}} ls EOF echo "\nJob finished in: $(pwd)" echo "Available files:" ls ''' ``` While for Geant4: ```python= command_template = ''' singularity run -B /lus/grand/projects/neutrino_osc_ADSP:/lus/grand/projects/neutrino_osc_ADSP:rw /lus/grand/projects/neutrino_osc_ADSP/fnal-wn-sl7.sing <<EOF #setup SBNDCODE: source /lus/grand/projects/neutrino_osc_ADSP/sbndcode/setup setup sbndcode v09_24_02 -q e20:prof lar -c standard_g4_sbnd.fcl --nevts {{nevts}} --nskip {{nskip}} --output {{output}} --source {{source}} ls EOF echo "\nJob finished in: $(pwd)" echo "Available files:" ls ''' ``` This python script created the jobs: ```python= from balsam.api import Job, App, site_config n_events = 5 node_packing_count=5 # # ProdSingle # prodsingle_app = App.objects.get(site_id=site_config.site_id, class_path="production.ProdSingle") prodsingle_jobs = [] for i in range(1): job = Job( workdir=f"prod_prodsingle/{i}", app_id=prodsingle_app.id, tags={'sbnd':'prodsingle'}, parameters={ "nevts": f"{n_events}", "output": f"prodsingle_sbnd_{i}.root"}, node_packing_count=node_packing_count, num_nodes=1, parent_ids=(), ) print(job) job.save() prodsingle_jobs.append(job) # # Geant4 # geant4_app = App.objects.get(site_id=site_config.site_id, class_path="production.Geant4") geant4_jobs = [] for i in range(n_events): job = Job( workdir=f"prod_geant4/{i}", app_id=geant4_app.id, tags={'sbnd':'geant4'}, parameters={ "nevts": "1", "nskip": f"{i}", "output": f"prodsingle_geant4_sbnd_{i}.root", "source": f"{prodsingle_jobs[0].parameters['output']}"}, node_packing_count=node_packing_count, num_nodes=1, parent_ids={prodsingle_jobs[0].id}, ) print(job) job.save() geant4_jobs.append(job) ``` Running this should create the following: ```bash= $> balsam job ls ID Site App Workdir State Tags 67191 thetalogin6:balsam_testsite2 production.Geant4 prod_geant4/4 AWAITING_PARENTS {'sbnd': 'geant4'} 67187 thetalogin6:balsam_testsite2 production.Geant4 prod_geant4/0 AWAITING_PARENTS {'sbnd': 'geant4'} 67190 thetalogin6:balsam_testsite2 production.Geant4 prod_geant4/3 AWAITING_PARENTS {'sbnd': 'geant4'} 67189 thetalogin6:balsam_testsite2 production.Geant4 prod_geant4/2 AWAITING_PARENTS {'sbnd': 'geant4'} 67186 thetalogin6:balsam_testsite2 production.ProdSingle prod_prodsingle/0 STAGED_IN {'sbnd': 'prodsingle'} 67188 thetalogin6:balsam_testsite2 production.Geant4 prod_geant4/1 AWAITING_PARENTS {'sbnd': 'geant4'} ``` TO BE CONTINUED ## Flux Files ### SBND Fluxes SBND flux files in neutrino mode are in `/cvmfs/sbnd.osgstorage.org/pnfs/fnal.gov/usr/sbnd/persistent/stash/fluxFiles/bnb/BooNEtoGSimple/configH-v1/march2021/neutrinoMode/`. They have been copyied to Theta at this location: ```bash= /grand/neutrino_osc_ADSP/files/flux/sbnd/neutrino_mode/ ``` In total, they take 69 GB of disk space. ### ICARUS Fluxes ### MicroBooNE Fluxes # Table of Contents [ToC]