<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://ccl.cse.nd.edu/feed.xml" rel="self" type="application/atom+xml"/><link href="https://ccl.cse.nd.edu/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-07-29T18:39:53+00:00</updated><id>https://ccl.cse.nd.edu/feed.xml</id><title type="html">The Cooperative Computing Lab</title><subtitle>Cooperative Computing Lab website: news, projects, publications, software, and community updates. </subtitle><entry><title type="html">How to Read HPC Error Logs (And What Common Failures Actually Mean)</title><link href="https://ccl.cse.nd.edu/blog/2026/how-to-read-hpc-error-logs.md/" rel="alternate" type="text/html" title="How to Read HPC Error Logs (And What Common Failures Actually Mean)"/><published>2026-07-29T17:00:00+00:00</published><updated>2026-07-29T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/how-to-read-hpc-error-logs.md</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/how-to-read-hpc-error-logs.md/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/how-to-read-hpc-error-logs/Beginner's%20Guide%20to%20HPC-480.webp 480w,/assets/blog/2026/how-to-read-hpc-error-logs/Beginner's%20Guide%20to%20HPC-800.webp 800w,/assets/blog/2026/how-to-read-hpc-error-logs/Beginner's%20Guide%20to%20HPC-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/how-to-read-hpc-error-logs/Beginner's%20Guide%20to%20HPC.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>You submit a batch job, wait in the queue, and suddenly see its status transition to <code class="language-plaintext highlighter-rouge">FAILED</code> or <code class="language-plaintext highlighter-rouge">HOLD</code>. When you open your output directory, you are greeted by a 200-line wall of obscure error messages, memory dumps, and cryptic exit codes.</p> <p>It is a classic high-performance computing friction point: feeling overwhelmed by stack traces and assuming something catastrophic went wrong. But <strong>HPC error logs are structured breadcrumbs, not punishments.</strong> Once you know where your scheduler writes these files and how to parse the output, identifying the root cause takes seconds across any Workload Manager—whether your cluster uses <strong>SLURM</strong>, <strong>Univa Grid Engine (UGE / SGE)</strong>, or <strong>HTCondor</strong>.</p> <h2 id="standard-output-vs-standard-error-vs-event-logs">Standard Output vs. Standard Error vs. Event Logs</h2> <p>When running non-interactive batch jobs, system output streams split into separate files depending on your workload manager:</p> <ul> <li><strong>Standard Output (<code class="language-plaintext highlighter-rouge">.out</code> / stdout):</strong> Reserved for standard runtime logs, progress bars, <code class="language-plaintext highlighter-rouge">print()</code> statements, and calculation results.</li> <li><strong>Standard Error (<code class="language-plaintext highlighter-rouge">.err</code> / stderr):</strong> Reserved for system warnings, thrown exceptions, segmentation faults, and library errors.</li> <li><strong>Workflow Event Log (<code class="language-plaintext highlighter-rouge">.log</code>):</strong> Unique to schedulers like <strong>HTCondor</strong>, this file records lifecycle events managed by the scheduler itself (e.g., job submission, node assignment, resource tracking, and hold reasons).</li> </ul> <p>Here is how you define these log files across the three major schedulers:</p> <h3 id="slurm-sub--sh">SLURM (<code class="language-plaintext highlighter-rouge">.sub</code> / <code class="language-plaintext highlighter-rouge">.sh</code>)</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#SBATCH --output=my_job_%j.out</span>
<span class="c">#SBATCH --error=my_job_%j.err</span>
</code></pre></div></div> <p><em>(Where <code class="language-plaintext highlighter-rouge">%j</code> inserts the unique SLURM Job ID).</em></p> <h3 id="univa-grid-engine--sge-sub--sh">Univa Grid Engine / SGE (<code class="language-plaintext highlighter-rouge">.sub</code> / <code class="language-plaintext highlighter-rouge">.sh</code>)</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#$ -o my_job_$JOB_ID.out</span>
<span class="c">#$ -e my_job_$JOB_ID.err</span>
</code></pre></div></div> <p><em>(Where <code class="language-plaintext highlighter-rouge">$JOB_ID</code> inserts the unique Grid Engine Job ID).</em></p> <h3 id="htcondor-submit">HTCondor (<code class="language-plaintext highlighter-rouge">.submit</code>)</h3> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>output = my_job_$(Cluster).out
error  = my_job_$(Cluster).err
log    = my_job_$(Cluster).log
</code></pre></div></div> <p><em>(Where <code class="language-plaintext highlighter-rouge">$(Cluster)</code> represents the HTCondor Cluster/Job ID).</em></p> <p>When a job fails, <strong>always inspect the <code class="language-plaintext highlighter-rouge">.err</code> file first</strong> (and check the <code class="language-plaintext highlighter-rouge">.log</code> file if you are using HTCondor).</p> <h2 id="reading-traces-top-to-bottom-vs-bottom-to-top">Reading Traces: Top-to-Bottom vs. Bottom-to-Top</h2> <p>Reading an error log sequentially from line 1 to line 200 is often a waste of time. Different programming languages and runtime tools print stack traces in entirely different directions.</p> <h3 id="python-read-bottom-to-top">Python: Read Bottom-to-Top</h3> <p>Python prints error traces chronologically, meaning the actual fatal exception is always printed at the <strong>very bottom</strong> of the trace.</p> <ul> <li><strong>The Strategy:</strong> Scroll directly to the final line of the <code class="language-plaintext highlighter-rouge">.err</code> file to identify the exact error type (e.g., <code class="language-plaintext highlighter-rouge">KeyError</code>, <code class="language-plaintext highlighter-rouge">IndexError</code>, <code class="language-plaintext highlighter-rouge">ModuleNotFoundError</code>). Once you know <em>what</em> failed, scan upward to find the line pointing to your script rather than an internal library package.</li> </ul> <h3 id="cc-and-fortran-read-top-to-bottom">C/C++ and Fortran: Read Top-to-Bottom</h3> <p>Compiled languages and build tools log errors chronologically as they are encountered during compilation or execution.</p> <ul> <li><strong>The Strategy:</strong> Start at the <strong>very top</strong> of the error log. The first error printed is almost always the true root cause; the hundreds of lines following it are usually cascading failures triggered by that initial crash.</li> </ul> <h3 id="bash--shell-scripts-read-where-it-stops">Bash / Shell Scripts: Read Where It Stops</h3> <p>By default, Bash scripts continue executing subsequent commands even if an earlier line fails (unless <code class="language-plaintext highlighter-rouge">set -e</code> is enabled).</p> <ul> <li><strong>The Strategy:</strong> Search for the specific command line that failed by scanning upward from where output stopped matching your expected workflow.</li> </ul> <h2 id="decoding-the-usual-suspects-classic-hpc-failures">Decoding the Usual Suspects: Classic HPC Failures</h2> <p>Most cluster job crashes stem from three recurring issues. Recognizing how each scheduler reports these failures allows you to fix them instantly.</p> <h3 id="1-out-of-memory-oom--exit-code-137--job-holds">1. Out Of Memory (OOM) / Exit Code 137 / Job Holds</h3> <ul> <li><strong>The Cause:</strong> Your program tried to consume more RAM than requested. To prevent your job from crashing neighboring processes on a shared node, the system kernel or scheduler terminated your process.</li> <li><strong>How Schedulers Report It:</strong></li> <li><strong>SLURM:</strong> Your <code class="language-plaintext highlighter-rouge">.err</code> file or <code class="language-plaintext highlighter-rouge">sacct -j &lt;job_id&gt;</code> reports exit code <strong><code class="language-plaintext highlighter-rouge">137</code></strong> (128 + Signal 9 <code class="language-plaintext highlighter-rouge">SIGKILL</code>), often accompanied by <code class="language-plaintext highlighter-rouge">slurmstepd: error: Detected allocation failure. OOM Killer invoked.</code></li> <li><strong>UGE / SGE:</strong> The job fails with exit code <code class="language-plaintext highlighter-rouge">137</code>. Running <code class="language-plaintext highlighter-rouge">qacct -j &lt;job_id&gt;</code> or <code class="language-plaintext highlighter-rouge">qstat -j &lt;job_id&gt;</code> shows <code class="language-plaintext highlighter-rouge">failed: 100 : Assumed OS problem</code> or reveals that the job exceeded its specified <code class="language-plaintext highlighter-rouge">maxvmem</code> ceiling.</li> <li> <p><strong>HTCondor:</strong> Rather than exiting outright, HTCondor usually places the job in a <strong><code class="language-plaintext highlighter-rouge">HOLD</code></strong> state (<code class="language-plaintext highlighter-rouge">H</code>). Running <code class="language-plaintext highlighter-rouge">condor_q -hold</code> or checking the <code class="language-plaintext highlighter-rouge">.log</code> file explicitly states: <code class="language-plaintext highlighter-rouge">Job used more memory than requested</code>.</p> </li> <li><strong>The Fix:</strong> Increase the requested memory in your submission script:</li> <li><strong>SLURM:</strong> <code class="language-plaintext highlighter-rouge">#SBATCH --mem=32G</code> (or <code class="language-plaintext highlighter-rouge">#SBATCH --mem-per-cpu=8G</code>)</li> <li><strong>UGE:</strong> <code class="language-plaintext highlighter-rouge">#$ -l h_vmem=32G</code></li> <li><strong>HTCondor:</strong> <code class="language-plaintext highlighter-rouge">request_memory = 32GB</code></li> </ul> <h3 id="2-no-space-left-on-device-or-quota-exceeded">2. “No Space Left on Device” or Quota Exceeded</h3> <ul> <li><strong>The Symptom:</strong> <code class="language-plaintext highlighter-rouge">IOError: [Errno 28] No space left on device</code> or <code class="language-plaintext highlighter-rouge">write error: disk quota exceeded</code>.</li> <li><strong>What it means:</strong> Your script ran out of disk space. This rarely happens on large global storage filesystems (<code class="language-plaintext highlighter-rouge">/scratch</code> or <code class="language-plaintext highlighter-rouge">/project</code>), but frequently occurs when temporary files auto-write to small localized <code class="language-plaintext highlighter-rouge">/tmp</code> partitions or constrained home directories (<code class="language-plaintext highlighter-rouge">/home/username</code>).</li> <li><strong>The Fix:</strong> Redirect temporary directory environment variables to high-capacity scratch space directly inside your job script before running code:</li> </ul> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">TMPDIR</span><span class="o">=</span>/scratch/username/tmp
<span class="nb">export </span><span class="nv">PIP_CACHE_DIR</span><span class="o">=</span>/scratch/username/pip_cache
<span class="nb">mkdir</span> <span class="nt">-p</span> <span class="nv">$TMPDIR</span> <span class="nv">$PIP_CACHE_DIR</span>
</code></pre></div></div> <p><em>(In HTCondor, you can also request dedicated local scratch disk space via <code class="language-plaintext highlighter-rouge">request_disk = 50GB</code> in your submit file).</em></p> <h3 id="3-command-not-found-or-modulenotfounderror">3. “Command Not Found” or “ModuleNotFoundError”</h3> <ul> <li><strong>The Symptom:</strong> <code class="language-plaintext highlighter-rouge">bash: line 14: gfortran: command not found</code> or <code class="language-plaintext highlighter-rouge">ModuleNotFoundError: No module named 'torch'</code>.</li> <li><strong>What it means:</strong> Compute nodes start in a clean, isolated environment. They <strong>do not</strong> automatically inherit loaded modules, exported <code class="language-plaintext highlighter-rouge">$PATH</code> variables, or active Conda environments from your login session terminal.</li> <li><strong>The Fix:</strong> Explicitly load system modules and activate virtual environments directly inside your execution script:</li> </ul> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Load system modules</span>
module load python/3.11

<span class="c"># Activate your custom environment</span>
<span class="nb">source</span> /scratch/username/envs/my_env/bin/activate

<span class="c"># Execute your application</span>
python3 my_script.py
</code></pre></div></div> <h2 id="quick-scheduler-diagnostic-cheat-sheet">Quick Scheduler Diagnostic Cheat Sheet</h2> <p>When a job finishes or fails unexpectedly, use these diagnostic commands to query job metadata and exit status:</p> <table> <thead> <tr> <th>Scheduler</th> <th>Query Live / Held Jobs</th> <th>Query Finished / Failed Job History</th> </tr> </thead> <tbody> <tr> <td><strong>SLURM</strong></td> <td><code class="language-plaintext highlighter-rouge">squeue -u $USER</code></td> <td><code class="language-plaintext highlighter-rouge">sacct -j &lt;job_id&gt; --format=JobID,State,ExitCode,MaxRSS</code></td> </tr> <tr> <td><strong>UGE / SGE</strong></td> <td><code class="language-plaintext highlighter-rouge">qstat -j &lt;job_id&gt;</code></td> <td><code class="language-plaintext highlighter-rouge">qacct -j &lt;job_id&gt;</code></td> </tr> <tr> <td><strong>HTCondor</strong></td> <td><code class="language-plaintext highlighter-rouge">condor_q -hold</code></td> <td><code class="language-plaintext highlighter-rouge">condor_history &lt;job_id&gt;</code></td> </tr> </tbody> </table> <hr/> <h2 id="the-log-parsing-checklist">The Log Parsing Checklist</h2> <p>Before reaching out to cluster administrators or teammates for help with a broken job, run through these steps:</p> <ol> <li><strong>Locate the standard error log (<code class="language-plaintext highlighter-rouge">.err</code>).</strong> For HTCondor, inspect the workflow <code class="language-plaintext highlighter-rouge">.log</code> file as well for scheduler-level events.</li> <li><strong>Determine the language direction.</strong> Read Python errors from the <strong>bottom up</strong>; read C/C++ build failures or shell errors from the <strong>top down</strong>.</li> <li><strong>Use scheduler diagnostics.</strong> Check <code class="language-plaintext highlighter-rouge">sacct</code> (SLURM), <code class="language-plaintext highlighter-rouge">qacct</code> (UGE), or <code class="language-plaintext highlighter-rouge">condor_q -hold</code> (HTCondor) to verify exit codes and memory usage.</li> <li><strong>Identify resource limits.</strong> An exit status of <strong>137</strong> or a memory hold reason means your job needs a higher memory allocation.</li> <li><strong>Set explicit pathing.</strong> Ensure all <code class="language-plaintext highlighter-rouge">module load</code> commands, <code class="language-plaintext highlighter-rouge">TMPDIR</code> paths, and environment activations are written explicitly inside your job submission file.</li> </ol>]]></content><author><name>Cooperative Computing Lab</name></author><category term="technical-articles"/><category term="hpc"/><category term="debugging"/><category term="slurm"/><category term="uge"/><category term="htcondor"/><category term="linux"/><summary type="html"><![CDATA[Don't panic when your batch job crashes. Here is how to locate log files, decode exit codes, and debug failures across SLURM, Univa Grid Engine (UGE), and HTCondor.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/how-to-read-hpc-error-logs/Beginner&apos;s%20Guide%20to%20HPC.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/how-to-read-hpc-error-logs/Beginner&apos;s%20Guide%20to%20HPC.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">Interactive Computing: Jupyter Notebooks and VS Code on Compute Nodes</title><link href="https://ccl.cse.nd.edu/blog/2026/interactive-computing/" rel="alternate" type="text/html" title="Interactive Computing: Jupyter Notebooks and VS Code on Compute Nodes"/><published>2026-07-22T17:00:00+00:00</published><updated>2026-07-22T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/interactive-computing</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/interactive-computing/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/interactive-computing/hero-image-480.webp 480w,/assets/blog/2026/interactive-computing/hero-image-800.webp 800w,/assets/blog/2026/interactive-computing/hero-image-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/interactive-computing/hero-image.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Developing code locally inside a Jupyter Notebook or stepping through lines of Python with VS Code’s debugger is a fast, intuitive way to work. But when your local machine runs out of RAM, CPU cores, or GPU memory, you pack up your workflow and move to a High-Performance Computing (HPC) cluster.</p> <p>Once there, many researchers hit an immediate friction point: clusters are traditionally built around non-interactive batch scripts submitted to job schedulers like SLURM or Grid Engine. Switching from an interactive graphical editor back to pure command-line scripts and print-statement debugging can feel like stepping backward in time.</p> <p>Fortunately, you don’t have to give up your interactive tools to use a supercomputer. You just need to know how to bridge local GUIs with remote cluster compute—<strong>without breaking cluster rules.</strong></p> <h2 id="the-cardinal-sin-running-servers-on-shared-login-nodes">The Cardinal Sin: Running Servers on Shared Login Nodes</h2> <p>When you SSH into a cluster, you land on a <strong>login node</strong> (or head node). Think of the login node as a shared front porch. It is meant exclusively for light administrative tasks: editing text files, organizing directory trees, checking queue status, and submitting job scripts.</p> <p>The most common mistake new cluster users make is running <code class="language-plaintext highlighter-rouge">jupyter notebook</code> or connecting VS Code’s Remote-SSH plugin directly to the login node.</p> <h3 id="why-this-breaks-the-cluster">Why this breaks the cluster:</h3> <ul> <li><strong>VS Code Server (<code class="language-plaintext highlighter-rouge">.vscode-server</code>)</strong> spins up background Node.js processes, language servers, file watchers, and extension host daemons that constantly index workspace directories.</li> <li><strong>Jupyter Notebooks</strong> execute heavy data manipulation, model training, and plotting live inside the server process.</li> </ul> <p>Login nodes are shared simultaneously by hundreds of users. When an interactive server process starts hogging gigabytes of RAM and maxing out CPU cores, the entire command-line interface bogs down for everyone else. To prevent system crashes, administrators install automated automated watcher scripts that will abruptly <strong>kill any long-running or high-memory user process on a login node.</strong></p> <p>To run these tools properly, your server processes <strong>must run on a compute node.</strong></p> <h2 id="strategy-1-ssh-port-forwarding-ssh--l">Strategy 1: SSH Port Forwarding (<code class="language-plaintext highlighter-rouge">ssh -L</code>)</h2> <p>If you want to run Jupyter or VS Code manually, you can use <strong>SSH Local Port Forwarding</strong> (<code class="language-plaintext highlighter-rouge">ssh -L</code>). This technique creates a secure tunnel between a port on your local laptop, through the login node, and directly into an active compute node.</p> <h3 id="step-1-request-an-interactive-compute-session">Step 1: Request an Interactive Compute Session</h3> <p>Before launching any server, request a temporary allocation on a compute node using your cluster’s scheduler:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Request 2 CPU cores, 16GB RAM, and 2 hours on SLURM</span>
srun <span class="nt">--tasks</span><span class="o">=</span>1 <span class="nt">--cpus-per-task</span><span class="o">=</span>2 <span class="nt">--mem</span><span class="o">=</span>16G <span class="nt">--time</span><span class="o">=</span>02:00:00 <span class="nt">--pty</span> bash
</code></pre></div></div> <p>Once your shell transfers you to a compute node, take note of the node’s hostname (e.g., <code class="language-plaintext highlighter-rouge">node042.cluster.internal</code>).</p> <h3 id="step-2-launch-the-server-on-the-compute-node">Step 2: Launch the Server on the Compute Node</h3> <p>Start your Jupyter server on the compute node, making sure to disable automatic browser opening:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Load your Python module or activate your Conda environment first</span>
module load python
jupyter notebook <span class="nt">--no-browser</span> <span class="nt">--port</span><span class="o">=</span>8888
</code></pre></div></div> <p>Terminal output will provide a URL containing a security token (e.g., <code class="language-plaintext highlighter-rouge">http://localhost:8888/?token=a1b2c3d4...</code>).</p> <h3 id="step-3-establish-the-ssh-tunnel-from-your-local-laptop">Step 3: Establish the SSH Tunnel from Your Local Laptop</h3> <p>Open a <strong>new terminal tab on your local laptop</strong> (not on the cluster) and set up the tunnel using <code class="language-plaintext highlighter-rouge">ssh -L</code>:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Syntax: ssh -L [Local_Port]:[Compute_Node_Hostname]:[Remote_Port] [Username]@[Login_Node]</span>
ssh <span class="nt">-L</span> 8888:node042.cluster.internal:8888 netid@cluster.university.edu
</code></pre></div></div> <p>This command forwards traffic from your laptop’s local <code class="language-plaintext highlighter-rouge">localhost:8888</code> through the login node jump host directly to port <code class="language-plaintext highlighter-rouge">8888</code> on compute <code class="language-plaintext highlighter-rouge">node042</code>.</p> <h3 id="step-4-access-the-interface">Step 4: Access the Interface</h3> <p>Open your local web browser and navigate to <code class="language-plaintext highlighter-rouge">http://localhost:8888</code>. Paste the security token generated in Step 2, and you now have a full Jupyter GUI running on dedicated cluster hardware!</p> <blockquote> <p><strong>VS Code Remote Tip:</strong> When using VS Code’s Remote SSH extension on shared systems, home directory file locking can sometimes break connections. Refer to resources like <a href="https://docs.crc.nd.edu/general_pages/v/vscode.html">Notre Dame’s CRC VS Code Documentation</a> for cluster-specific settings, such as enabling <strong>“Lockfiles In Tmp”</strong> in your extension settings to ensure seamless reconnects.</p> </blockquote> <h2 id="strategy-2-open-ondemand-the-modern-web-portal">Strategy 2: Open OnDemand (The Modern Web Portal)</h2> <p>Setting up SSH tunnels manually works well, but it requires managing port numbers, tokens, and multiple terminal windows. Many modern HPC centers simplify this entirely by deploying <strong>Open OnDemand (OOD)</strong>.</p> <p>Open OnDemand is an open-source, web-based portal that gives you graphical access to cluster resources straight through a web browser without needing any local SSH configuration or command-line tunneling.</p> <h3 id="how-open-ondemand-works">How Open OnDemand Works:</h3> <ol> <li><strong>Log in via Web Browser:</strong> Navigate to your university’s Open OnDemand URL (e.g., <code class="language-plaintext highlighter-rouge">ondemand.crc.nd.edu</code>) and authenticate with your institutional login.</li> <li><strong>Select an Interactive App:</strong> Choose <strong>Jupyter</strong>, <strong>VS Code</strong>, <strong>RStudio</strong>, or <strong>MATLAB</strong> from the interactive applications menu.</li> <li><strong>Configure Your Resource Allocation:</strong> A form will ask you to specify your required resources (number of CPUs, GPUs, RAM amount, and maximum runtime).</li> <li><strong>Launch:</strong> Click <strong>Launch</strong>.</li> </ol> <p>Under the hood, Open OnDemand automatically writes a job script, submits it to the cluster scheduler (SLURM/Grid Engine), waits for a compute node to be allocated, launches the server process, builds a secure web proxy, and presents a <strong>“Connect”</strong> button in your browser window.</p> <p>Because Open OnDemand routes all compute through scheduled jobs, you get the full speed of dedicated compute hardware and GPUs without violating cluster usage policies or risking process kills on login nodes.</p> <hr/> <h2 id="summary-the-interactive-computing-checklist">Summary: The Interactive Computing Checklist</h2> <p>Interactive development and HPC compute can easily coexist if you follow these rules:</p> <ol> <li><strong>Never run Jupyter Notebooks or VS Code Server processes on login nodes.</strong> Keep login nodes clean for light editing and job submission.</li> <li><strong>Check for Open OnDemand first.</strong> If your site hosts an Open OnDemand portal, use it for one-click interactive web sessions.</li> <li><strong>Allocate compute nodes before launching servers manually.</strong> Always start with an interactive job allocation (<code class="language-plaintext highlighter-rouge">srun</code> or <code class="language-plaintext highlighter-rouge">qsub</code>).</li> <li><strong>Tunnel securely with <code class="language-plaintext highlighter-rouge">ssh -L</code>.</strong> Forward local ports through the login host to the specific compute node hosting your active server.</li> <li><strong>Clean up when finished.</strong> Terminate your interactive compute sessions and close notebook servers when you finish working so cluster resources return to the queue for other researchers.</li> </ol>]]></content><author><name>Cooperative Computing Lab</name></author><category term="technical-articles"/><category term="hpc"/><category term="vscode"/><category term="jupyter"/><category term="open-ondemand"/><category term="ssh"/><summary type="html"><![CDATA[Bridge the gap between local, GUI-based development and remote cluster compute without crashing login nodes or violating HPC policies.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/interactive-computing/hero-image.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/interactive-computing/hero-image.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">SADE-SIM at FSE 2026</title><link href="https://ccl.cse.nd.edu/blog/2026/fse-2026-highlights/" rel="alternate" type="text/html" title="SADE-SIM at FSE 2026"/><published>2026-07-15T17:00:00+00:00</published><updated>2026-07-15T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/fse-2026-highlights</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/fse-2026-highlights/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/fse-2026-highlights/fse-hero-image-480.webp 480w,/assets/blog/2026/fse-2026-highlights/fse-hero-image-800.webp 800w,/assets/blog/2026/fse-2026-highlights/fse-hero-image-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/fse-2026-highlights/fse-hero-image.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="FSE 2026" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>This July, CCL lab member <strong>Lax</strong> traveled to Montreal, Canada for <strong><a href="https://conf.researchr.org/home/fse-2026">FSE 2026</a></strong>, the ACM International Conference on the Foundations of Software Engineering, to present our paper <strong><a href="https://ccl.cse.nd.edu/assets/paper/pdf/sade-sim-2026.pdf">SADE-SIM: A Scalable Simulation Platform for Validating City-Scale Multi-sUAS Missions</a></strong>.</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/fse-2026-highlights/IMG_5483-480.webp 480w,/assets/blog/2026/fse-2026-highlights/IMG_5483-800.webp 800w,/assets/blog/2026/fse-2026-highlights/IMG_5483-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/fse-2026-highlights/IMG_5483.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>SADE-SIM is a hybrid simulation framework that pairs physical accuracy with photorealistic visualization to support large multi-sUAS deployments at city scale. It’s built to close a gap in existing tools, which typically handle only a handful of concurrent vehicles and fall short on the fidelity needed to evaluate vision-based navigation, sensor degradation in urban environments, and compliance with evolving airspace regulations. The platform brings together web-based mission planning, real-time control compatible with standard protocols, live video stream visualization, and archival review of flight data.</p> <p>To show what the system can do, Lax presented a case study built around a 32-sUAS heterogeneous fleet flying diverse mission profiles through a restricted airspace zone, where vehicles dynamically request entry and the system evaluates mission-critical safety parameters before granting access.</p> <p>Between sessions, Lax followed the <strong><a href="https://conf.researchr.org/program/fse-2026/program-fse-2026/">conference program</a></strong>, catching keynotes, technical tracks, and plenty of hallway conversations along the way. FSE still has that familiar, vibrant mix of software engineering foundations, automated testing, and cyber-physical systems validation. Testing and validating autonomous systems was clearly a hot topic this year, coming up again and again across sessions and informal chats about deployment safety at scale.</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/fse-2026-highlights/IMG_5477-480.webp 480w,/assets/blog/2026/fse-2026-highlights/IMG_5477-800.webp 800w,/assets/blog/2026/fse-2026-highlights/IMG_5477-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/fse-2026-highlights/IMG_5477.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Thanks to everyone who came to the SADE-SIM session and to the FSE organizers for another smooth run. We’re glad to have the paper out in the proceedings, and we’re looking forward to continuing these conversations with researchers and practitioners working on the safety, validation, and scalability of autonomous aerial systems.</p> <p>You can view the presentation slides <strong><a href="/assets/blog/2026/fse-2026-highlights/SADE-SIM-Presentation.pdf">here</a></strong>.</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/fse-2026-highlights/20260706_175305-480.webp 480w,/assets/blog/2026/fse-2026-highlights/20260706_175305-800.webp 800w,/assets/blog/2026/fse-2026-highlights/20260706_175305-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/fse-2026-highlights/20260706_175305.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div>]]></content><author><name>Cooperative Computing Lab</name></author><category term="news"/><category term="news"/><category term="conference"/><summary type="html"><![CDATA[CCL fist-year PhD student Lax traveled to FSE 2026 in Montreal, Canada to present his work, "SADE-SIM: A Scalable Simulation Platform for Validating City-Scale Multi-sUAS Missions."]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/fse-2026-highlights/fse-hero-image.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/fse-2026-highlights/fse-hero-image.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">Conda, Modules, and Containers: How to Manage Your Software Without Breaking the Cluster</title><link href="https://ccl.cse.nd.edu/blog/2026/containers-on-clusters/" rel="alternate" type="text/html" title="Conda, Modules, and Containers: How to Manage Your Software Without Breaking the Cluster"/><published>2026-07-07T17:00:00+00:00</published><updated>2026-07-07T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/containers-on-clusters</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/containers-on-clusters/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/containers-on-clusters/conda-logo-480.webp 480w,/assets/blog/2026/containers-on-clusters/conda-logo-800.webp 800w,/assets/blog/2026/containers-on-clusters/conda-logo-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/containers-on-clusters/conda-logo.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>If you are transitioning from running code on your personal laptop to using a high-performance computing (HPC) cluster, you are about to encounter a major cultural shock: <strong>you do not have <code class="language-plaintext highlighter-rouge">sudo</code> privileges.</strong> On your own machine, installing a new tool is as simple as running <code class="language-plaintext highlighter-rouge">sudo apt-get install</code>, <code class="language-plaintext highlighter-rouge">brew install</code>, or clicking an installer. On a shared cluster, these commands will reward you with a blunt <code class="language-plaintext highlighter-rouge">Permission denied</code>. This restriction isn’t just bureaucratic cruelty; it is a fundamental safety measure. In a shared environment with hundreds of users, giving everyone root access would lead to broken configurations, security breaches, and software chaos.</p> <p>So, how do you install the specific libraries, languages, and tools your research requires?</p> <p>HPC systems use three primary tools for software management: <strong>Environment Modules</strong>, <strong>Conda</strong>, and <strong>Containers</strong>. Each has its own strengths, and using them correctly will save you days of troubleshooting—and keep you from accidentally drawing the ire of the cluster administrators.</p> <h2 id="level-1-environment-modules-the-built-in-way">Level 1: Environment Modules (The Built-In Way)</h2> <p>Before you try to download or compile anything yourself, you should check if the cluster administrators have already installed it for you. HPC systems use an environment management tool called <strong>Modules</strong> to manage hundreds of pre-installed, highly optimized software packages.</p> <p>Because different researchers need different versions of the same software (e.g., Python 3.8 vs. Python 3.11, or different versions of CUDA), these packages sit dormant on the system until you explicitly ask for them.</p> <h3 id="key-commands-to-know">Key Commands to Know:</h3> <ul> <li><strong><code class="language-plaintext highlighter-rouge">module avail</code></strong>: Displays a massive list of all software packages pre-compiled on the cluster. You can filter this by adding a keyword, such as <code class="language-plaintext highlighter-rouge">module avail python</code> or <code class="language-plaintext highlighter-rouge">module avail gcc</code>.</li> <li><strong><code class="language-plaintext highlighter-rouge">module load &lt;package&gt;</code></strong>: Injects the chosen software into your current terminal session. For example, running <code class="language-plaintext highlighter-rouge">module load python/3.10.8</code> updates your environment so that typing <code class="language-plaintext highlighter-rouge">python</code> points directly to that specific version.</li> <li><strong><code class="language-plaintext highlighter-rouge">module list</code></strong>: Shows you which modules are currently active in your session.</li> <li><strong><code class="language-plaintext highlighter-rouge">module purge</code></strong>: Clears out all loaded modules, giving you a clean slate. This is incredibly useful if two software packages are conflicting with one another.</li> </ul> <h3 id="why-you-should-use-them">Why you should use them:</h3> <p>Modules are pre-compiled specifically for the cluster’s underlying hardware. This means they are often optimized to run significantly faster than a generic version you download off the internet. Best of all, they take up exactly zero bytes of your personal storage quota. <strong>Always check <code class="language-plaintext highlighter-rouge">module avail</code> first.</strong></p> <h2 id="level-2-conda--miniconda-the-user-space-way">Level 2: Conda / Miniconda (The User-Space Way)</h2> <p>What happens when you need a Python library or a niche scientific package that isn’t in the module list? For most data scientists and researchers, the immediate answer is <strong>Conda</strong>.</p> <p>Conda allows you to create completely isolated “sandboxes” (environments) where you can install any package version you want entirely within your user account. However, Conda comes with two massive pitfalls that frequently break beginners’ workflows.</p> <h3 id="pitfall-1-the-home-directory-trap">Pitfall #1: The Home Directory Trap</h3> <p>By default, when you run <code class="language-plaintext highlighter-rouge">conda create</code> or <code class="language-plaintext highlighter-rouge">conda install</code>, Conda downloads and extracts files into a hidden folder in your home directory (<code class="language-plaintext highlighter-rouge">~/.conda</code> or <code class="language-plaintext highlighter-rouge">~/.cache</code>).</p> <p>On almost all HPC clusters, your home directory (<code class="language-plaintext highlighter-rouge">/home/username</code>) has a <strong>strict, tiny storage quota</strong> (often between 10GB and 50GB) intended only for configuration files and source code. Because modern data science environments (especially those involving PyTorch or TensorFlow) can easily balloon to 10GB+ per environment, running a few installations can completely max out your storage quota. When this happens, you won’t even be able to log in or run basic commands.</p> <h4 id="the-fix-redirect-conda-to-storage-or-scratch">The Fix: Redirect Conda to Storage or Scratch</h4> <p>Before installing anything with Conda, tell it to store its environments and package caches in your lab’s high-capacity group folder or a fast scratch directory. You can do this by creating or editing a configuration file named <code class="language-plaintext highlighter-rouge">.condarc</code> in your home directory:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># ~/.condarc</span>
<span class="na">envs_dirs</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">/scratch/username/conda/envs</span>
  <span class="pi">-</span> <span class="s">/project/labname/shared_conda/envs</span>
<span class="na">pkgs_dirs</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s">/scratch/username/conda/pkgs</span>
</code></pre></div></div> <p>Replace <code class="language-plaintext highlighter-rouge">/scratch/username/</code> or <code class="language-plaintext highlighter-rouge">/project/labname/</code> with the actual high-capacity data paths provided by your cluster administrators.</p> <h3 id="pitfall-2-compiling-on-the-login-node">Pitfall #2: Compiling on the Login Node</h3> <p>When you log into a cluster, you land on a “login node.” This node is a shared hallway where hundreds of users are editing files and submitting jobs.</p> <p>Running a heavy command like <code class="language-plaintext highlighter-rouge">conda env create -f environment.yml</code> fires up intense CPU and memory processes to resolve dependencies and compile code. Doing this on a login node will slow down the terminal experience for everyone else on the cluster and will usually trigger an automated system script that kills your process mid-installation.</p> <h4 id="the-fix-use-an-interactive-compute-session">The Fix: Use an Interactive Compute Session</h4> <p>Whenever you need to build or modify a Conda environment, request a temporary compute node using SLURM’s interactive mode:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Request an interactive shell on a compute node for 1 hour</span>
srun <span class="nt">--tasks</span><span class="o">=</span>1 <span class="nt">--cpus-per-task</span><span class="o">=</span>2 <span class="nt">--mem</span><span class="o">=</span>8G <span class="nt">--time</span><span class="o">=</span>01:00:00 <span class="nt">--pty</span> bash
</code></pre></div></div> <p>Once your terminal transfers you to a compute node (e.g., <code class="language-plaintext highlighter-rouge">user@node042</code>), you can safely run your Conda installation commands without affecting anyone else.</p> <h2 id="level-3-containers-the-bulletproof-way">Level 3: Containers (The Bulletproof Way)</h2> <p>Sometimes, even Conda isn’t enough. If your workflow requires a complex web of system libraries, an entirely different operating system (like a specific version of Ubuntu when the cluster runs Rocky Linux), or you want to replicate an exact software pipeline from a published paper, you need <strong>containers</strong>.</p> <p>In the commercial tech world, <strong>Docker</strong> is the king of containers. However, Docker is fundamentally incompatible with shared HPC clusters because running Docker requires a background process (daemon) with root privileges. If you could run Docker on a cluster, you could easily bypass security and access other users’ data.</p> <h3 id="apptainer--singularity-to-the-rescue">Apptainer / Singularity to the Rescue</h3> <p>To solve this, the HPC community developed <strong>Apptainer</strong> (formerly known as Singularity). Apptainer allows you to run containers completely in “user space” without needing <code class="language-plaintext highlighter-rouge">sudo</code>.</p> <p>Instead of dealing with background daemons, Apptainer compresses an entire container environment into a single, portable file ending in <code class="language-plaintext highlighter-rouge">.sif</code> (Singularity Image Format).</p> <h3 id="key-commands-to-know-1">Key Commands to Know:</h3> <ol> <li><strong>Download and Convert a Docker Image:</strong> You can pull almost any public image directly from Docker Hub, and Apptainer will automatically translate it into an HPC-safe <code class="language-plaintext highlighter-rouge">.sif</code> file: <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apptainer pull ubuntu_python.sif docker://python:3.11-slim
</code></pre></div> </div> </li> <li><strong>Execute a Command Inside the Container:</strong> To run your code using the software isolated inside that container image, use <code class="language-plaintext highlighter-rouge">exec</code>: <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apptainer <span class="nb">exec </span>ubuntu_python.sif python3 my_script.py
</code></pre></div> </div> </li> <li><strong>Run an Interactive Shell Inside the Container:</strong> If you want to look around inside your containerized operating system environment: <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apptainer shell ubuntu_python.sif
</code></pre></div> </div> </li> </ol> <h3 id="why-you-should-use-them-1">Why you should use them:</h3> <p>Containers are the ultimate tool for <strong>scientific reproducibility</strong>. Once you find a container configuration that works, that <code class="language-plaintext highlighter-rouge">.sif</code> file will run exactly the same way on your university cluster, a national lab supercomputer, or a cloud instance five years from now.</p> <h2 id="summary-the-software-management-checklist">Summary: The Software Management Checklist</h2> <p>To keep your account active and the cluster running smoothly, run through this mental checklist every time you need new software:</p> <ol> <li><strong>Check <code class="language-plaintext highlighter-rouge">module avail</code> first.</strong> If it’s already installed by the system administrators, load it and move on.</li> <li><strong>Check your storage quotas.</strong> Run your cluster’s quota check command (like <code class="language-plaintext highlighter-rouge">myquota</code> or <code class="language-plaintext highlighter-rouge">lfs quota</code>) to ensure your home directory isn’t on the verge of filling up.</li> <li><strong>Configure your <code class="language-plaintext highlighter-rouge">.condarc</code> file.</strong> Never leave Conda on its default settings; always point your environment and package directories to a high-capacity scratch or group folder.</li> <li><strong>Never install software on a login node.</strong> Use <code class="language-plaintext highlighter-rouge">srun</code> to spin up an interactive compute session before compiling or running extensive installers.</li> <li><strong>Use Apptainer for complex pipelines.</strong> If a workflow requires intricate system dependencies or absolute reproducibility, skip the installation headaches entirely and look for a container image.</li> </ol>]]></content><author><name>Cooperative Computing Lab</name></author><category term="technical-articles"/><category term="hpc"/><category term="conda"/><category term="modules"/><category term="containers"/><category term="hpc"/><summary type="html"><![CDATA[Managing software on a shared supercomputer is completely different from your personal laptop. Here is how to use Modules, Conda, and Containers effectively without exhausting your storage or crashing the cluster.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/containers-on-clusters/conda-logo.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/containers-on-clusters/conda-logo.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">Getting Started with SLURM</title><link href="https://ccl.cse.nd.edu/blog/2026/getting-started-with-slurm/" rel="alternate" type="text/html" title="Getting Started with SLURM"/><published>2026-07-01T17:00:00+00:00</published><updated>2026-07-01T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/getting-started-with-slurm</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/getting-started-with-slurm/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/getting-started-with-slurm/Slurm_logo_sized-1875592753-480.webp 480w,/assets/blog/2026/getting-started-with-slurm/Slurm_logo_sized-1875592753-800.webp 800w,/assets/blog/2026/getting-started-with-slurm/Slurm_logo_sized-1875592753-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/getting-started-with-slurm/Slurm_logo_sized-1875592753.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>When you log into a university or national lab cluster, you aren’t logging directly into the powerful machines that run your code. Instead, you land on a “login node” shared with dozens of other users. To actually run your heavy computations, you have to request permission from a gatekeeper.</p> <p>On most High-Performance Computing (HPC) systems today, that gatekeeper is <strong>SLURM</strong> (Simple Linux Utility for Resource Management). Think of SLURM as a reservation system for a supercomputer. While it has a reputation for being complex, most day-to-day work comes down to a handful of basic commands. This guide covers the essential subset you need to get started: submitting jobs, monitoring them, stopping them when things go sideways, and understanding why they might be stuck in line.</p> <p><strong>One major caveat:</strong> SLURM is highly configurable, and every institution customizes it differently. Queue names, time limits, memory defaults, and specific resource rules vary from cluster to cluster. The commands here are standard SLURM, but you should always cross-reference them with your local site’s documentation.</p> <h2 id="submitting-a-job">Submitting a Job</h2> <p>You don’t run heavy scripts directly in the terminal on an HPC. Instead, you wrap your commands in a shell script and hand it over to SLURM using the <code class="language-plaintext highlighter-rouge">sbatch</code> command:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sbatch my_job.sh
</code></pre></div></div> <p>When SLURM accepts your job, it assigns it a unique <strong>Job ID</strong> and prints it to the screen:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Submitted batch job 847312
</code></pre></div></div> <p>You will use this number to track, manage, or cancel your job. A minimal, beginner-friendly job script looks like this:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c">#SBATCH --job-name=hpc-demo</span>
<span class="c">#SBATCH --output=hpc-demo-%j.out</span>
<span class="c">#SBATCH --error=hpc-demo-%j.err</span>
<span class="c">#SBATCH --time=04:00:00</span>
<span class="c">#SBATCH --ntasks=1</span>
<span class="c">#SBATCH --cpus-per-task=4</span>
<span class="c">#SBATCH --mem=8G</span>

<span class="c"># The commands below will run on the compute node once allocated:</span>
<span class="nb">echo</span> <span class="s2">"Starting my analysis..."</span>
python3 my_analysis_script.py <span class="nt">--input</span> data.csv
</code></pre></div></div> <p>The special <code class="language-plaintext highlighter-rouge">#SBATCH</code> lines at the top tell SLURM exactly what resources your code needs to run.</p> <h3 id="what-do-these-headers-mean">What do these headers mean?</h3> <ul> <li><code class="language-plaintext highlighter-rouge">--job-name</code>: A friendly nickname for your job so you can spot it easily in the queue.</li> <li><code class="language-plaintext highlighter-rouge">--output</code> and <code class="language-plaintext highlighter-rouge">--error</code>: Where your program’s text output and error messages should be saved. The <code class="language-plaintext highlighter-rouge">%j</code> is a variable that automatically fills in your unique Job ID, preventing different runs from overwriting each other’s logs.</li> <li><code class="language-plaintext highlighter-rouge">--time</code>: The maximum runtime allowed (Hours:Minutes:Seconds). If your job exceeds this, SLURM will stop it automatically.</li> <li><code class="language-plaintext highlighter-rouge">--cpus-per-task</code> and <code class="language-plaintext highlighter-rouge">--mem</code>: The requested number of CPU cores and total RAM (8 Gigabytes in this case).</li> </ul> <h2 id="passing-arguments-header-vs-command-line">Passing Arguments: Header vs. Command Line</h2> <p>Every <code class="language-plaintext highlighter-rouge">#SBATCH</code> line inside your script is identical to passing a flag directly to <code class="language-plaintext highlighter-rouge">sbatch</code> on the command line. These two methods accomplish the exact same thing:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Option A: All configuration is kept inside the script header</span>
sbatch my_job.sh

<span class="c"># Option B: Overriding the script's defaults from the command line</span>
sbatch <span class="nt">--time</span><span class="o">=</span>08:00:00 <span class="nt">--mem</span><span class="o">=</span>16G my_job.sh
</code></pre></div></div> <p>Command-line flags always take precedence over header directives. The best habit to build is putting your <strong>sensible defaults</strong> in the script header—the values you expect to use 90% of the time—and then overriding them on the command line for one-off experiments that require extra memory or longer runtimes.</p> <h2 id="watching-your-jobs">Watching Your Jobs</h2> <p>Once you submit a job, <code class="language-plaintext highlighter-rouge">squeue</code> is the command you will use most often. Running it without arguments shows every single job currently running on the entire cluster, which is overwhelming. Instead, filter it to show only your jobs:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>squeue <span class="nt">-u</span> <span class="nv">$USER</span>
</code></pre></div></div> <p>The output will look something like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>JOBID    PARTITION  NAME        USER     ST   TIME   NODES  NODELIST(REASON)
847312   general    hpc-demo    dthain   R    0:42   1      node047
847313   general    hpc-demo    dthain   PD   0:00   1      (Resources)
847314   general    hpc-demo    dthain   PD   0:00   1      (Priority)
</code></pre></div></div> <p>The <strong>ST (State)</strong> column tells you what your job is currently doing:</p> <ul> <li><strong><code class="language-plaintext highlighter-rouge">R</code> (Running):</strong> Your job is actively executing on a compute node.</li> <li><strong><code class="language-plaintext highlighter-rouge">PD</code> (Pending):</strong> Your job is waiting in line.</li> </ul> <p>The <strong><code class="language-plaintext highlighter-rouge">NODELIST(REASON)</code></strong> column explains <em>why</em> a pending job hasn’t started yet. <code class="language-plaintext highlighter-rouge">(Resources)</code> means the cluster is currently full and waiting for other users’ jobs to finish. <code class="language-plaintext highlighter-rouge">(Priority)</code> means your job is sitting behind higher-priority work in the queue.</p> <p>If you want to check when SLURM expects your job to start, add the <code class="language-plaintext highlighter-rouge">--start</code> flag:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>squeue <span class="nt">-u</span> <span class="nv">$USER</span> <span class="nt">--start</span>
</code></pre></div></div> <p><em>Note: SLURM’s start-time estimates are notoriously optimistic, as they assume every running job will use its maximum requested time. Treat these numbers as rough ballparks rather than guarantees.</em></p> <h2 id="cancelling-a-job">Cancelling a Job</h2> <p>If you realize your script has a bug, or you accidentally requested the wrong parameters, you can clear it out of the system using <code class="language-plaintext highlighter-rouge">scancel</code> and its Job ID:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scancel 847312
</code></pre></div></div> <p>To wipe the slate clean and cancel <strong>all</strong> of your jobs at once:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scancel <span class="nt">-u</span> <span class="nv">$USER</span>
</code></pre></div></div> <p>If you only want to clear out your waiting jobs while letting your active, running jobs finish safely, specify the pending state:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scancel <span class="nt">-u</span> <span class="nv">$USER</span> <span class="nt">-t</span> pending
</code></pre></div></div> <h2 id="checking-cluster-availability">Checking Cluster Availability</h2> <p>Before you submit a massive job, it is helpful to see how busy the cluster is. The <code class="language-plaintext highlighter-rouge">sinfo</code> command provides a snapshot of the available hardware pools (called “partitions”):</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sinfo
</code></pre></div></div> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PARTITION  AVAIL  TIMELIMIT   NODES  STATE   NODELIST
general*   up     7-00:00:00  12     idle    node[001-012]
gpu        up     2-00:00:00  4      mix     gpu[01-04]
debug      up     0-01:00:00  2      idle    node[013-014]
</code></pre></div></div> <p>Pay attention to the <strong>STATE</strong> column:</p> <ul> <li><strong><code class="language-plaintext highlighter-rouge">idle</code>:</strong> The nodes are completely free and ready for work.</li> <li><strong><code class="language-plaintext highlighter-rouge">mix</code>:</strong> Some CPU cores on these nodes are busy, but others are still available.</li> <li><strong><code class="language-plaintext highlighter-rouge">alloc</code>:</strong> The nodes are completely full.</li> <li><strong><code class="language-plaintext highlighter-rouge">drain</code>:</strong> The nodes have been taken offline by administrators for maintenance.</li> </ul> <h2 id="inspecting-a-live-or-stuck-job">Inspecting a Live or Stuck Job</h2> <p>For detailed troubleshooting on a specific job, <code class="language-plaintext highlighter-rouge">scontrol show job</code> will output a comprehensive diagnostic record:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>scontrol show job 847312
</code></pre></div></div> <p>The output is quite long, but look closely for <code class="language-plaintext highlighter-rouge">JobState</code>, <code class="language-plaintext highlighter-rouge">Reason</code>, and <code class="language-plaintext highlighter-rouge">TRES</code> (the exact resource request). If a job has been pending for days, the <code class="language-plaintext highlighter-rouge">Reason</code> field will often reveal if it is blocked by an administrative hold, an impossible resource request, or standard queue traffic.</p> <h2 id="checking-what-completed-jobs-actually-used">Checking What Completed Jobs <em>Actually</em> Used</h2> <p>One of the biggest mistakes beginners make is overestimating how much memory or time their code needs. Requesting too many resources forces your job to wait in line much longer than necessary.</p> <p>To look back at a completed job and see its actual resource footprint, use <code class="language-plaintext highlighter-rouge">sacct</code>:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sacct <span class="nt">-j</span> 847312 <span class="nt">--format</span><span class="o">=</span>JobID,JobName,State,Elapsed,MaxRSS,ReqMem
</code></pre></div></div> <p>The <strong><code class="language-plaintext highlighter-rouge">MaxRSS</code></strong> field shows the peak amount of RAM your job actually consumed during its run. Compare this against <strong><code class="language-plaintext highlighter-rouge">ReqMem</code></strong> (what you requested). If your job only used 2GB of RAM but you requested 32GB, you are artificially delaying your own queue times. Aim to request roughly 20–30% more memory than your historical peak to keep your queue times short while avoiding out-of-memory errors.</p> <h2 id="a-few-silent-pitfalls-to-avoid">A Few Silent Pitfalls to Avoid</h2> <p>SLURM enforces local cluster rules strictly, and it often does so silently. Keep these four items in mind as you review your institution’s specific user guide:</p> <ul> <li><strong>Partition Time Caps:</strong> Most cluster queues have hard maximum runtimes (e.g., a 24-hour limit). If you ask for 48 hours on a 24-hour queue, SLURM will reject your job the second you attempt to submit it.</li> <li><strong>Account Flags:</strong> Many institutions require you to specify a billing project or account via <code class="language-plaintext highlighter-rouge">--account=my_lab_group</code>. If you omit this, your job may fail instantly or be assigned to a lowest-priority pool.</li> <li><strong>Silent Memory Defaults:</strong> If you don’t specify a <code class="language-plaintext highlighter-rouge">--mem</code> flag, SLURM will assign you a default value per core. On some clusters, this default can be incredibly small (like 1GB), causing your program to crash unexpectedly with an <code class="language-plaintext highlighter-rouge">OUT_OF_MEMORY</code> error. Always declare your memory explicitly.</li> <li><strong>Job Arrays for Repetitive Work:</strong> If you need to run the exact same analysis script over 50 different data files, do not run <code class="language-plaintext highlighter-rouge">sbatch</code> 50 separate times. Instead, look into <strong>Job Arrays</strong> using <code class="language-plaintext highlighter-rouge">sbatch --array=1-50</code>. It allows the scheduler to handle your workload as a single cohesive unit, saving your sanity and keeping the cluster running smoothly.</li> </ul>]]></content><author><name>Cooperative Computing Lab</name></author><category term="technical-articles"/><category term="slurm"/><category term="tutorial"/><category term="hpc"/><summary type="html"><![CDATA[SLURM is the job scheduler running on most HPC clusters today. Here are the commands and habits that get you productive quickly as an end-user, without having to read the entire manual first.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/getting-started-with-slurm/Slurm_logo_sized-1875592753.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/getting-started-with-slurm/Slurm_logo_sized-1875592753.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">Work Queue Insights: Practical Debugging on HPC Systems</title><link href="https://ccl.cse.nd.edu/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/" rel="alternate" type="text/html" title="Work Queue Insights: Practical Debugging on HPC Systems"/><published>2026-06-23T17:00:00+00:00</published><updated>2026-06-23T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/Work-Queue-Insights-480.webp 480w,/assets/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/Work-Queue-Insights-800.webp 800w,/assets/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/Work-Queue-Insights-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/Work-Queue-Insights.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Debugging distributed systems on HPC has its own rhythm. The feedback loop is slow, the machines are shared, and the error you are chasing may only appear under load, across nodes, or after a scheduler delay you cannot reproduce locally. This note grew out of <a href="https://github.com/cooperative-computing-lab/cctools/issues/4415">issue #4415</a>: a segmentation fault (SIGSEGV) in <code class="language-plaintext highlighter-rouge">task_min_resources</code> inside <a href="https://github.com/cooperative-computing-lab/cctools/tree/master/work_queue/src"><code class="language-plaintext highlighter-rouge">work_queue.c</code></a>, triggered by Makeflow running a large parallel workflow in Work Queue mode.</p> <p>The habits below are less about any single tool and more about discipline: keeping your changes visible, your experiments small, and your teammates in the loop. They apply equally whether you are working in <a href="https://github.com/cooperative-computing-lab/cctools/tree/master/work_queue/src"><code class="language-plaintext highlighter-rouge">work_queue.c</code></a> or anywhere else in a large C codebase running on a shared cluster.</p> <h2 id="talk-to-your-teammates-early-and-often">Talk to your teammates early and often</h2> <p>The most underrated debugging tool is a colleague. When you hit a wall the instinct is to keep grinding alone until you have something to show. Resist it. A two-sentence description of what you changed and where you are stuck surfaces assumptions you did not know you were making before you spend a day looking in the wrong function.</p> <p>Post a short note to your team channel whenever you switch gears. If you are about to run a batch of SLURM jobs to test a hypothesis, say so. Someone may have already run that experiment, or may know that the catalog tick interval is configurable and could be shortened for testing.</p> <p>The flip side: when someone asks for help, give them the full picture up front. Paste the Valgrind output, the backtrace, and a short description of what you have already tried. “Here is what I know” cuts the back-and-forth in half.</p> <h2 id="put-your-changes-somewhere-others-can-see-them">Put your changes somewhere others can see them</h2> <p>Debugging on HPC usually means modifying source, rebuilding, and staging a binary on a shared login node where the next person has no idea what you changed. The fix is obvious but easy to skip when you are in a hurry: commit and push early, to a branch, a fork, or a scratch repository your colleagues can actually reach.</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git checkout <span class="nt">-b</span> debug/task-min-resources-segfault
<span class="c"># edit work_queue/src/work_queue.c</span>
git add work_queue/src/work_queue.c
git commit <span class="nt">-m</span> <span class="s2">"add null check before task_min_resources dereferences ready list node"</span>
git push origin debug/task-min-resources-segfault
</code></pre></div></div> <p>A pushed branch does several things at once. It gives collaborators a URL to look at instead of a terminal paste. It lets them check out your exact tree, reproduce the build, and point out something you missed. And it is an automatic checkpoint: if <code class="language-plaintext highlighter-rouge">make clean</code> goes sideways or a node corrupts your scratch directory, the work is not gone. Uncommitted changes on a cluster login node are one bad disk event away from disappearing.</p> <h2 id="keep-a-running-log-of-what-you-changed-and-why">Keep a running log of what you changed and why</h2> <p>Segfault hunts often take days or weeks. Memory is not reliable across that span. Keep a plain text file, a section in the PR description, or a lab notebook — and update it every time you try something:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2026-06-09  opened #4415; Valgrind log attached; fault site is work_queue.c:8174 in task_min_resources
2026-06-10  added null check on q-&gt;ready_list head before dereferencing — crash still appears on run 3 of 5
2026-06-11  hypothesis: node is removed from the ready list but list_next still returns it; added fprintf around list traversal
2026-06-12  confirmed: stale pointer survives across catalog tick; looking at where nodes are freed vs unlinked
</code></pre></div></div> <p>This log is not for posterity. It is for you, tomorrow morning, when you cannot remember why you commented out that block. It is also what you paste when you ask a teammate for help.</p> <h2 id="scale-down-before-you-scale-out">Scale down before you scale out</h2> <p>Submitting a five-hundred-task Makeflow workflow to test a one-line fix is one of the most reliable ways to waste an afternoon. Queue wait times are unpredictable, the logs from hundreds of workers are noisy, and if the fix is wrong you have burned allocation budget and still do not know why.</p> <p>The better approach is to find or construct the smallest possible reproducer. Once the small case reproduces reliably, you have a debuggable target. Only when that case is clean do you run at scale to confirm nothing regresses. This discipline also makes it far easier to share a reproducer with a teammate: “clone, run these two commands, watch it crash” is a much better bug report than “submit two hundred SLURM jobs and search the logs.”</p> <h2 id="instrument-the-code-before-you-reach-for-a-debugger">Instrument the code before you reach for a debugger</h2> <p>Before attaching GDB or running Valgrind, the fastest thing you can do is add targeted <code class="language-plaintext highlighter-rouge">fprintf</code> calls to verify that your fix is actually being reached. This sounds obvious, and yet the most common source of “my patch does nothing” confusion is that the code path you edited is never entered for the input you are testing.</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* In work_queue.c, before the dereference that Valgrind flagged */</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"[DEBUG] task_min_resources: checking node %p on ready list</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">t</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">t</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"[DEBUG] task_min_resources: null node encountered — skipping</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">continue</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"[DEBUG] task_min_resources: node task_id=%d resources_requested=%p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
        <span class="n">t</span><span class="o">-&gt;</span><span class="n">taskid</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">t</span><span class="o">-&gt;</span><span class="n">resources_requested</span><span class="p">);</span>
</code></pre></div></div> <p>Write to <code class="language-plaintext highlighter-rouge">stderr</code>, not <code class="language-plaintext highlighter-rouge">stdout</code>, which may be buffered or redirected by the framework. Add prints before and after the critical section. If the “before” line appears but the “after” line does not, you found the crash site. If neither appears, the function is not being called — which means the bug is upstream of where you thought it was, and you just saved yourself an hour of reading the wrong code.</p> <p>If the prints confirm your fix is being reached but the crash keeps happening, the root cause is elsewhere: probably the point where the stale node enters the list, not the point where it is dereferenced. Move the instrumentation upstream.</p> <p>Gate these prints behind a compile-time flag before merging so they do not pollute production builds:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#ifdef WQ_DEBUG_TASK_RESOURCES
</span><span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"[DEBUG] task_min_resources: node %p task_id=%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
        <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">t</span><span class="p">,</span> <span class="n">t</span><span class="o">-&gt;</span><span class="n">taskid</span><span class="p">);</span>
<span class="cp">#endif
</span></code></pre></div></div> <p>Pass <code class="language-plaintext highlighter-rouge">-DWQ_DEBUG_TASK_RESOURCES</code> in <code class="language-plaintext highlighter-rouge">CFLAGS</code> to turn them on; a normal build leaves no noise.</p> <h2 id="reach-for-gdb-and-valgrind-when-instrumentation-is-not-enough">Reach for GDB and Valgrind when instrumentation is not enough</h2> <p>When <code class="language-plaintext highlighter-rouge">fprintf</code> tells you where the crash is but not why, it is time to bring in a real debugger. For a crash you can reproduce locally, GDB is the first stop:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Build with debug symbols and no optimization so variables are readable</span>
./configure <span class="nv">CFLAGS</span><span class="o">=</span><span class="s2">"-g -O0"</span>
make <span class="nt">-C</span> work_queue/src
 
<span class="c"># Run until it crashes, then inspect the frame</span>
gdb <span class="nt">--args</span> work_queue_worker <span class="nt">-d</span> all localhost 9123
<span class="o">(</span>gdb<span class="o">)</span> run
<span class="o">(</span>gdb<span class="o">)</span> bt                        <span class="c"># full backtrace at the crash point</span>
<span class="o">(</span>gdb<span class="o">)</span> frame 2                   <span class="c"># switch to the frame inside task_min_resources</span>
<span class="o">(</span>gdb<span class="o">)</span> p t                       <span class="c"># is the pointer null or garbage?</span>
<span class="o">(</span>gdb<span class="o">)</span> p t-&gt;resources_requested  <span class="c"># does the struct look sane?</span>
<span class="o">(</span>gdb<span class="o">)</span> watch t-&gt;taskid           <span class="c"># set a watchpoint to catch when this field changes</span>
</code></pre></div></div> <p>Valgrind slows execution by roughly ten to twenty times, so pair it with the scaled-down reproducer from the previous section. A handful of short tasks that trigger the ready-list traversal during a catalog tick is a much better target than a full production workflow.</p> <p>One practical note: you generally cannot run GDB interactively inside a SLURM job. If the bug only appears at scale, use Work Queue’s <code class="language-plaintext highlighter-rouge">-d all</code> flag to write a verbose trace to a shared filesystem path that both the execute node and your login node can read:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>work_queue_worker <span class="nt">-d</span> all <span class="nt">-o</span> /cephfs/group/myproject/wq-logs/worker-<span class="si">$(</span><span class="nb">date</span> +%Y%m%d%H%M%S<span class="si">)</span>.log <span class="se">\</span>
  localhost 9123
</code></pre></div></div> <p>Then reconstruct a local reproducer from what the trace tells you, and use GDB on that.</p> <h2 id="read-the-logs-that-are-already-there">Read the logs that are already there</h2> <p>Before adding instrumentation or firing up a debugger, check what Work Queue already records. The <code class="language-plaintext highlighter-rouge">-d all</code> flag produces a structured trace across subsystems — scheduling decisions, catalog updates, task state transitions — that often answers the question before you write a single <code class="language-plaintext highlighter-rouge">fprintf</code>.</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Watch the debug stream in real time on a local test run</span>
work_queue_worker <span class="nt">-d</span> all localhost 9123 2&gt;&amp;1 | <span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"task_min</span><span class="se">\|</span><span class="s2">ready</span><span class="se">\|</span><span class="s2">segfault</span><span class="se">\|</span><span class="s2">null</span><span class="se">\|</span><span class="s2">error"</span>
 
<span class="c"># After a cluster run, search a saved log</span>
<span class="nb">grep</span> <span class="nt">-n</span> <span class="s2">"task_min_resources</span><span class="se">\|</span><span class="s2">ready_list"</span> worker-20260609.log | <span class="nb">head</span> <span class="nt">-40</span>
</code></pre></div></div> <p>The log format uses timestamps and subsystem tags, so you can narrow a twenty-thousand-line trace to the thirty lines around the catalog tick event without much effort. For the #4415 bug in particular, looking for the catalog update message immediately before the crash narrows the search window considerably.</p> <h2 id="turn-on-every-debug-flag-and-log-everything">Turn on every debug flag and log everything</h2> <p>When you are stuck, err heavily on the side of logging too much rather than too little. A verbose log that you have to <code class="language-plaintext highlighter-rouge">grep</code> through is far better than a quiet one that leaves you guessing. The more you record, the more likely it is that the crash site, the bad pointer, and the sequence of events leading to it are all sitting in the file waiting for you.</p> <p>CCTools exposes this through the <code class="language-plaintext highlighter-rouge">-d</code> flag, which accepts one or more subsystem names. The relevant ones for a Work Queue + Makeflow investigation are <code class="language-plaintext highlighter-rouge">wq</code> (Work Queue task scheduling and worker communication), <code class="language-plaintext highlighter-rouge">batch</code> (the batch system layer that submits SLURM or Condor jobs), <code class="language-plaintext highlighter-rouge">rmon</code> (the resource monitor that measures cores, memory, and disk per task), and <code class="language-plaintext highlighter-rouge">makeflow</code> (the Makeflow DAG engine, which covers parsing, lexing, and the run loop). Pass them all:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Worker: turn on every relevant subsystem and save to a named file</span>
work_queue_worker <span class="nt">-d</span> all <span class="nt">-o</span> worker.log localhost 9123 &amp;
 
<span class="c"># Makeflow manager: same idea, log to a separate file</span>
makeflow <span class="nt">-T</span> wq <span class="nt">-d</span> wq,batch,rmon,makeflow <span class="nt">-o</span> makeflow.log mini.makeflow
</code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">-d all</code> is the blunt instrument — it sets every bit in the flag word and includes subsystems you probably do not care about on this run. That is fine. The extra volume costs you nothing except disk space, and the subsystem tags in the log make it easy to filter later. If the log grows large enough to be unwieldy, narrow it down once you know which subsystem to focus on; start with <code class="language-plaintext highlighter-rouge">all</code> and restrict from there.</p> <p>On the cluster, where you cannot read <code class="language-plaintext highlighter-rouge">stderr</code> interactively, always pair <code class="language-plaintext highlighter-rouge">-d all</code> with <code class="language-plaintext highlighter-rouge">-o</code> pointing at a shared filesystem path that your login node can reach after the job finishes. Give each job a unique filename so concurrent workers do not overwrite each other:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>work_queue_worker <span class="nt">-d</span> all <span class="se">\</span>
  <span class="nt">-o</span> /cephfs/group/myproject/wq-logs/worker-<span class="si">$(</span><span class="nb">date</span> +%Y%m%d%H%M%S<span class="si">)</span>-<span class="nv">$$</span>.log <span class="se">\</span>
  localhost 9123
</code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">$$</code> expands to the worker process id on the execute node, which is a cheap uniquifier on top of the timestamp. Once the logs land, search them as a unit:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Find the catalog tick and the crash window across all workers in a session</span>
<span class="nb">grep</span> <span class="nt">-h</span> <span class="s2">"task_min_resources</span><span class="se">\|</span><span class="s2">catalog</span><span class="se">\|</span><span class="s2">ready_list</span><span class="se">\|</span><span class="s2">SIGSEGV"</span> <span class="se">\</span>
  /cephfs/group/myproject/wq-logs/worker-20260609-<span class="k">*</span>.log <span class="se">\</span>
  | <span class="nb">sort</span> <span class="nt">-k1</span>,2 | less
</code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">-h</code> flag suppresses the filename prefix so the timestamps sort cleanly. Sorting by the first two fields — date and time — stitches the per-worker logs into a single chronological view of what the whole pool was doing in the seconds before the crash. That cross-worker timeline is often what finally makes the bug obvious.</p> <p>One warning: do not turn on <code class="language-plaintext highlighter-rouge">--debug-workers</code> in <code class="language-plaintext highlighter-rouge">work_queue_factory</code> and also pass <code class="language-plaintext highlighter-rouge">-d all</code> through <code class="language-plaintext highlighter-rouge">--extra-options</code> at the same time. The factory-side flag already appends <code class="language-plaintext highlighter-rouge">-d all -o worker.&lt;n&gt;.log</code> to every submission; doubling up means every worker writes two interleaved logs to slightly different paths and you end up reading redundant output. Pick one approach per session.</p> <h2 id="the-quick-checklist-before-every-cluster-run">The quick checklist before every cluster run</h2> <p>Before you fire off a batch job, spend sixty seconds on these:</p> <ul> <li>Did you rebuild and reinstall after your last edit? A stale binary is the most common source of “my fix does nothing.”</li> <li>Is the debug log going to a path that exists and is writable from the execute node?</li> <li>Is the job small enough that you will get a result in under ten minutes, or do you have a good reason to go bigger right now?</li> <li>Did you commit your current state so that whatever happens on the cluster, the code is recoverable?</li> <li>Did you tell a teammate what you are about to test, so they can flag it if they know something relevant?</li> </ul> <p>None of these take long. Together they prevent the most common ways a cluster debugging session turns into a wasted afternoon.</p>]]></content><author><name>Cooperative Computing Lab</name></author><category term="technical-articles"/><category term="work_queue"/><category term="makeflow"/><category term="slurm"/><category term="debugging"/><category term="hpc"/><summary type="html"><![CDATA[A segfault in task_min_resources taught us a few things about staying sane while debugging on HPC systems. Here are the habits that keep you from burning hours waiting on a large workflow when a three-task smoke test would have told you the same thing.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/Work-Queue-Insights.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/work-queue-insights-practical-debugging-on-hpc-systems/Work-Queue-Insights.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">HTC26 Experience</title><link href="https://ccl.cse.nd.edu/blog/2026/htc26-experience/" rel="alternate" type="text/html" title="HTC26 Experience"/><published>2026-06-17T17:00:00+00:00</published><updated>2026-06-17T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/htc26-experience</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/htc26-experience/"><![CDATA[<p>One of the graduate students from our lab, Lax, attended <a href="https://agenda.hep.wisc.edu/event/2432/">HTC26</a> for the first time. While there, he had the chance to connect with researchers from universities, industry, and national laboratories across the HPC community. Here are his thoughts on the experience:</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/htc26-experience/throughput-2026-banners-480.webp 480w,/assets/blog/2026/htc26-experience/throughput-2026-banners-800.webp 800w,/assets/blog/2026/htc26-experience/throughput-2026-banners-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/htc26-experience/throughput-2026-banners.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Last week, I had the opportunity to attend <strong>Throughput Computing Week 2026</strong> in Madison, Wisconsin, organized by the Center for High Throughput Computing (CHTC). I participated in the conference on Wednesday and Thursday and came away with a deeper appreciation for the diverse ways high-throughput computing is impacting research across disciplines.</p> <p>One of the highlights of the event was attending my advisor <strong>Dr. Douglas Thain’s</strong> talk on Thursday, <em>“Wrangling Massive Task Graphs with VineReduce.”</em> The presentation showcased new approaches for managing large-scale computational workflows and demonstrated the continued evolution of distributed computing systems.</p> <p>Beyond the technical sessions, one of the most rewarding aspects of the conference was meeting researchers from a wide range of scientific domains. I spoke with teams working in space research who use HTCondor to process massive amounts of satellite-generated terrain data. Other researchers shared how high-throughput computing is accelerating genome analysis in biology and enabling large-scale weather modeling that helps civil engineers design more efficient roads and buildings.</p> <p>Among the many talks, I was particularly fascinated by discussions around <strong>Pelican</strong> and its role in distributed data storage and access. I also learned about emerging challenges surrounding next-generation hardware accelerators and AI-focused chips. Researchers and computing teams from universities across the country discussed how they are balancing growing computational demands through cloud resources, strategic infrastructure investments, and cost optimization techniques.</p> <p>As artificial intelligence continues to reshape science and engineering, the conference highlighted how computing infrastructures are evolving alongside it. From data-intensive scientific discovery to large-scale AI workloads, the conversations at Throughput Computing Week reinforced how rapidly the world of research computing is changing—and how important collaboration across disciplines will be in navigating that future.</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/htc26-experience/image-480.webp 480w,/assets/blog/2026/htc26-experience/image-800.webp 800w,/assets/blog/2026/htc26-experience/image-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/htc26-experience/image.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/htc26-experience/IMG_0168-480.webp 480w,/assets/blog/2026/htc26-experience/IMG_0168-800.webp 800w,/assets/blog/2026/htc26-experience/IMG_0168-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/htc26-experience/IMG_0168.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div>]]></content><author><name>Cooperative Computing Lab</name></author><category term="news"/><category term="news"/><summary type="html"><![CDATA[One of our graduate students attended HTC26 for the first time, here is what he learned.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/htc26-experience/throughput-2026-banners.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/htc26-experience/throughput-2026-banners.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">Alan Visits Fermilab</title><link href="https://ccl.cse.nd.edu/blog/2026/alan-visits-fermilab/" rel="alternate" type="text/html" title="Alan Visits Fermilab"/><published>2026-06-10T17:00:00+00:00</published><updated>2026-06-10T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/alan-visits-fermilab</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/alan-visits-fermilab/"><![CDATA[<p>In mid-May, <strong>Alan Rodrigues</strong> headed to Fermilab for the <strong>Scientific Workflow Management Cross-Experiment Retreat</strong>! 🚀</p> <p>This event brought together experts from 10 different experiments to align on shared challenges and collaborate on community solutions. Beyond establishing a common technical language, we mapped out key focus areas for the future:</p> <ul> <li>Resource optimization: Improving execution behavior and utilization.</li> <li>Data-aware late binding: Navigating data locality and streaming.</li> <li>Request, provenance &amp; validation: Exploring unified standards for workflow interfaces.</li> <li>AI in operations: Leveraging AI assistance in complex distributed systems.</li> </ul> <p>The conversation is just getting started. If you’re interested in the evolution of Workflow/Workload Management and community standards, we’d love for you to join us! Connect via our <a href="https://mattermost.web.cern.ch/signup_user_complete/?id=1qzfshcjbbr4z81w6yrr4qbtic&amp;md=link&amp;sbr=su">Mattermost channel</a></p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/alan-visits-fermilab/20260514-_DSC1302-480.webp 480w,/assets/blog/2026/alan-visits-fermilab/20260514-_DSC1302-800.webp 800w,/assets/blog/2026/alan-visits-fermilab/20260514-_DSC1302-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/alan-visits-fermilab/20260514-_DSC1302.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Alan Visits Fermilab" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div>]]></content><author><name>Cooperative Computing Lab</name></author><category term="news"/><category term="news"/><category term="conference"/><summary type="html"><![CDATA[At the Scientific Workflow Management Cross-Experiment Retreat at Fermilab, Alan Rodrigues joined experts from 10 experiments to tackle shared workflow management challenges and define future priorities in resource optimization, data-aware scheduling, workflow standards, and AI-assisted operations.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/alan-visits-fermilab/20260514-_DSC1302.jpg"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/alan-visits-fermilab/20260514-_DSC1302.jpg" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">SciWIND at IPDPS 2026</title><link href="https://ccl.cse.nd.edu/blog/2026/ipdps2026-highlights/" rel="alternate" type="text/html" title="SciWIND at IPDPS 2026"/><published>2026-06-03T17:00:00+00:00</published><updated>2026-06-03T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/ipdps2026-highlights</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/ipdps2026-highlights/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/ipdps2026-highlights/ipdps-hero-image-480.webp 480w,/assets/blog/2026/ipdps2026-highlights/ipdps-hero-image-800.webp 800w,/assets/blog/2026/ipdps2026-highlights/ipdps-hero-image-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/ipdps2026-highlights/ipdps-hero-image.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="IPDPS 2026" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>This May CCL third-year PhD student <strong>Jin Zhou</strong> traveled to New Orleans for <strong><a href="https://www.ipdps.org/">IPDPS 2026</a></strong>, the 40th IEEE International Parallel &amp; Distributed Processing Symposium, held at the Marriott on Canal Street from May 25 to 29. He presented our paper <a href="https://ccl.cse.nd.edu/assets/paper/pdf/sciwind-ipdps-2026.pdf"><strong>SciWIND: Effectively Exploiting Node-Local Storage for Data-Intensive High-Energy Physics Workflows</strong></a>, which looks at how to use node-local scratch more deliberately when large HEP workflows run on opportunistic clusters and workers fail mid-run. The talk was a nice cap on a line of work the lab has been pushing through TaskVine and our HEP collaborations, and it was good to put the system in front of people who live with scheduling, storage, and workflow engines every day.</p> <p>Between sessions Jin followed the <strong><a href="https://ssl.linklings.net/conferences/ipdps/ipdps2026_program/views/at_a_glance.html">conference program</a></strong>: tutorials and workshops on the first two days, then the main track, keynotes, and plenty of hallway conversations. IPDPS still has that familiar mix of parallel algorithms, distributed systems, and applications at scale. AI was clearly a hot topic this year, showing up in keynotes, panels, and hallway chats about training and inference at scale. A few questions after the SciWIND talk turned into longer conversations about eviction recovery, disk pressure on shared filesystems, and where workflow runtimes should own policy versus leave it to the user. New Orleans helped too, with late walks along Canal Street and coffee between sessions that made the week feel less like a sprint and more like a real meeting of the community.</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/ipdps2026-highlights/conference-photo-480.webp 480w,/assets/blog/2026/ipdps2026-highlights/conference-photo-800.webp 800w,/assets/blog/2026/ipdps2026-highlights/conference-photo-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/ipdps2026-highlights/conference-photo.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="Jin Zhou at IPDPS 2026" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Thanks to everyone who came to the SciWIND session and to the IPDPS organizers for another smooth run. We are glad the paper is out in the proceedings and happy to keep the conversation going with groups wrestling with the same storage and resilience headaches in production science workflows.</p>]]></content><author><name>Cooperative Computing Lab</name></author><category term="news"/><category term="news"/><category term="conference"/><summary type="html"><![CDATA[CCL third-year PhD student Jin Zhou traveled to IPDPS 2026 in New Orleans to present SciWIND on node-local storage for data-intensive high-energy physics workflows.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/ipdps2026-highlights/ipdps-hero-image.png"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/ipdps2026-highlights/ipdps-hero-image.png" xmlns:media="http://search.yahoo.com/mrss/"/></entry><entry><title type="html">CCL Team at GCASR 2026</title><link href="https://ccl.cse.nd.edu/blog/2026/gcasr/" rel="alternate" type="text/html" title="CCL Team at GCASR 2026"/><published>2026-05-12T17:00:00+00:00</published><updated>2026-05-12T17:00:00+00:00</updated><id>https://ccl.cse.nd.edu/blog/2026/gcasr</id><content type="html" xml:base="https://ccl.cse.nd.edu/blog/2026/gcasr/"><![CDATA[<div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/gcasr/hall-480.webp 480w,/assets/blog/2026/gcasr/hall-800.webp 800w,/assets/blog/2026/gcasr/hall-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/gcasr/hall.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="GCASR venue" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>This week our lab was in Chicago for <strong>GCASR 2026</strong>—the <strong>Greater Chicago Area Systems Research Workshop</strong> (<a href="https://gcasr.org">gcasr.org</a>), a regional gathering focused on computer systems, from operating systems and distributed infrastructure to the tools that make large-scale science tractable. It is a friendly venue for students and faculty to share work in progress, compare notes on real systems problems, and meet peers from departments and labs around the Midwest.</p> <p>The CCL makes this trip every year: Chicago is home base for GCASR, and showing up has become part of how we stay plugged into the systems community between the bigger conference cycles.</p> <p>Each student on the team presented a research poster, as we typically do at this venue. The poster floor was busy, with good questions, fast feedback, and plenty of hallway conversations that do not fit on a slide deck. Between sessions, people attended invited talks and panels, swapped implementation details, and followed threads from scheduling and storage to workflows and AI-facing infrastructure.</p> <div class="row justify-content-sm-center"> <div class="col-sm-12"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/blog/2026/gcasr/group-photo-480.webp 480w,/assets/blog/2026/gcasr/group-photo-800.webp 800w,/assets/blog/2026/gcasr/group-photo-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/blog/2026/gcasr/group-photo.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" title="CCL at GCASR" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </div> </div> <p>Thanks to everyone who stopped by our posters and to the organizers for another well-run GCASR. We appreciated the insights, the introductions, and the chance to catch up with colleagues in person. We look forward to seeing familiar faces at GCASR 2027!</p>]]></content><author><name>Cooperative Computing Lab</name></author><category term="news"/><category term="news"/><category term="workshop"/><category term="gcasr"/><summary type="html"><![CDATA[The CCL traveled to Chicago for the Greater Chicago Area Systems Research Workshop (GCASR). Students presented posters, caught invited talks, and connected with the local systems community.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://ccl.cse.nd.edu/assets/blog/2026/gcasr/hall.jpg"/><media:content medium="image" url="https://ccl.cse.nd.edu/assets/blog/2026/gcasr/hall.jpg" xmlns:media="http://search.yahoo.com/mrss/"/></entry></feed>