Re: [PATCH 2/3] plugin/amdgpu: Add topology dump file

Tvrtko Ursulin <[email protected]> Wed, 22 Apr 2026 14:58:19 +0100
Newsgroups dev.linux.lists.criu
Message-ID <[email protected]>
On 17/04/2026 14:21, Francis, David wrote:
>>>> Ah neat, but I am guessing the data comes from kfd? At some point we
>>>> will need to bite the bullet and start designing uapi for an amdgpu only
>>>> world.
>>>
>>> No, the data comes solely from sysfs in this case.
>>
>> But exported by kfd, no? Ie. /sys/class/kfd/kfd/topology/nodes/. I
>> understand the goal is to migrate away from kfd which is why I wondered
>> if it makes sense to add an image based of both internal and external
>> kfd data.
> 
> I think current plans are to deprecate the kfd device file first -
> /sys/class/kfd will continue to exist for a good while longer.

Exported by the kfd driver, or you mean the plan is to export them from 
amdgpu to achieve uapi compatibility in a way?

Regards,

Tvrtko

>> In one aspect it is better than my hack of allow restore from a single
>> to a single GPU system, although even there the gpu id is not stable,
>> but on the other hand it does add an image format which looks like a
>> dead end from a design persective.
>>
>> Hm, how does this patch handle gpu id changing across reboots?
> 
> It does the whole amdgpu_plugin_topology matching thing to find a
> mapping between the old GPUs and the new ones.
> 
> The renderD minor numbers of the new GPUs determine which files are
> opened to replace the open renderD handles. It doesn't really matter
> what the gpu ids are at that point. To target a specific GPU in amdgpu,
> you don't need gpu id, you just point the operation at the right renderD
> file.
> 
> ________________________________________
> From: Tvrtko Ursulin <[email protected]>
> Sent: Friday, April 17, 2026 5:07 AM
> To: Francis, David; [email protected]
> Subject: Re: [PATCH 2/3] plugin/amdgpu: Add topology dump file
> 
> 
> On 16/04/2026 19:26, Francis, David wrote:
>>> Ah neat, but I am guessing the data comes from kfd? At some point we
>>> will need to bite the bullet and start designing uapi for an amdgpu only
>>> world.
>>
>> No, the data comes solely from sysfs in this case.
> 
> But exported by kfd, no? Ie. /sys/class/kfd/kfd/topology/nodes/. I
> understand the goal is to migrate away from kfd which is why I wondered
> if it makes sense to add an image based of both internal and external
> kfd data.
> 
>> No urgency on merging this since it doesn't do much without more patches
>> but also unlikely to cause problems on its own - if kfd is present, the plugin
>> will continue to make the same dump it always did.
>>
>> Review would be appreciated, thanks.
> 
> In one aspect it is better than my hack of allow restore from a single
> to a single GPU system, although even there the gpu id is not stable,
> but on the other hand it does add an image format which looks like a
> dead end from a design persective.
> 
> Hm, how does this patch handle gpu id changing across reboots?
> 
> Regards,
> 
> Tvrtko
> 
>> ________________________________________
>> From: Tvrtko Ursulin <[email protected]>
>> Sent: Thursday, April 16, 2026 10:54 AM
>> To: Francis, David; [email protected]
>> Subject: Re: [PATCH 2/3] plugin/amdgpu: Add topology dump file
>>
>>
>> On 10/04/2026 15:45, David Francis wrote:
>>> The state of the source topology (the GPUs, CPUs, and links
>>> between them) is saved by the plugin as part of kfd dump.
>>>
>>> If there is no kfd dump, we need to save the topology anyways.
>>>
>>> Do so in new file amdgpu-topology.img.
>>
>> Ah neat, but I am guessing the data comes from kfd? At some point we
>> will need to bite the bullet and start designing uapi for an amdgpu only
>> world.
>>
>> In the meantime, would you like me to review this in detail to perhaps
>> have it merged in the interim? Although in that case backward
>> compatibility gets more complicated.
>>
>> Regards,
>>
>> Tvrtko
>>
>>>
>>> Signed-off-by: David Francis <[email protected]>
>>> ---
>>>     plugins/amdgpu/amdgpu_plugin.c      | 84 ++++++++++++++++++++++++++---
>>>     plugins/amdgpu/amdgpu_plugin_drm.c  | 64 ++++++++++++++++++++--
>>>     plugins/amdgpu/amdgpu_plugin_util.h |  9 ++++
>>>     plugins/amdgpu/criu-amdgpu.proto    |  5 ++
>>>     4 files changed, 151 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/plugins/amdgpu/amdgpu_plugin.c b/plugins/amdgpu/amdgpu_plugin.c
>>> index 89ab10dac..1e9785440 100644
>>> --- a/plugins/amdgpu/amdgpu_plugin.c
>>> +++ b/plugins/amdgpu/amdgpu_plugin.c
>>> @@ -91,6 +91,9 @@ int current_pid;
>>>      */
>>>     bool parallel_disabled = false;
>>>
>>> +bool kfd_dump_complete = false;
>>> +bool amdgpu_topology_dump_complete = false;
>>> +
>>>     pthread_t parallel_thread = 0;
>>>     int parallel_thread_result = 0;
>>>     /**************************************************************************************************/
>>> @@ -189,9 +192,14 @@ int topology_to_devinfo(struct tp_system *sys, struct device_maps *maps, KfdDevi
>>>                 devinfo->node_id = node->id;
>>>
>>>                 if (NODE_IS_GPU(node)) {
>>> -                     devinfo->gpu_id = maps_get_dest_gpu(maps, node->gpu_id);
>>> -                     if (!devinfo->gpu_id)
>>> -                             continue;
>>> +                     if (maps) {
>>> +                             devinfo->gpu_id = maps_get_dest_gpu(maps, node->gpu_id);
>>> +                             if (!devinfo->gpu_id)
>>> +                                     continue;
>>> +                     } else {
>>> +                             devinfo->gpu_id = node->gpu_id;
>>> +                     }
>>> +
>>>
>>>                         devinfo->simd_count = node->simd_count;
>>>                         devinfo->mem_banks_count = node->mem_banks_count;
>>> @@ -238,9 +246,13 @@ int topology_to_devinfo(struct tp_system *sys, struct device_maps *maps, KfdDevi
>>>                                 if (!iolink->valid)
>>>                                         continue;
>>>
>>> -                             list_for_each_entry(node2, &sys->nodes, listm_system)
>>> -                                     if (node2->id == iolink->node_to_id && maps_get_dest_gpu(maps, node2->gpu_id) != 0)
>>> -                                             link_to_present_node = true;
>>> +                             if (maps) {
>>> +                                     list_for_each_entry(node2, &sys->nodes, listm_system)
>>> +                                             if (node2->id == iolink->node_to_id && maps_get_dest_gpu(maps, node2->gpu_id) != 0)
>>> +                                                     link_to_present_node = true;
>>> +                             } else {
>>> +                                     link_to_present_node = true;
>>> +                             }
>>>
>>>                                 if (!link_to_present_node)
>>>                                         continue;
>>> @@ -386,6 +398,11 @@ int amdgpu_plugin_init(int stage)
>>>         maps_init(&checkpoint_maps);
>>>         maps_init(&restore_maps);
>>>
>>> +     if (stage == CR_PLUGIN_STAGE__DUMP) {
>>> +             kfd_dump_complete = false;
>>> +             amdgpu_topology_dump_complete = false;
>>> +     }
>>> +
>>>         if (stage == CR_PLUGIN_STAGE__RESTORE) {
>>>                 if (has_children(root_item)) {
>>>                         pr_info("Parallel restore disabled\n");
>>> @@ -1552,6 +1569,7 @@ int amdgpu_plugin_dump_file(int fd, int id)
>>>         if (ret)
>>>                 goto exit;
>>>
>>> +     kfd_dump_complete = true;
>>>         if (!plugin_added_to_inventory) {
>>>                 ret = add_inventory_plugin(CR_PLUGIN_DESC.name);
>>>                 if (ret) {
>>> @@ -1908,6 +1926,60 @@ int amdgpu_plugin_restore_file(int id, bool *retry_needed)
>>>
>>>                 pr_info("render node gpu_id = 0x%04x\n", rd->gpu_id);
>>>
>>> +             if (list_empty(&restore_maps.cpu_maps) && list_empty(&restore_maps.gpu_maps)) {
>>> +                     AmdgpuDevinfo *ad;
>>> +
>>> +                     pr_info("No restore maps found, making them from topology file\n");
>>> +
>>> +                     img_fp = open_img_file(IMG_AMDGPU_TOPOLOGY_FILE, false, &img_size, true);
>>> +                     if (!img_fp) {
>>> +                             pr_err("Failed to find either kfd or amdgpu src topology information\n");
>>> +                             ret = -EINVAL;
>>> +                             goto exit;
>>> +                     }
>>> +
>>> +                     buf = xmalloc(img_size);
>>> +                     if (!buf) {
>>> +                             pr_err("Failed to allocate memory\n");
>>> +                             return -ENOMEM;
>>> +                     }
>>> +
>>> +                     ret = read_fp(img_fp, buf, img_size);
>>> +                     if (ret) {
>>> +                             pr_err("Unable to read from %s\n", IMG_AMDGPU_TOPOLOGY_FILE);
>>> +                             ret = -EINVAL;
>>> +                             goto exit;
>>> +                     }
>>> +
>>> +                     ad = amdgpu_devinfo__unpack(NULL, img_size, buf);
>>> +                     if (rd == NULL) {
>>> +                             pr_perror("Unable to parse the amdgpu topology message\n");
>>> +                             fclose(img_fp);
>>> +                             ret = -EINVAL;
>>> +                             goto exit;
>>> +                     }
>>> +                     fclose(img_fp);
>>> +
>>> +                     ret = devinfo_to_topology(ad->device_entries, ad->num_of_devices, &src_topology);
>>> +                     if (ret) {
>>> +                             pr_err("Failed to convert amdgpu device information to topology\n");
>>> +                             ret = -EINVAL;
>>> +                             goto exit;
>>> +                     }
>>> +
>>> +                     ret = topology_parse(&dest_topology, "Local");
>>> +                     if (ret) {
>>> +                             pr_err("Failed to parse local system topology\n");
>>> +                             goto exit;
>>> +                     }
>>> +
>>> +                     ret = set_restore_gpu_maps(&src_topology, &dest_topology, &restore_maps);
>>> +                     if (ret) {
>>> +                             pr_err("Failed to map GPUs\n");
>>> +                             goto exit;
>>> +                     }
>>> +             }
>>> +
>>>                 target_gpu_id = maps_get_dest_gpu(&restore_maps, rd->gpu_id);
>>>                 if (!target_gpu_id) {
>>>                         fd = -ENODEV;
>>> diff --git a/plugins/amdgpu/amdgpu_plugin_drm.c b/plugins/amdgpu/amdgpu_plugin_drm.c
>>> index c1dfb2dd4..a4c650753 100644
>>> --- a/plugins/amdgpu/amdgpu_plugin_drm.c
>>> +++ b/plugins/amdgpu/amdgpu_plugin_drm.c
>>> @@ -467,11 +467,65 @@ int amdgpu_plugin_drm_dump_file(int fd, int id, struct stat *drm)
>>>                 return -ENODEV;
>>>         }
>>>
>>> -     /* Get the GPU_ID of the DRM device */
>>> -     rd->gpu_id = maps_get_dest_gpu(&checkpoint_maps, tp_node->gpu_id);
>>> -     if (!rd->gpu_id) {
>>> -             pr_err("Failed to find valid gpu_id for the device = %d\n", rd->gpu_id);
>>> -             return -ENODEV;
>>> +     if (kfd_dump_complete) {
>>> +             /* Get the GPU_ID of the DRM device */
>>> +             rd->gpu_id = maps_get_dest_gpu(&checkpoint_maps, tp_node->gpu_id);
>>> +             if (!rd->gpu_id) {
>>> +                     pr_err("Failed to find valid gpu_id for the device = %d\n", rd->gpu_id);
>>> +                     return -ENODEV;
>>> +             }
>>> +     } else {
>>> +             rd->gpu_id = tp_node->gpu_id;
>>> +
>>> +             if (!amdgpu_topology_dump_complete) {
>>> +                     AmdgpuDevinfo *ad = NULL;
>>> +                     unsigned char *buf;
>>> +
>>> +                     ad = xmalloc(sizeof(*ad));
>>> +                     amdgpu_devinfo__init(ad);
>>> +
>>> +                     ad->num_of_devices = src_topology.num_nodes;
>>> +
>>> +                     ad->device_entries = xmalloc(sizeof(KfdDeviceEntry *) * ad->num_of_devices);
>>> +                     if (!ad->device_entries) {
>>> +                             pr_err("Failed to allocate device_entries\n");
>>> +                             return -ENOMEM;
>>> +                     }
>>> +
>>> +                     for (int i = 0; i < ad->num_of_devices; i++) {
>>> +                             KfdDeviceEntry *entry = xzalloc(sizeof(*entry));
>>> +
>>> +                             if (!entry) {
>>> +                                     pr_err("Failed to allocate entry\n");
>>> +                                     return -ENOMEM;
>>> +                             }
>>> +
>>> +                             kfd_device_entry__init(entry);
>>> +
>>> +                             ad->device_entries[i] = entry;
>>> +                             ad->n_device_entries++;
>>> +                     }
>>> +
>>> +                     topology_to_devinfo(&src_topology, NULL, ad->device_entries);
>>> +
>>> +                     len = amdgpu_devinfo__get_packed_size(ad);
>>> +
>>> +                     buf = xmalloc(len);
>>> +                     if (!buf) {
>>> +                             pr_perror("Failed to allocate memory to store protobuf");
>>> +                             return -ENOMEM;
>>> +                     }
>>> +
>>> +                     amdgpu_devinfo__pack(ad, buf);
>>> +
>>> +                     ret = write_img_file(IMG_AMDGPU_TOPOLOGY_FILE, buf, len);
>>> +                     if (ret) {
>>> +                             pr_err("Failed to write image file %s\n", IMG_AMDGPU_TOPOLOGY_FILE);
>>> +                             return -EINVAL;
>>> +                     }
>>> +
>>> +                     amdgpu_topology_dump_complete = true;
>>> +             }
>>>         }
>>>
>>>         len = criu_render_node__get_packed_size(rd);
>>> diff --git a/plugins/amdgpu/amdgpu_plugin_util.h b/plugins/amdgpu/amdgpu_plugin_util.h
>>> index 69b98a31c..ccfe30b49 100644
>>> --- a/plugins/amdgpu/amdgpu_plugin_util.h
>>> +++ b/plugins/amdgpu/amdgpu_plugin_util.h
>>> @@ -2,6 +2,7 @@
>>>     #define __AMDGPU_PLUGIN_UTIL_H__
>>>
>>>     #include <libdrm/amdgpu.h>
>>> +#include "criu-amdgpu.pb-c.h"
>>>
>>>     #ifndef _GNU_SOURCE
>>>     #define _GNU_SOURCE 1
>>> @@ -59,6 +60,9 @@
>>>     /* Name of file having serialized data of DRM device buffer objects (BOs) */
>>>     #define IMG_DRM_PAGES_FILE "amdgpu-drm-pages-%d-%d-%04x.img"
>>>
>>> +/* Name of file containing the source device topology (generated only if IMG_KFD_FILE is not)*/
>>> +#define IMG_AMDGPU_TOPOLOGY_FILE "amdgpu-topology.img"
>>> +
>>>     /* Helper macros to Checkpoint and Restore a ROCm file */
>>>     #define HSAKMT_SHM_PATH                     "/dev/shm/hsakmt_shared_mem"
>>>     #define HSAKMT_SHM                          "/hsakmt_shared_mem"
>>> @@ -115,6 +119,9 @@ extern bool kfd_vram_size_check;
>>>     extern bool kfd_numa_check;
>>>     extern bool kfd_capability_check;
>>>
>>> +extern bool kfd_dump_complete;
>>> +extern bool amdgpu_topology_dump_complete;
>>> +
>>>     int read_fp(FILE *fp, void *buf, const size_t buf_len);
>>>     int write_fp(FILE *fp, const void *buf, const size_t buf_len);
>>>     int read_file(const char *file_path, void *buf, const size_t buf_len);
>>> @@ -142,4 +149,6 @@ int sdma_copy_bo(int shared_fd, uint64_t size, FILE *storage_fp,
>>>
>>>     int serve_out_dmabuf_fd(int handle, int fd);
>>>
>>> +int topology_to_devinfo(struct tp_system *sys, struct device_maps *maps, KfdDeviceEntry **deviceEntries);
>>> +
>>>     #endif              /* __AMDGPU_PLUGIN_UTIL_H__ */
>>> diff --git a/plugins/amdgpu/criu-amdgpu.proto b/plugins/amdgpu/criu-amdgpu.proto
>>> index 7682a8f21..6e44e22aa 100644
>>> --- a/plugins/amdgpu/criu-amdgpu.proto
>>> +++ b/plugins/amdgpu/criu-amdgpu.proto
>>> @@ -93,3 +93,8 @@ message criu_render_node {
>>>     message criu_dmabuf_node {
>>>         required uint32 gem_handle = 1;
>>>     }
>>> +
>>> +message amdgpu_devinfo {
>>> +     required uint32 num_of_devices = 1;
>>> +     repeated kfd_device_entry device_entries = 2;
>>> +}
>>> \ No newline at end of file
>>
>