CLI Interface Deep-Dive
How oclgrind-kernel.cpp parses command-line arguments, maps them to OCLGRIND_* environment variables, and drives the Simulation class.
Architecture
graph LR CLI[oclgrind-kernel] -->|parseArguments| ENV[setenv OCLGRIND_*] CLI -->|positional arg| SIM[Simulation::load] SIM -->|.sim file| RUN[Simulation::run] ENV -.->|read by| Core[Core subsystem]
The oclgrind-kernel binary is the standalone kernel simulator. Unlike oclgrind (which wraps an existing app via LD_PRELOAD), this tool reads a .sim file directly and executes the kernel outside any OpenCL runtime.
Flag → Environment Variable Mapping
Every CLI flag calls setEnvironment(name, value) which wraps setenv() (POSIX) or _putenv_s() (Windows). The Core subsystem reads these variables at initialisation.
| CLI Flag | Environment Variable | Value |
|---|---|---|
--build-options OPT | OCLGRIND_BUILD_OPTIONS | OPT string |
--data-races | OCLGRIND_DATA_RACES | "1" |
--global-mem-size N | OCLGRIND_GLOBAL_MEM_SIZE | N bytes |
--local-mem-size N | OCLGRIND_LOCAL_MEM_SIZE | N bytes |
--max-wgsize N | OCLGRIND_MAX_WGSIZE | N |
--interactive / -i | OCLGRIND_INTERACTIVE | "1" |
--inst-counts | OCLGRIND_INST_COUNTS | "1" |
--plugins LIBS | OCLGRIND_PLUGINS | colon-separated |
--quick / -q | OCLGRIND_QUICK | "1" |
--uninitialized | OCLGRIND_UNINITIALIZED | "1" |
--num-threads N | OCLGRIND_NUM_THREADS | N |
--log FILE | OCLGRIND_LOG | path |
--max-errors N | OCLGRIND_MAX_ERRORS | N |
-g / --global-mem | (local flag) | sets outputGlobalMemory |
-g / --global-mem flag is unique to oclgrind-kernel — it sets a local boolean rather than an environment variable, passing it as the dumpGlobalMemory parameter to Simulation::run().Argument Parsing Loop
The parser is a simple strcmp chain — no getopt or library dependency. The first positional (non-flag) argument is taken as the .sim file path; any extra positional argument triggers an error.
// Simplified parseArguments logic from oclgrind-kernel.cpp
static bool parseArguments(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--data-races")) {
setEnvironment("OCLGRIND_DATA_RACES", "1");
}
else if (!strcmp(argv[i], "--global-mem-size")) {
if (++i >= argc) { cerr << "Missing argument"; return false; }
setEnvironment("OCLGRIND_GLOBAL_MEM_SIZE", argv[i]);
}
else if (argv[i][0] == '-') {
cerr << "Unrecognised option '" << argv[i] << "'"; return false;
}
else {
if (simfile == NULL) simfile = argv[i];
else { cerr << "Unexpected positional argument"; return false; }
}
}
if (simfile == NULL) { printUsage(); return false; }
return true;
}
Execution Flow
sequenceDiagram
participant U as User
participant CLI as oclgrind-kernel
participant SIM as Simulation
participant CTX as Core::Context
U->>CLI: oclgrind-kernel --data-races test.sim
CLI->>CLI: setenv(OCLGRIND_DATA_RACES, 1)
CLI->>SIM: simulation.load('test.sim')
SIM->>CTX: new Context()
SIM->>SIM: parse .sim header
SIM->>SIM: build program & create kernel
SIM->>SIM: parseArgument() × N
SIM-->>CLI: true
CLI->>SIM: simulation.run(false)
SIM->>CTX: KernelInvocation::run
SIM-->>U: dump results to stdoutUsage Examples
// Basic kernel run
// $ oclgrind-kernel vecadd.sim
// Enable data-race detection and interactive debugging
// $ oclgrind-kernel --data-races --interactive vecadd.sim
// Limit memory and dump global memory at exit
// $ oclgrind-kernel --global-mem-size 67108864 -g vecadd.sim
// Load custom plugins, limit errors, log to file
// $ oclgrind-kernel --plugins myplugin.so --max-errors 10 \
// --log errors.txt vecadd.sim
oclgrind: The oclgrind
wrapper launches an arbitrary application with LD_PRELOAD
injection. oclgrind-kernel runs a single kernel from a
.sim file — no OpenCL runtime, no ICD loader, and no host
application needed.
Environment Variable Helper
The setEnvironment() function abstracts the platform
difference between POSIX and Windows:
static void setEnvironment(const char* name, const char* value) {
#if defined(_WIN32) && !defined(__MINGW32__)
_putenv_s(name, value);
#else
setenv(name, value, 1);
#endif
}
setenv
is 1, meaning CLI flags always override any pre-existing
environment variables. This lets users combine shell-level defaults
with per-invocation overrides.
Error Behaviour
Argument parsing failures produce specific messages and return
false, causing main() to return exit code 1.
Common errors include:
- Missing value after a flag that requires one (e.g.
--logwithout a path) - Unrecognised flag (anything starting with
-that does not match known options) - Duplicate positional arguments (only one
.simfile is accepted) - No positional argument at all → prints usage and exits
Plugin Loading
The --plugins flag accepts a colon-separated list of shared
library paths. These are stored in OCLGRIND_PLUGINS and loaded
by the Core subsystem at context creation time. Plugins can hook into
memory accesses, kernel invocations, and other simulation events to
implement custom analysis passes.
Interactive Debugging Mode
When --interactive (or -i) is passed, the Core
subsystem enters a GDB-like command loop at each kernel invocation.
Users can inspect work-item state, set breakpoints on specific
global IDs, and step through LLVM IR instructions. This mode is
invaluable for debugging complex race conditions or out-of-bounds
accesses.
Quick Mode
The --quick flag sets OCLGRIND_QUICK=1, causing
the simulator to only execute the first and last work-groups. This
dramatically reduces simulation time for large NDRanges while still
catching boundary-related bugs.
Version and Help Output
Both -v / --version and -h / --help cause the
program to print information and call exit(0) immediately,
skipping simulation entirely. The version output includes the
PACKAGE_VERSION macro set at build time, the copyright
notice, and a link to the GitHub repository.
Comparison: oclgrind vs oclgrind-kernel
| Feature | oclgrind | oclgrind-kernel |
|---|---|---|
| Input | Arbitrary application | .sim file |
| Injection | LD_PRELOAD / DLL | Direct Core API |
| OpenCL runtime | Full ICD-compatible | None |
| Global mem dump | No | Yes (-g) |
| Argument dump | No | Yes (per-arg dump) |
Edge Cases & Common Pitfalls
| Scenario | Behaviour | Resolution |
|---|---|---|
No .sim file argument | Prints usage text, exits with code 1 | Provide a valid .sim file as the last positional argument |
| Two positional arguments | "Unexpected positional argument" error | Only one .sim file is accepted per invocation |
--global-mem-size without value | "Missing argument" error, exit 1 | Always pass the byte count after the flag |
| Flag after positional argument | Treated as a second positional → error | Place all flags before the .sim path |
| Environment variable already set | CLI flag silently overwrites it (setenv overwrite=1) | Intended behaviour — CLI takes precedence |
Invalid .sim file path | Simulation::load() fails with an I/O error | Verify the path exists and is readable |
| Plugin shared library not found | Core logs a dlopen / LoadLibrary error at context creation | Use absolute paths or ensure LD_LIBRARY_PATH is set |
Troubleshooting
Simulation loads but produces no output
Ensure at least one kernel argument has the dump modifier in its header, or pass -g to dump all global memory. Without either, oclgrind-kernel runs silently.
Interactive mode does not start
Verify that --interactive is spelled correctly. A common mistake is passing -I (uppercase) which is not recognised and triggers an "Unrecognised option" error. The short form is lowercase -i.
Memory limit appears to have no effect
The --global-mem-size value is in bytes, not megabytes. Passing --global-mem-size 64 gives you 64 bytes, not 64 MiB. Use 67108864 for 64 MiB.
Plugin causes segfault at startup
Plugins are loaded via dlopen during Core::Context creation. If a plugin has unresolved symbols or an incompatible ABI version, the process crashes before any simulation output. Test plugins in isolation by loading them with LD_PRELOAD first to check for link errors.
Related Topics
- Simulation Lifecycle — how
Simulation::load()andSimulation::run()work internally - ICD Dispatch Table — how the
oclgrindwrapper (LD_PRELOAD mode) differs fromoclgrind-kernel - OpenCL API Layer — the runtime that
oclgrindinjects vs. the direct Core usage inoclgrind-kernel - Kernel Module Overview — parent page with links to all kernel sub-topics