The neuronx-cc Command Dispatcher & Subcommand Model
All symbols and addresses on this page apply to
neuronx_cc2.24.5133.0+58f8de22 (cp310 Cython moduleneuronxcc/driver/CommandDriver.cpython-310-x86_64-linux-gnu.so, 1,204,064 bytes). cp311/cp312 share the layout; addresses differ. Treat every offset as version-pinned. Evidence is the IDA full decompile (__pyx_pf/__pyx_pwbodies,__pyx_n_s_*attribute interns,_Pyx_AddTraceback(...)source-line markers) cross-checked against the binary's*_strings.json/*_functions.jsonsidecars.
Abstract
neuronx-cc is a multiplexing front door, not a monolithic compiler binary. A single ELF entry point (CommandDriver) parses a small set of driver-level arguments, peels off the first positional token as a subcommand name, looks that name up in a known_commands dictionary, and hands the remaining argv to the selected CommandInterface subclass. The public banner advertises two subcommands — compile and list-operators — but a third command class, neff-info, ships in driver/commands/ and is dispatchable even though it is omitted from the help text.
The other half of this page is process isolation. Under --fork-subcommand, the dispatcher does not run the subcommand inline; it spawns a multiprocessing.Process, joins it, reads its exitcode, and maps abnormal exits onto three operator-facing diagnostic codes — [F134], [F137], [F139] — so that a segfault or an OOM-kill inside the compile child surfaces as a clean error banner instead of a Python traceback on a dead interpreter. This is the boundary between "the driver crashed" and "the compile crashed," and the wiki treats it as the contract every subcommand runs behind.
| Module entry | CommandDriver.main @ 0x17a90 (neuronxcc.driver.CommandDriver.main) |
| Dispatcher | CommandDriver.run @ 0x25a70 (pw) / 0x1c510 (pf body, py-line 323) |
| Subcommand registry | self.known_commands (interned known_commands @ str 0x38970) |
| In-process runner | CommandDriver.run_subcommand @ 0x1a7c0 (py ~?) |
| Forked-child runner | CommandDriver.run_subcommand_in_process @ 0x19110 (py 366–367) |
| Error/exit formatter | CommandDriver.handleError @ 0x30470 (py-line 113) |
| Version printer | VersionAction.__call__ @ 0x2c830; getVersionString @ 0x2d690 |
| Usage string | %(prog)s [args] <subcommand> [<subcommand args>] @ 0x37ac0 |
The subcommand → Pipeline → Job descent that compile triggers is 3.3 The CompileCommand Pipeline; the two argparse systems behind it (3.2 Two-Parser Architecture); the whole-program orientation is 0.2 The Compile Pipeline at a Glance.
1. The CLI shape — one usage string, two-and-a-half subcommands
The top-level usage is a single interned literal at 0x37ac0, the complete text of which is (verbatim from the string pool):
%(prog)s [args] <subcommand> [<subcommand args>]
Run the AWS Neuron compiler.
The following subcommands are supported:
compile Compile a neural network model
list-operators List supported operators
See '%(prog)s <subcommand> --help' for more information about a
specific subcommand.
This is the [args] <subcommand> [<subcommand args>] model: a left band of driver-global options (--version/-V, --verbose, --logfile, --fork-subcommand, help flags), then one positional subcommand token, then everything to its right belongs to the subcommand. The split point is parse_known_args (below), not a position count.
Three command classes are present in driver/commands/, each a Cython .so:
| Subcommand name | CommandInterface subclass | Binary | In public banner? |
|---|---|---|---|
compile | CompileCommand | commands__CompileCommand.cpython-310-…so | yes |
list-operators | ListOperatorsCommand | commands__ListOperatorsCommand.cpython-310-…so | yes |
neff-info | NeffInfoCommand | commands__NeffInfoCommand.cpython-310-…so | no |
QUIRK —
neff-infois a banner-omitted command class. The two-line help block at0x37ac0lists onlycompileandlist-operators, yetNeffInfoCommand.cpython-310-…soships in the samedriver/commands/directory as the other two and exports the sameCommandInterfacesurface. It is reachable by name (theknown_commandsdict is built from the available command classes, not from the help banner), but it is intentionally absent from the public usage text — treat it as a semi-private inspection command (NEFF-container dump) rather than a compile entry point. The banner is documentation, not the dispatch table. (STRONG: all three binaries confirmed present; banner text CONFIRMED; the omission is structural, not a build artifact.)
--version / -V short-circuits dispatch entirely: it is wired to VersionAction (0x2c830), a custom argparse.Action whose __call__ prints getVersionString() and exits before any subcommand is selected. getVersionString (0x2d690) assembles the three-line block "NeuronX Compiler version " … "Python version " … "NumPy version " from KccVersion. (CONFIRMED: --version @ str 0x38d80, VersionAction @ str 0x38af8, version literals in getVersionString's string refs.)
2. Entry: main → logging → run
CommandDriver.main (0x17a90) is the wheel's console-script entry point. Its body (from interned attribute names) does three things before dispatch:
# neuronxcc.driver.CommandDriver.main @ 0x17a90 (reconstructed from __pyx_n_s_* interns)
def main():
# 1. Reset SIGINT to the default disposition so Ctrl-C kills the
# process group cleanly (interns: signal, SIGINT, SIG_DFL).
signal.signal(signal.SIGINT, signal.SIG_DFL)
# 2. Wire stdlib + absl logging: UTC timestamps, a single root handler.
logging.Formatter.converter = time.gmtime # interns: Formatter, converter, gmtime
logging.captureWarnings(True) # intern: captureWarnings
logging.root.removeHandler(absl_handler) # interns: root, removeHandler, absl_handler
# 3. Build the driver and dispatch on the real argv.
driver = CommandDriver() # __init__ @ 0x28160
sys.exit(driver.run(sys.argv)) # interns: run, sys, argv, exit
(CONFIRMED interns in main: signal/SIGINT/SIG_DFL, Formatter/converter/gmtime, captureWarnings, root/removeHandler/absl_handler, CommandDriver, run, sys/argv/exit. The gmtime converter forces UTC log timestamps; the absl_handler removal de-duplicates absl's auto-installed root handler.)
CommandDriver.__init__ (0x28160, 18,113 bytes, 271 callees) constructs the top-level InterceptingArgumentParser (the recording argparse subclass detailed in 3.2), registers the global [args] flags and the subcommand positional, builds the known_commands name→class dict, and seeds the per-level logging helpers (to_numeric_level @ 0x26c40 maps a log-level name — DEBUG/INFO/WARNING — to a numeric level). It is the largest non-dispatch function in the module.
3. Dispatch: parse_known_args → known_commands[name] → CommandInterface
The dispatcher is CommandDriver.run. Its public-wrapper is 0x25a70; the real body is the pf function at 0x1c510 (6,716 decompiled lines, py-line 323). The dispatch is a four-step pipeline, each step anchored to a concrete call site in the 0x1c510 decompile:
# CommandDriver.run (pf body @ 0x1c510) — annotated with decompile line numbers
def run(self, argv):
# ── STEP 1 · split driver args from subcommand args ───────────────────
# argparser.parse_known_args(argv) → (known_args, delegated_args)
known_args, delegated_args = self.argparser.parse_known_args(argv) # decomp L631
# `known_args` = the driver-level Namespace (verbose, logfile, fork, …)
# `delegated_args` = leftover tokens = the subcommand's own argv
# (interns: parse_known_args @0x387d0, known_args @0x38d20, delegated_args @0x389d0)
# ── STEP 2 · configure logging from the parsed Namespace ──────────────
# verbose → numeric level; console vs logfile handler selection.
# (interns: setup_console_logging, setup_logfile_logging, getLogger,
# StreamHandler, FileHandler, Formatter, setLevel, isatty)
# ── STEP 3 · select the subcommand class by name ──────────────────────
subcommand = self.known_commands[command_name] # decomp L1075
# command_name = known_args's subcommand positional;
# known_commands maps 'compile'→CompileCommand, 'list-operators'→…,
# 'neff-info'→NeffInfoCommand. Each subclass returns its own name via
# CommandInterface.getCommandName() (intern getCommandName @0x389a0).
# ── STEP 4 · run it, in-process or forked (see §4) ────────────────────
if known_args.fork_subcommand: # decomp L5150
exitcode = <run in a child Process> # §4
else:
exitcode = self.run_subcommand(subcommand, delegated_args, logfile)
return exitcode
The key structural fact: parse_known_args (not parse_args) is what makes the [args] <subcommand> [<subcommand args>] grammar work. The top parser is deliberately permissive — it knows only the driver-global flags, so any token it does not recognise (every subcommand flag) falls into delegated_args instead of triggering an "unrecognized arguments" error. That leftover list becomes the subcommand's argv unchanged. The two-parser design (3.2) is precisely so the driver parser and the subcommand parser can each parse_known_args their own slice of the same flat argv without fighting over flags they do not own.
NOTE —
getCommandNameis the registry's source of truth.CommandInterface(base class @0x8830incommands__CommandInterface.cpython-310-…so) declaresgetCommandName@0x9150; each subclass overrides it to return its subcommand string ('compile','list-operators','neff-info'). Theknown_commandsdict inCommandDriver.__init__is keyed by exactly these return values, so adding a command is a matter of registering one more class whosegetCommandNameyields a fresh name — there is no separate name table to keep in sync. (CONFIRMED:getCommandNamesymbol in bothCommandDriver(str0x389a0) andCommandInterface(0x9150);known_commandsintern0x38970.)
run_subcommand (0x1a7c0) is the in-process path: it calls subcommand.run(delegated_args, …) (intern run, self, subcommand, delegated_args, logfile), wrapping failures through handleError and falling back to os.EX_SOFTWARE on error (interns os, EX_SOFTWARE, handleError). For compile, subcommand.run is CompileCommand.run → buildPipeline → runPipeline — see 3.3.
4. Process isolation: --fork-subcommand
The flag --fork-subcommand (interned literal 0x38890; Namespace attr fork_subcommand @ str 0x386a0) switches dispatch from inline to a forked child. The decompile in run (0x1c510) shows the exact sequence:
# CommandDriver.run, fork path (pf body @ 0x1c510) — decompile line anchors
if known_args.fork_subcommand: # L5150
multiprocessing.set_start_method(...) # interns: multiprocessing, set_start_method
child = multiprocessing.Process( # L5505 (intern Process)
target = self.run_subcommand_in_process, # L5538
args = (subcommand, delegated_args, logfile),
)
child.start() # intern: start
child.join() # intern: join
code = child.exitcode # L5708 (intern exitcode @0x37493)
# log "Subcommand returned with exitcode=" + code (str @0x37800)
if <code indicates failure>:
handleError(...) # L6174 / L6181
sys.exit(os.EX_SOFTWARE) # L6367 (intern EX_SOFTWARE @0x38c80)
return code
The child target, run_subcommand_in_process (0x19110, py-lines 366–367), is a thin shim around the same in-process runner, terminated by an explicit interpreter teardown so the child exits cleanly with the subcommand's status:
# CommandDriver.run_subcommand_in_process(self, subcommand, delegated_args, logfile)
# @ 0x19110 (py 366–367; interns: run_subcommand, logging, shutdown, sys, exit)
def run_subcommand_in_process(self, subcommand, delegated_args, logfile):
rc = self.run_subcommand(subcommand, delegated_args, logfile) # py 366
logging.shutdown() # flush+close every handler before the child dies
sys.exit(rc) # py 367 — child's exitcode == subcommand status
(CONFIRMED: run_subcommand_in_process arg names subcommand/delegated_args/logfile from __pyx_pyargnames + interns; calls run_subcommand, then logging.shutdown() and sys.exit via interns logging/shutdown/sys/exit; _Pyx_AddTraceback(..., 366, 366, ...) and ..., 367, 367, ... markers pin the py-lines.)
The rationale is the ICE/OOM banner. run_subcommand_in_process and handleError carry the operator text (interned in this module):
An Internal Compiler Error has occurred
Processes may be terminated if they encountered an internal error or if there
was insufficient memory. Please review the log file for any error conditions.
Please check the available memory on the compile instance. Current memory
usage for neuronxcc is …
handleError (0x30470, py-line 113) is where a child failure is classified: it inspects the broken-process condition (interns BrokenProcessPool, RemoteTraceback, TracebackException, from_exception, origin_job), reads resident-set sizes for the memory report (interns resource, getrusage, ru_maxrss, RUSAGE_CHILDREN, RUSAGE_SELF), tears down global compiler state (intern FinalizeGlobalState), and emits one of the [F134]/[F137]/[F139] banners. (CONFIRMED interns in handleError; BrokenProcessPool also interned at str 0x38770, RUSAGE_CHILDREN @ 0x388e0, RUSAGE_SELF @ 0x38c50.)
GOTCHA —
--fork-subcommandis the only thing that makesexitcodemeaningful. Without the flag,run_subcommandruns the subcommand in the driver's own interpreter; a hard crash (SIGSEGV in a native pass) or an OOM-kill takes the wholeneuronx-ccprocess down and there is no survivingexitcodeto inspect. With the flag, the crash is confined to themultiprocessing.Processchild; the parent readschild.exitcode, recognises the negative (signal) or non-zero status, and converts it into a support-ticket banner. Framework integrations that compile many graphs in one host process rely on this isolation so one bad graph does not abort the batch. (STRONG.)
5. The crash-exit codes — [F134], [F137], [F139]
Three diagnostic banners are interned in this module (symbol names from *_names.json, message text from *_strings.json):
| Code | Symbol | Addr | Message (verbatim) |
|---|---|---|---|
[F134] | __pyx_k_F134_neuronx_cc_terminated_abno | 0x37fa0 | [F134] neuronx-cc terminated abnormally - Please open a support ticket at https://github.com/aws-neuron/aws-neuron-sdk/issues/new |
[F137] | __pyx_k_F137_neuronx_cc_was_forcibly_ki | 0x37ee0 | [F137] neuronx-cc was forcibly killed - This most commonly occurs due to insufficient system memory. Using a smaller data type, dimensions, batch size, or a larger instance type may help. |
[F139] | __pyx_k_F139_neuronx_cc_terminated_abno | 0x37e40 | [F139] neuronx-cc terminated abnormally - Please open a support ticket at https://github.com/aws-neuron/aws-neuron-sdk/issues/new |
The codes are not arbitrary — they decode the child's exit status under the POSIX 128 + signal convention, which is exactly what a multiprocessing.Process.exitcode reports as a negative number for a signal-killed child:
F134= 128 + 6 = SIGABRT — the child aborted (a C++assert/abort(), an uncaughtstd::terminate, or a Python-level fatal in a native pass). Generic "terminated abnormally."F137= 128 + 9 = SIGKILL — the child was forcibly killed, almost always the OOM-killer reclaiming memory. The message is the only one of the three that suggests a remedy (smaller dtype / batch / bigger instance), because OOM is the dominant cause.F139= 128 + 11 = SIGSEGV — the child segfaulted. Second "terminated abnormally" variant, distinguished fromF134only by the originating signal.
CORRECTION —
F137is SIGKILL (128+9), not "SIGSEGV", andF139is SIGSEGV (128+11). An earlier strand note pairedF137with SIGSEGV. The numeric suffixes are self-describing under128 + signo: 134→SIGABRT(6), 137→SIGKILL(9), 139→SIGSEGV(11). TheF137message text ("was forcibly killed … insufficient system memory") is the SIGKILL/OOM banner, confirming the 128+9 reading over any SIGSEGV pairing. (STRONG: the message text disambiguates; the suffix arithmetic is the standard shell convention for signal-terminated processes.)
NOTE — the exact
exitcode → [F13x]branch is derived, not a clean switch. The three banner constants are interned by__Pyx_CreateStringTabAndInitStrings(0x4bbf) and selected on the child'sexitcode(read atrundecompile L5708) inside the failure path that callshandleError(L6174). The decompiler renders the per-code selection as opaque interned-const loads from_pyx_mstate_global_staticrather than a readableswitch, so the precise comparison thresholds are INFERRED from the128 + signoarithmetic and the message semantics; the ownership (this isCommandDriver'srun/run_subcommand_in_process/handleErrortriad) and the banner identities are CONFIRMED. The final driver-level exit on a failed fork isos.EX_SOFTWARE(str0x38c80, decompile L6367).*
6. End-to-end flow
sys.argv
│
▼
CommandDriver.main (0x17a90)
│ SIGINT→SIG_DFL; UTC logging; build CommandDriver
▼
CommandDriver.run (pf 0x1c510)
│ ① argparser.parse_known_args(argv) → (known_args, delegated_args) L631
│ ② configure logging from known_args
│ ③ subcommand = known_commands[command_name] L1075
│ compile → CompileCommand list-operators → ListOperatorsCommand
│ neff-info → NeffInfoCommand (banner-omitted)
│ ④ dispatch ↓
├───────────────── known_args.fork_subcommand? (L5150) ─────────────────┐
│ NO (inline) │ YES (isolated) │
▼ ▼ │
run_subcommand (0x1a7c0) multiprocessing.Process( │
subcommand.run(delegated_args) target=run_subcommand_in_process, │
handleError on failure; args=(subcommand, delegated_args, │
os.EX_SOFTWARE logfile)) (L5505/L5538) │
child.start(); child.join() │
code = child.exitcode (L5708) │
┌── code abnormal? ───────────────┐ │
│ handleError (L6174) → │ │
│ [F134]/[F137]/[F139] banner; │ │
│ sys.exit(os.EX_SOFTWARE) L6367 │ │
└─────────────────────────────────┘ │
│ │
▼ (compile only) │
CompileCommand.run → buildPipeline → runPipeline ── see 3.3 ───────────────┘
7. Adversarial self-verification
The five strongest claims on this page, re-challenged against the binary:
- Two public subcommands + a hidden
neff-info. The usage banner (0x37ac0) lists onlycompile/list-operators— CONFIRMED verbatim.NeffInfoCommand.cpython-310-…soexists alongside the other two command binaries — CONFIRMED by directory listing. That it is dispatchable but un-bannered is STRONG (the dict is built from command classes viagetCommandName, not from the help text), not CONFIRMED at the byte level for the precise registry-population call. parse_known_argsis the argv split. Theparse_known_argsintern (0x387d0) is referenced atrundecompile L631, producingknown_args(0x38d20) anddelegated_args(0x389d0) — CONFIRMED.known_commands[name]selects the class. Theknown_commandsintern (0x38970) is indexed atrundecompile L1075 withgetCommandName(0x389a0) as the key source — CONFIRMED.- Fork path =
multiprocessing.Process(target=run_subcommand_in_process)→ readexitcode.fork_subcommandchecked at L5150,Processat L5505,run_subcommand_in_processtarget at L5538,exitcoderead at L5708,handleErrorat L6174,EX_SOFTWAREat L6367 — all CONFIRMED call-site anchors in the0x1c510decompile. [F134]=SIGABRT, [F137]=SIGKILL/OOM, [F139]=SIGSEGVvia128+signo. Banner symbols/text CONFIRMED (0x37fa0/0x37ee0/0x37e40). The signal mapping is INFERRED from the suffix arithmetic + theF137"forcibly killed / insufficient memory" text; the exactexitcode→bannercomparison is not a readable switch in the decompile (interned-const loads), so the threshold logic is tagged INFERRED while ownership and identities are CONFIRMED.
Nothing on this page references a source tree; every symbol, offset, string, and py-line is read from the shipped Cython .so and its IDA sidecars.