nvproxy: support NV_EVENT_BUFFER - #14005
Conversation
| 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 | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Gotcha. Want me to write an explicit rejection? The driver will reject it today, right?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Did the simplest: added rmAllocEventBuffer that returns linuxerr.EINVAL when HBufferHeader == 0. Let me know what you think.
There was a problem hiding this comment.
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.
f197193 to
6e274bf
Compare
|
@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).
6e274bf to
83a0e2d
Compare
|
Thanks @luiscape! I think one last issue left, we still need to translate the |
Adds the NV_EVENT_BUFFER (0x90cd) event-record buffer API when
capProfilingis enabled.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=trueflag. 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.