oxidecomputer / idolatry

An experimental IPC interface definition language for Hubris.
Mozilla Public License 2.0
17 stars 11 forks source link

generate counters for client and server IPC ops #43

Closed hawkw closed 8 months ago

hawkw commented 8 months ago

Depends on #41.

This branch adds the capability to automatically generate counters of IPC operations using the Hubris counters crate to Idol code generation. Counters can be generated for both client and server stubs, and will generate a separate counter for each IPC operation in an interface. Fallible IPC operations will generate separate counters of Ok and Err responses, with the Err path including child counters of each variant of the IPC's error type, provided it derives the Count trait.

In order to configure how and where counters are generated, I've added a new Generator struct that represents a code-generation configuration. This type has flags for whether counters are enabled, and a flag that changes the server-side counter generation to track all ClientError variants globally rather than per-IPC, if this is necessary to limit the size of the generated counter table. This is configured using the Generator struct added in #41.

This also requires additions to the counters crate in the corresponding Hubris PR #1642.

As an example, the counters generated by this branch for the Gimlet sequencer IPC API look like this in Humility. Note that a separate set of counters is generated for each task which is a client of the sequencer:

Humility output: ```console $ humility -d hubris.c12.autocounts.core.3 counters --full __SEQUENCER_CLIENT` humility: attached to dump control_plane_agent | +---> drv_gimlet_seq_api::__SEQUENCER_CLIENT_COUNTERS: 0 get_state(_) 0 | get_state(Ok) 0 | get_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 set_state(_) 0 | set_state(Ok) 0 | set_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_on(_) 0 | fans_on(Ok) 0 | fans_on(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_off(_) 0 | fans_off(Ok) 0 | fans_off(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 send_hardware_nmi(_) 0 | send_hardware_nmi(Ok) 0 | send_hardware_nmi(Err) 0 read_fpga_regs(_) 0 | read_fpga_regs(Ok) 0 | read_fpga_regs(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) gimlet_inspector | +---> drv_gimlet_seq_api::__SEQUENCER_CLIENT_COUNTERS: 0 get_state(_) 0 | get_state(Ok) 0 | get_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 set_state(_) 0 | set_state(Ok) 0 | set_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_on(_) 0 | fans_on(Ok) 0 | fans_on(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_off(_) 0 | fans_off(Ok) 0 | fans_off(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 send_hardware_nmi(_) 0 | send_hardware_nmi(Ok) 0 | send_hardware_nmi(Err) 0 read_fpga_regs(_) 0 | read_fpga_regs(Ok) 0 | read_fpga_regs(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) host_sp_comms | +---> drv_gimlet_seq_api::__SEQUENCER_CLIENT_COUNTERS: 4 get_state(_) 4 +---> get_state(Ok) 0 | get_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 set_state(_) 0 | set_state(Ok) 0 | set_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_on(_) 0 | fans_on(Ok) 0 | fans_on(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_off(_) 0 | fans_off(Ok) 0 | fans_off(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 send_hardware_nmi(_) 0 | send_hardware_nmi(Ok) 0 | send_hardware_nmi(Err) 0 read_fpga_regs(_) 0 | read_fpga_regs(Ok) 0 | read_fpga_regs(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) power | +---> drv_gimlet_seq_api::__SEQUENCER_CLIENT_COUNTERS: 67 get_state(_) 67 +---> get_state(Ok) 0 | get_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 set_state(_) 0 | set_state(Ok) 0 | set_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_on(_) 0 | fans_on(Ok) 0 | fans_on(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_off(_) 0 | fans_off(Ok) 0 | fans_off(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 send_hardware_nmi(_) 0 | send_hardware_nmi(Ok) 0 | send_hardware_nmi(Err) 0 read_fpga_regs(_) 0 | read_fpga_regs(Ok) 0 | read_fpga_regs(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) thermal | +---> drv_gimlet_seq_api::__SEQUENCER_CLIENT_COUNTERS: 146 get_state(_) 146 +---> get_state(Ok) 0 | get_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 set_state(_) 0 | set_state(Ok) 0 | set_state(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_on(_) 0 | fans_on(Ok) 0 | fans_on(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 fans_off(_) 0 | fans_off(Ok) 0 | fans_off(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) 0 send_hardware_nmi(_) 0 | send_hardware_nmi(Ok) 0 | send_hardware_nmi(Err) 0 read_fpga_regs(_) 0 | read_fpga_regs(Ok) 0 | read_fpga_regs(Err(_)) 0 | Err(IllegalTransition) 0 | Err(MuxToHostCPUFailed) 0 | Err(MuxToSPFailed) 0 | Err(ReadRegsFailed) 0 | Err(CPUNotPresent) 0 | Err(UnrecognizedCPU) 0 | Err(A1Timeout) 0 | Err(A0TimeoutGroupC) 0 | Err(A0Timeout) 0 | Err(I2cFault) 0 | Err(ServerRestarted) ```
hawkw commented 8 months ago

Unfortunately, merging this is a little bit tricky, as there's kind of a circular dependency between the hubris and idolatry repos. This branch currently has a Git dep on oxidecomputer/hubris#1642, the branch that integrates these changes with Hubris, because it needs changes to the counters crate in the Hubris repo. But, oxidecomputer/hubris#1642 depends on idolatry from this branch, because it uses the new APIs added in this change.

I'm going to separate out the counters crate changes in the Hubris repo, so that we can merge them first. That way, we can merge this PR without having a broken master branch in either repo, and without merging branch deps to master.

hawkw commented 8 months ago

Update: the Hubris PRs that need to merge before this branch are oxidecomputer/hubris#1640 and oxidecomputer/hubris#1647. Once those branches have merged, this PR can depend on oxidecomputer/hubris@master, and we can merge it, and then move on to actually using the new counter generation stuff in Hubris.

hawkw commented 8 months ago

Okay, this branch now depends on oxidecomputer/hubris@master again, now that the requisite PRs have merged.