rpc: do not abort on shutdown when a teardown round trip fails - #203
Open
danielhanchen wants to merge 1 commit into
Open
rpc: do not abort on shutdown when a teardown round trip fails#203danielhanchen wants to merge 1 commit into
danielhanchen wants to merge 1 commit into
Conversation
llama-server built with GGML_RPC aborts on exit, after it has printed "cleaning up before exit", inside ggml_backend_rpc_get_device_memory called from common_memory_breakdown_print: ggml-rpc.cpp: Remote RPC server crashed or returned malformed response #3 ggml_backend_rpc_get_device_memory #4 common_memory_breakdown_print(llama_context const*) #5 llama_server(common_params&, int, char**) The memory breakdown is printed after clean_up(), which calls llama_backend_free(). The RPC device answers get_memory with a round trip to the peer, and by that point the round trip fails, so RPC_STATUS_ASSERT aborts the process. Reproduced with a peer rpc-server that is alive and healthy the whole time, so this is not about the peer going away first. Device memory is an informational property, not part of the data path, and the function already has a defined answer for an endpoint it cannot reach: report 0/0. Report the same when the query itself fails. Freeing a remote buffer is released state and is also a teardown operation, so a failure there is logged instead of aborting; if the peer is gone then so is the buffer. Every other RPC_STATUS_ASSERT, including all the data path ones, is unchanged. Confined to ggml/src/ggml-rpc/ggml-rpc.cpp, which is compiled only when GGML_RPC is on (OFF by default, ggml_add_backend(RPC) in ggml/src/CMakeLists.txt), so a build without RPC is untouched.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
You have reached your Codex usage limits for security reviews. Please try again later. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What happens
llama-serverbuilt withGGML_RPCaborts on exit, after it has already printedcleaning up before exit:Why
common_memory_breakdown_print()is called afterclean_up(), which callsllama_backend_free(). The RPC device answersget_memorywith a round trip to the peer,and by that point the round trip fails, so
RPC_STATUS_ASSERTaborts the process.This was first seen on a two node layer split where the peer
ggml-rpc-serverhad beenstopped before the local server exited, so it looked like a consequence of the peer going
away. It is not. It reproduces with a peer that is alive and healthy for the whole run,
which makes it a deterministic abort on every shutdown of a server that uses
--rpc.The fix
Device memory is an informational property, not part of the data path, and
ggml_backend_rpc_get_device_memory()already has a defined answer for an endpoint itcannot reach at all: report 0 free and 0 total. Report the same when the query itself
fails, and log an error.
Freeing a remote buffer is released state and is also a teardown operation, so a failure
there is logged instead of aborting: if the peer is gone then so is the buffer, and the
local context is freed either way. Without this second hunk the process still aborts a few
microseconds later in
ggml_backend_rpc_buffer_free_bufferfromggml_backend_sched_free, on the way out of~llama_context.Every other
RPC_STATUS_ASSERT, including all of the data path ones, is unchanged. Afailure while setting or getting a tensor or running a graph still aborts.
The alternative, teaching
common_memory_breakdown_print()to skip backends whoseconnection has dropped, was rejected: that code is shared with every non-RPC build and has
no way to ask a backend whether it is still reachable, so it would need a new backend
interface entry for one caller. Caching the last known figure inside the RPC backend was
also rejected: it adds state to keep in sync in order to print a number that is meaningless
by the time it is printed.
What was measured
CPU only,
stories15M-q4_0.gguf, a localggml-rpc-serveron 127.0.0.1, server startedwith
--rpc 127.0.0.1:PORT --device RPC0 -ngl 99, one completion served, then SIGINT.failed to query device memory of ..., reporting 0and three
failed to free the remote buffer, the connection is gone.Non-RPC builds
The change touches one file,
ggml/src/ggml-rpc/ggml-rpc.cpp. That file is compiled onlythrough
ggml_add_backend(RPC)inggml/src/CMakeLists.txt, which adds the subdirectoryonly if
GGML_RPCis set, andGGML_RPCdefaults to OFF inggml/CMakeLists.txt. Noheader, no public signature and no shared code path changes, so NVIDIA, AMD and CPU only
builds without RPC are byte for byte unaffected.