Repository navigation
Introduce dtoctl, a CLI wrapper for running programs with DTO preloaded - #33
honggyukim wants to merge 3 commits into
Conversation
Using the DTO library today requires the user to understand two orthogonal mechanisms before a single program can be offloaded to DSA. The library has to be injected into the target through LD_PRELOAD, and its behavior is steered entirely through a set of roughly twenty DTO_* environment variables that must be discovered by reading the manual and then exported by hand. This is easy to get wrong: the LD_PRELOAD path and the variable names are stringly typed, an exported variable silently leaks into every later command in the same shell, and there is no validation or discoverability at the point of use. Provide a small wrapper, dtoctl, that turns this into a single self-describing command line. It follows the same model as hmctl from the hmsdk project: parse options, translate them into the environment the library expects, and then exec the target program so no state lingers in the caller's shell. On top of that model dtoctl also takes care of the injection itself by prepending the resolved libdto.so to LD_PRELOAD, which is possible because DTO works by transparently interposing on the standard memory APIs. Every DTO_* variable is exposed as an option so the mapping stays obvious and greppable. Only options that are actually given are written to the child environment; anything left unset keeps whatever the caller already exported or the library's own default, and an explicit option wins over an inherited variable. The library path is resolved from -l/--library, then $DTO_LIBRARY, then a compiled-in default, and execvp() is used so a bare command name on PATH works as well as an explicit path. Build and install dtoctl with both Make and CMake. Set its compiled-in library path to match the installation directory, since CMake's default /usr/local/lib differs from the Makefile's /usr/lib64. Allow that path to be overridden with DTOCTL_LIBPATH. With this in place the previous incantation $ export LD_PRELOAD=/usr/lib64/libdto.so $ export DTO_WAIT_METHOD=busypoll $ export DTO_CPU_SIZE_FRACTION=0.33 $ ./prog collapses to $ dtoctl -w busypoll -c 0.33 ./prog Signed-off-by: Honggyu Kim <honggyu.kim@sk.com>
The dtoctl options mirror the DTO_* environment variables, but a user coming to the tool for the first time still needs a single authoritative place that explains what each option does, what values it accepts, and how the library path and LD_PRELOAD are resolved. Scattering that information across the source help text alone makes it hard to consult without running the tool. Add a manual page in the same troff-friendly markdown form the hmsdk project uses for hmctl, and render it as a section 1 man page for the user command. Besides the per-option reference it documents the library resolution order and the override semantics, and it gathers the common tuning goals - latency, power, and cache-pollution avoidance - as ready-to-run examples such as $ dtoctl -w umwait -c 0.0 --no-auto-adjust ./prog so users can map an intent directly onto a command instead of reverse engineering it from the individual variables. Keep the markdown as the source form and generate dtoctl.1 with pandoc during the Makefile and CMake builds. Both build systems install the generated page under man1, so it can be read with $ man 1 dtoctl Pandoc is optional: when it is unavailable, print a message recommending its installation and skip manual generation. The Makefile can still install an already generated page. Ignore its generated doc/dtoctl.1 and remove it on make clean; CMake keeps its generated page in the build directory. Signed-off-by: Honggyu Kim <honggyu.kim@sk.com>
The README is where users first learn how to configure and run DTO, and until now it only described the manual LD_PRELOAD and DTO_* export workflow. A reader following it has no reason to know that dtoctl exists or that it removes most of that ceremony, so the easier path stays hidden precisely where people look for guidance. Introduce dtoctl after the environment variable reference and the common usage models that accompany it, so that discussion stays in one piece and the new section can point back at those usage models. Contrast the old export sequence with the equivalent $ dtoctl -w busypoll -c 0.33 ./prog and spell out the resolution order for libdto.so along with the rule that only the options actually passed are applied. Keep the per-option reference in dtoctl(1) instead of repeating it here. The option list already exists in the --help output and in the manual, and a third copy in the README would only be one more place to forget when an option changes. Signed-off-by: Honggyu Kim <honggyu.kim@sk.com>
|
Hi @byrnedj, this is the work that I showed you before. Please have a look. Thanks! |
There was a problem hiding this comment.
🟡 Changes recommended
There are a few correctness/UX issues (notably --stats-file not enabling stats) plus build cleanup gaps and missing test coverage for the new CLI behavior.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR introduces dtoctl, a small CLI wrapper that configures DTO via command-line options, sets the corresponding DTO_* environment variables, prepends libdto.so to LD_PRELOAD, and then execs the target program to avoid leaking configuration into the caller’s shell.
Changes:
- Add
dtoctlexecutable that translates CLI options intoDTO_*env vars and composesLD_PRELOAD. - Add user documentation for
dtoctl(README section + pandoc-generateddtoctl(1)manpage source). - Update Makefile/CMake build and install flows to build/install
dtoctland optionally generate/install the man page.
File summaries
| File | Description |
|---|---|
| README.md | Documents dtoctl usage and library path resolution behavior. |
| Makefile | Builds/installs dtoctl and optionally generates/installs dtoctl(1) via pandoc. |
| dtoctl.c | Implements the dtoctl CLI wrapper (arg parsing, env var mapping, LD_PRELOAD composition, exec). |
| doc/dtoctl.md | Adds the dtoctl(1) manual source (pandoc markdown). |
| CMakeLists.txt | Adds dtoctl build/install rules and optional manpage generation/install. |
| .gitignore | Ignores the dtoctl binary and generated doc/dtoctl.1. |
Review details
- Files reviewed: 5/6 changed files
- Comments generated: 4
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| case OPT_STATS_FILE: | ||
| opts->stats_file = arg; | ||
| break; |
| clean: | ||
| rm -rf *.o *.so dto-test | ||
| rm -rf *.o *.so dto-test dtoctl | ||
| rm -f doc/dtoctl.1 |
| free(preload); | ||
| } | ||
|
|
||
| int main(int argc, char *argv[]) |
| execvp(opts.exename, argv); | ||
| perror(opts.exename); | ||
|
|
||
| return -1; |
…cks up #33) (#38) * Add dtoctl wrapper to drive DTO without manual LD_PRELOAD setup Using the DTO library today requires the user to understand two orthogonal mechanisms before a single program can be offloaded to DSA. The library has to be injected into the target through LD_PRELOAD, and its behavior is steered entirely through a set of roughly twenty DTO_* environment variables that must be discovered by reading the manual and then exported by hand. This is easy to get wrong: the LD_PRELOAD path and the variable names are stringly typed, an exported variable silently leaks into every later command in the same shell, and there is no validation or discoverability at the point of use. Provide a small wrapper, dtoctl, that turns this into a single self-describing command line. It follows the same model as hmctl from the hmsdk project: parse options, translate them into the environment the library expects, and then exec the target program so no state lingers in the caller's shell. On top of that model dtoctl also takes care of the injection itself by prepending the resolved libdto.so to LD_PRELOAD, which is possible because DTO works by transparently interposing on the standard memory APIs. Every DTO_* variable is exposed as an option so the mapping stays obvious and greppable. Only options that are actually given are written to the child environment; anything left unset keeps whatever the caller already exported or the library's own default, and an explicit option wins over an inherited variable. The library path is resolved from -l/--library, then $DTO_LIBRARY, then a compiled-in default, and execvp() is used so a bare command name on PATH works as well as an explicit path. Build and install dtoctl with both Make and CMake. Set its compiled-in library path to match the installation directory, since CMake's default /usr/local/lib differs from the Makefile's /usr/lib64. Allow that path to be overridden with DTOCTL_LIBPATH. With this in place the previous incantation $ export LD_PRELOAD=/usr/lib64/libdto.so $ export DTO_WAIT_METHOD=busypoll $ export DTO_CPU_SIZE_FRACTION=0.33 $ ./prog collapses to $ dtoctl -w busypoll -c 0.33 ./prog Signed-off-by: Honggyu Kim <honggyu.kim@sk.com> * Add a dtoctl man page The dtoctl options mirror the DTO_* environment variables, but a user coming to the tool for the first time still needs a single authoritative place that explains what each option does, what values it accepts, and how the library path and LD_PRELOAD are resolved. Scattering that information across the source help text alone makes it hard to consult without running the tool. Add a manual page in the same troff-friendly markdown form the hmsdk project uses for hmctl, and render it as a section 1 man page for the user command. Besides the per-option reference it documents the library resolution order and the override semantics, and it gathers the common tuning goals - latency, power, and cache-pollution avoidance - as ready-to-run examples such as $ dtoctl -w umwait -c 0.0 --no-auto-adjust ./prog so users can map an intent directly onto a command instead of reverse engineering it from the individual variables. Keep the markdown as the source form and generate dtoctl.1 with pandoc during the Makefile and CMake builds. Both build systems install the generated page under man1, so it can be read with $ man 1 dtoctl Pandoc is optional: when it is unavailable, print a message recommending its installation and skip manual generation. The Makefile can still install an already generated page. Ignore its generated doc/dtoctl.1 and remove it on make clean; CMake keeps its generated page in the build directory. Signed-off-by: Honggyu Kim <honggyu.kim@sk.com> * Document dtoctl in the README The README is where users first learn how to configure and run DTO, and until now it only described the manual LD_PRELOAD and DTO_* export workflow. A reader following it has no reason to know that dtoctl exists or that it removes most of that ceremony, so the easier path stays hidden precisely where people look for guidance. Introduce dtoctl after the environment variable reference and the common usage models that accompany it, so that discussion stays in one piece and the new section can point back at those usage models. Contrast the old export sequence with the equivalent $ dtoctl -w busypoll -c 0.33 ./prog and spell out the resolution order for libdto.so along with the rule that only the options actually passed are applied. Keep the per-option reference in dtoctl(1) instead of repeating it here. The option list already exists in the --help output and in the manual, and a third copy in the README would only be one more place to forget when an option changes. Signed-off-by: Honggyu Kim <honggyu.kim@sk.com> * dto: honor DTO_WAIT_METHOD=yield The yield wait method is implemented in dsa_wait() and documented in the README, but dsa_init() never matched "yield" when parsing DTO_WAIT_METHOD, so DTO_WAIT_METHOD=yield silently ran with busypoll. * dtoctl: validate options, resolve the library up front, add --dry-run Make the wrapper catch the mistakes it exists to prevent instead of passing them on to libdto, which silently falls back to a default: - Validate every option value: wait method names, integer ranges for --numa-aware and --log-level, a cpu fraction in [0, 1), a positive umwait delay, and non-empty paths and WQ list. --min-bytes takes an optional K/M/G suffix and is passed on as plain bytes; libdto would read "64K" as 64 and "abc" as 0. - Resolve libdto.so to an absolute path and fail with exit status 125 if it cannot be read. ld.so only warns about a missing preload and runs the program without DTO, and a relative path stopped working as soon as the program changed directory. When built with LIBDTO_REL_PATH, prefer the library installed next to dtoctl so a relocated install finds its own copy. - Drop other libdto.so entries from an inherited LD_PRELOAD, so one process never loads two copies of DTO. - --stats-file implies --stats; libdto ignores DTO_STATS_FILE otherwise. - Add -i/--ignore-env to unset inherited DTO_* variables. The --no-* flags can only turn features off, so this is the way to undo an exported DTO_USESTDC_CALLS=1 or DTO_DSA_MEMCPY=0. - Add --dry-run to print the resolved library, LD_PRELOAD, each DTO_* variable with whether it came from an option or the environment, and the command, without running it. - Add --version, and exit with 126/127 when the program cannot be run or is not found, as env(1) and timeout(1) do. - Make the options local to main() and drop dead argument handling. * dtoctl: follow the install prefix, report the version, add tests CMake cached the default library path on the first configure, so a later CMAKE_INSTALL_PREFIX change was ignored, and "cmake --install --prefix" produced a dtoctl that preloaded /usr/local/lib/libdto.so. Compute the default on every configure, pass dtoctl the library's path relative to its own bindir so a relocated install finds its own copy, and keep DTOCTL_LIBPATH as an explicit override. Pass the project version to both builds for --version, and make the Makefile's install target build dtoctl first. Add tests/test_dtoctl.sh as the "dtoctl" CTest (label functional). It needs no DSA: it checks the option to variable mapping, validation, library resolution, LD_PRELOAD handling and exit statuses through --dry-run and the program's environment, and that libdto applies the settings through its own configuration trace. * docs: document dtoctl's validation, library resolution and --dry-run Update the dtoctl man page and README section for the new behavior: option validation, -i/--ignore-env, --dry-run, --version, size suffixes, --stats-file implying --stats, how the library is resolved, and the exit statuses. Add a note on sudo, which resets the environment and strips LD_PRELOAD when it sits between dtoctl and the program, and on settings being inherited by child processes. Fix stale defaults in the README's variable list: DTO_WAIT_METHOD defaults to busypoll and DTO_MIN_BYTES to 65536, tpause is a valid wait method, and DTO_LOG_FILE gets .<program>.<pid> appended. Describe the dtoctl test in TESTING.md. * gitignore: ignore the libdto_explicit build output --------- Signed-off-by: Honggyu Kim <honggyu.kim@sk.com> Co-authored-by: Honggyu Kim <honggyu.kim@sk.com>
|
Thanks, we actually merged this here: 5dfa009 |
Using DTO currently requires understanding two orthogonal mechanisms before a single
program can be offloaded to DSA. The library has to be injected into the target
through
LD_PRELOAD, and its behavior is steered entirely through manyDTO_*environment variables that have to be discovered in the README and then exported
by hand. That is easy to get wrong: the preload path and the variable names are
stringly typed, an exported variable silently leaks into every later command in
the same shell, and there is no validation or discoverability at the point of
use.
This adds
dtoctl, a small wrapper that turns the setup into a singleself-describing command line. It parses options, translates them into the
environment the library expects, prepends the resolved
libdto.sotoLD_PRELOAD, and thenexecvp()s the target program, so nothing lingers in thecaller's shell.
So the previous usage
collapses to