Skip to content

nvproxy: support NV_EVENT_BUFFER - #14005

Open
luiscape wants to merge 1 commit into
google:masterfrom
luiscape:luis/nv-event-buffer-support
Open

nvproxy: support NV_EVENT_BUFFER#14005
luiscape wants to merge 1 commit into
google:masterfrom
luiscape:luis/nv-event-buffer-support

Conversation

@luiscape

@luiscape luiscape commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Adds the NV_EVENT_BUFFER (0x90cd) event-record buffer API when capProfiling is enabled.

  • Allocation classes: NV_EVENT_BUFFER (0x90cd), NV_EVENT_BUFFER_BIND (0x7f).
  • Control commands: NV_EVENT_BUFFER_CTRL_CMD_{ENABLE_EVENTS,UPDATE_GET,FLUSH}, NV2080_CTRL_CMD_GR_FECS_BIND_EVTBUF_FOR_UID, NV2080_CTRL_CMD_EVENT_VIDEO_BIND_EVTBUF.

Validated with tools/nvidia_driver_differ and the driver struct parity test (20 supported drivers).

This adds support to GPU context switches when profiling, specifically the nsys profile --gpuctxsw=true flag. Example:

nsys profile --trace=cuda --gpuctxsw=true -o /out/rep --force-overwrite=true \
  python3 -c "import torch; torch.mm(torch.rand(4096,4096,device='cuda'), torch.rand(4096,4096,device='cuda')); torch.cuda.synchronize()"

Without this implementation the program above will generate a profile with empty context switches.

@github-actions
github-actions Bot requested review from fvoznika and trantoji August 5, 2026 23:00
@EtiennePerot
EtiennePerot requested review from ayushr2 and removed request for fvoznika and trantoji August 6, 2026 00:03
Comment thread pkg/abi/nvgpu/classes.go Outdated
Comment thread pkg/sentry/devices/nvproxy/version.go Outdated
Comment thread pkg/abi/nvgpu/classes.go
Comment thread pkg/abi/nvgpu/ctrl.go Outdated
Comment thread pkg/abi/nvgpu/classes.go Outdated
Comment thread pkg/abi/nvgpu/classes.go
Comment on lines +298 to +314
type NV_EVENT_BUFFER_ALLOC_PARAMETERS struct {
_ structs.HostLayout
BufferHeader P64
RecordBuffer P64
RecordSize uint32
RecordCount uint32
VardataBuffer P64
VardataBufferSize uint32
RecordsFreeThreshold uint32
NotificationHandle uint64
VardataFreeThreshold uint32
HSubDevice Handle
Flags uint32
HBufferHeader Handle
HRecordBuffer Handle
HVardataBuffer Handle
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually needs a lot of translation. According to driver source code:

  • NotificationHandle is actually a FD. We need to translate it to a frontend host FD.
  • BufferHeader / RecordBuffer / VardataBuffer are all pointers. But this is more nuanced. More below

When HBufferHeader == 0, the driver allocates the buffers and memdescMaps them into the caller's user VA (_allocAndMapMemory), returning those VAs in these fields. Under gVisor the caller is the sentry, so the mapping lands in the sentry's address space and the returned VAs are meaningless to the guest app. This is more involved since you'd have to intercept these like NV_ESC_RM_MAP_MEMORY, re-establishing the mapping in the guest address space via the memmap machinery.

Caller-provided mode (hBufferHeader/hRecordBuffer/hVardataBuffer != 0): the caller supplies NV01_MEMORY_DEVICELESS objects it already allocated/mapped itself. No kernel-side mapping into the caller happens for the guest's benefit, so this mode is far more tractable to proxy.

Do you know if we actually see HBufferHeader == 0 in practice?

@luiscape luiscape Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be difficult to translate memory but, when running the profiling with nsys profile --trace=cuda --gpuctxsw=true, I don't see HBufferHeader==0 so plain rmAllocSimple works. I'd leave this as is unless I have evidence that a program sends HBufferHeader==0.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't think we should translate memory either. But to be safe, we should programmatically reject HBufferHeader == 0 and only passthrough HBufferHeader != 0. It would require defining a function for NV_EVENT_BUFFER.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. Want me to write an explicit rejection? The driver will reject it today, right?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The driver will not reject it; i.e. HBufferHeader == 0 will cause it to allocate stuff in sentry's address space and we won't be able to translate it easily. So better to reject it in nvproxy rather than letting it passthrough and succeed and the application getting a sentry VA in the response of the ioctl, which when it accesses will cause a SIGSEGV since that VA doesn't make sense it the application address space.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did the simplest: added rmAllocEventBuffer that returns linuxerr.EINVAL when HBufferHeader == 0. Let me know what you think.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to translate NotificationHandle, which is a frontend FD. The handler must translate NotificationHandle guest fd -> frontendFD.hostFD when non-zero (and leave 0 as-is, which disables notifications), restoring the original on copy-out. You can see rmAllocEventOSEvent(), which does exactly this for NV0005's Data fd.

@luiscape
luiscape force-pushed the luis/nv-event-buffer-support branch 2 times, most recently from f197193 to 6e274bf Compare August 8, 2026 02:10
@luiscape

luiscape commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@ayushr2 I ran a smaller example and collected more data about the allocations. I responded to your review -- thank you. Ready for another pass.

Adds the NV_EVENT_BUFFER (0x90cd) event-record buffer API when `capProfiling` is enabled.

- Allocation classes: NV_EVENT_BUFFER (0x90cd), NV_EVENT_BUFFER_BIND (0x7f).
- Control commands: NV_EVENT_BUFFER_CTRL_CMD_{ENABLE_EVENTS,UPDATE_GET,FLUSH}, NV2080_CTRL_CMD_GR_FECS_BIND_EVTBUF_FOR_UID, NV2080_CTRL_CMD_EVENT_VIDEO_BIND_EVTBUF.

Validated with tools/nvidia_driver_differ and the driver struct parity test (20 supported drivers).
@luiscape
luiscape force-pushed the luis/nv-event-buffer-support branch from 6e274bf to 83a0e2d Compare August 10, 2026 16:19
@ayushr2

ayushr2 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Thanks @luiscape! I think one last issue left, we still need to translate the NotificationHandle, which is a FD.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants