<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Developer Guide on IOPS</title><link>https://iops.gitlabpages.inria.fr/developer-guide/</link><description>Recent content in Developer Guide on IOPS</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://iops.gitlabpages.inria.fr/developer-guide/index.xml" rel="self" type="application/rss+xml"/><item><title>Execution Loop</title><link>https://iops.gitlabpages.inria.fr/developer-guide/execution-loop/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://iops.gitlabpages.inria.fr/developer-guide/execution-loop/</guid><description>&lt;p>This page documents the IOPS execution loop architecture: how the Runner, Planner, and Executor components orchestrate benchmark execution.&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>The execution loop follows a &lt;strong>pull-based&lt;/strong> design where the Runner requests tests from the Planner and delegates execution to the Executor:&lt;/p>
&lt;pre tabindex="0">&lt;code>┌─────────────────────────────────────────────────────────────────┐
│ IOPSRunner │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Planner │─────►│ Runner │─────►│ Executor │ │
│ │ │ │ Loop │ │ │ │
│ │ next_test() │ │ │ │ submit() │ │
│ │ │◄─────│ │◄─────│ wait_and_ │ │
│ │ record_ │ │ │ │ collect() │ │
│ │ completed() │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Matrix │ │ Cache │ │ Parser │ │
│ │ Builder │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
&lt;/code>&lt;/pre>&lt;h2 id="component-roles">Component Roles&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Component&lt;/th>
 &lt;th>Responsibility&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>Runner&lt;/strong>&lt;/td>
 &lt;td>Orchestrates the execution loop, manages cache, tracks budget, writes results&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Planner&lt;/strong>&lt;/td>
 &lt;td>Generates test configurations, manages execution order, prepares artifacts&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Executor&lt;/strong>&lt;/td>
 &lt;td>Submits jobs, waits for completion, collects output and metrics&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Matrix Builder&lt;/strong>&lt;/td>
 &lt;td>Generates parameter combinations from config, applies constraints&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Cache&lt;/strong>&lt;/td>
 &lt;td>Stores/retrieves results to skip redundant executions&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>Parser&lt;/strong>&lt;/td>
 &lt;td>Extracts metrics from benchmark output files&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="the-execution-loop">The Execution Loop&lt;/h2>
&lt;h3 id="main-loop-iopsrunnerrun">Main Loop (&lt;code>IOPSRunner.run()&lt;/code>)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">run&lt;/span>(self):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 1. Check budget&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> budget_exceeded:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 2. Get next test from planner&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> test &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>planner&lt;span style="color:#f92672">.&lt;/span>next_test()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> test &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">break&lt;/span> &lt;span style="color:#75715e"># No more tests&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 3. Check cache&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>cache &lt;span style="color:#f92672">and&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>use_cache_reads:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cached_result &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>cache&lt;span style="color:#f92672">.&lt;/span>get_cached_result(test&lt;span style="color:#f92672">.&lt;/span>vars, test&lt;span style="color:#f92672">.&lt;/span>repetition)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> cached_result:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Use cached result, skip execution&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> test&lt;span style="color:#f92672">.&lt;/span>metadata&lt;span style="color:#f92672">.&lt;/span>update(cached_result)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> test&lt;span style="color:#f92672">.&lt;/span>metadata[&lt;span style="color:#e6db74">&amp;#39;__cached&amp;#39;&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 4. Execute if not cached&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> used_cache:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>_write_status_file(test, status&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;RUNNING&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>executor&lt;span style="color:#f92672">.&lt;/span>submit(test)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>executor&lt;span style="color:#f92672">.&lt;/span>wait_and_collect(test)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Store in cache if succeeded&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> succeeded:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>cache&lt;span style="color:#f92672">.&lt;/span>store_result(&lt;span style="color:#f92672">...&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 5. Write status and results&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>_write_status_file(test)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> save_test_execution(test)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 6. Notify planner of completion&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> self&lt;span style="color:#f92672">.&lt;/span>planner&lt;span style="color:#f92672">.&lt;/span>record_completed_test(test)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="sequence-diagram">Sequence Diagram&lt;/h3>
&lt;pre tabindex="0">&lt;code>Runner Planner Executor Cache
 │ │ │ │
 │ next_test() │ │ │
 │───────────────────►│ │ │
 │ │ │ │
 │ ExecutionInstance │ │ │
 │◄───────────────────│ │ │
 │ │ │ │
 │ get_cached_result() │ │
 │──────────────────────────────────────────────────────────►│
 │ │ │ │
 │ (cache miss) │ │ │
 │◄──────────────────────────────────────────────────────────│
 │ │ │ │
 │ submit(test) │ │ │
 │────────────────────────────────────────►│ │
 │ │ │ │
 │ wait_and_collect(test) │ │
 │────────────────────────────────────────►│ │
 │ │ │ │
 │ test.metadata updated │ │
 │◄────────────────────────────────────────│ │
 │ │ │ │
 │ store_result() │ │ │
 │──────────────────────────────────────────────────────────►│
 │ │ │ │
 │ record_completed_test() │ │
 │───────────────────►│ │ │
 │ │ │ │
&lt;/code>&lt;/pre>&lt;h2 id="planner-architecture">Planner Architecture&lt;/h2>
&lt;h3 id="base-planner">Base Planner&lt;/h3>
&lt;p>All planners inherit from &lt;code>BasePlanner&lt;/code> and implement:&lt;/p></description></item><item><title>Probe System</title><link>https://iops.gitlabpages.inria.fr/developer-guide/probe-system/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://iops.gitlabpages.inria.fr/developer-guide/probe-system/</guid><description>&lt;p>This page documents the IOPS system probe mechanism for developers who want to extend the collected metrics or modify probe behavior.&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>The probe system collects system information (CPU, memory, filesystems, etc.) from the actual compute node where the benchmark runs. This matters for SLURM jobs, where the login node differs from compute nodes.&lt;/p>
&lt;p>&lt;strong>Key files:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;code>__iops_exit_handler.sh&lt;/code> - Centralized EXIT trap coordinator&lt;/li>
&lt;li>&lt;code>__iops_node_launcher.sh&lt;/code> - Resolves the job&amp;rsquo;s node list and starts one helper per node&lt;/li>
&lt;li>&lt;code>__iops_atexit_sysinfo.sh&lt;/code> - System info collection script&lt;/li>
&lt;li>&lt;code>__iops_sysinfo.json&lt;/code> - Collected data (generated at runtime)&lt;/li>
&lt;/ul>
&lt;h2 id="architecture">Architecture&lt;/h2>
&lt;pre tabindex="0">&lt;code>User Script Exit Handler Sysinfo Script
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
│ #!/bin/bash │ │ # Sets EXIT trap │ │ # Registers cleanup │
│ #SBATCH ... │ │ trap &amp;#39;_iops_run_ │ │ _iops_register_exit │
│ │ │ exit_actions&amp;#39; EXIT│ │ &amp;#34;_iops_collect_ │
│ # IOPS injection │ │ │ │ sysinfo&amp;#34; │
│ source handler.sh │───────►│ # Registry array │ │ │
│ source sysinfo.sh │───────────────────────────────────────►│ # Collection func │
│ │ │ _iops_register_exit │ │ _iops_collect_ │
│ # User&amp;#39;s benchmark │ │ () { ... } │ │ sysinfo() { ... } │
│ mpirun ./benchmark │ └─────────────────────┘ └─────────────────────┘
└─────────────────────┘ │
 │ │
 ▼ (on script exit) ▼
┌─────────────────────┐ ┌─────────────────────┐
│ __iops_sysinfo.json │◄───────│ _iops_run_exit_ │
│ { │ │ actions() calls │
│ &amp;#34;hostname&amp;#34;: ..., │ │ all registered │
│ &amp;#34;cpu_model&amp;#34;: ..., │ │ functions │
│ &amp;#34;duration&amp;#34;: ... │ └─────────────────────┘
│ } │
└─────────────────────┘
&lt;/code>&lt;/pre>&lt;p>The exit handler provides a centralized EXIT trap that other IOPS features (system probe, resource sampler) register cleanup actions with, avoiding trap conflicts.&lt;/p></description></item><item><title>Data Sources</title><link>https://iops.gitlabpages.inria.fr/developer-guide/data-sources/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://iops.gitlabpages.inria.fr/developer-guide/data-sources/</guid><description>&lt;p>This page documents where IOPS CLI commands read their data.&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>IOPS commands read from result files and from metadata files generated during execution. Metadata files have the &lt;code>__iops_&lt;/code> prefix and are documented in the &lt;a href="https://iops.gitlabpages.inria.fr/user-guide/metadata-files/">Metadata Files&lt;/a> user guide.&lt;/p>
&lt;h2 id="data-sources-by-command">Data Sources by Command&lt;/h2>
&lt;pre tabindex="0">&lt;code>iops find ◄─── __iops_index.json
 ◄─── __iops_status_rollup.json (preferred; falls back to per-folder scan)
 ◄─── __iops_status.json (fallback)
 ◄─── __iops_run_metadata.json (optional metadata)

iops find --watch ◄─── __iops_index.json (polling)
 ◄─── __iops_status_rollup.json (preferred; polling)
 ◄─── __iops_status.json (fallback scan)

iops report ◄─── __iops_run_metadata.json
 ◄─── results.csv/parquet/sqlite
&lt;/code>&lt;/pre>&lt;h3 id="status-roll-up-fast-path">Status roll-up fast path&lt;/h3>
&lt;p>Both &lt;code>iops find&lt;/code> and watch mode read the run-root &lt;code>__iops_status_rollup.json&lt;/code>
aggregate instead of scanning every execution&amp;rsquo;s repetition folders, which keeps
them responsive on large parameter spaces. The per-folder &lt;code>__iops_status.json&lt;/code>
files remain the source of truth (and the node-to-runner channel in
single-allocation mode); the roll-up is an accelerator. Watch always prefers it;
&lt;code>iops find&lt;/code> only trusts it when the run marked it &lt;code>complete&lt;/code>, otherwise it falls
back to the folder scan. When the roll-up is absent (older runs, archives), both
fall back automatically.&lt;/p></description></item></channel></rss>