掌桥专利:专业的专利平台
掌桥专利
首页

虚拟地址分配方法及装置

文献发布时间:2024-04-18 20:00:50


虚拟地址分配方法及装置

技术领域

本公开涉及计算机技术领域,尤其涉及一种虚拟地址分配方法及装置。

背景技术

随着计算机技术和网络技术的发展,多进程协同作业来执行一项任务的机制越来越常见。例如GPU的远程调用场景中,客户端的应用程序运行后,一些运行任务可以通过数据传输和函数调用跑在远程GPU服务节点(服务端)上,此时在客户端上存在一个CPU进程,在服务端上存在一个GPU进程。

相关技术中,在GPU远程调用场景的程序运行期间,为CPU进程分配的内存存在于客户端,为GPU进程分配的显存(显卡内存)存在于服务端,二者并不在一个地址空间内,因此常常会出现在客户端分配的内存地址与在服务端分配的显存地址一样的情况,而当地址相同的内存和显存需要数据交互时,会由于无法分辨该地址指向的内存的位置而导致数据交互失败,影响了跨进程通信协作执行任务中数据交互的准确性。

需要说明的是,在上述背景技术部分公开的信息仅用于加强对本公开的背景的理解,因此可以包括不构成对本领域普通技术人员已知的现有技术的信息。

发明内容

本公开的目的在于提供一种虚拟地址分配方法及装置,以将多进程场景下的服务端分配的显存地址和客户端分配的CPU内存地址进行分隔,保证了跨进程通信协作执行任务中数据交互的准确性。

本公开的其他特性和优点将通过下面的详细描述变得显然,或部分地通过本公开的实践而习得。

根据本公开的一个方面,提供一种虚拟地址分配方法,该方法应用于远程调用过程,远程调用过程中存在具有调用关系的CPU进程和GPU进程;虚拟地址分配方法包括:在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块;使用CPU进程地址空间中除了预留内存块之外的剩余地址空间为CPU进程进行内存分配;使用GPU进程地址空间的预留内存块为GPU进程进行显存分配。

在本公开一个实施例中,在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块,包括:分别在CPU进程地址空间和GPU进程地址空间中请求占用第一地址范围的地址空间;若针对第一地址范围均占用成功,则将第一地址范围的地址空间确定为预留内存块。

在本公开一个实施例中,虚拟地址分配还包括:若针对第一地址范围未均占用成功,则分别在CPU进程地址空间和GPU进程地址空间中请求占用第二地址范围的地址空间;其中,第二地址范围与第一地址范围不同;若针对第二地址范围均占用成功,则将第二地址范围的地址空间确定为预留内存块。

在本公开一个实施例中,使用GPU进程地址空间的预留内存块为GPU进程进行显存分配,包括:当GPU进程中存在mmap函数被触发,判断触发mmap函数的指令是否为显存分配相关指令;若是,则从GPU进程地址空间的预留内存块中确定出子内存块;使用子内存块进行显存分配。

在本公开一个实施例中,从GPU进程地址空间的预留内存块中确定出子内存块,包括:获取mmap函数被触发时函数入参中的length参数值;根据length参数值从GPU进程地址空间的预留内存块中确定出目标子内存块。

在本公开一个实施例中,使用双向链表管理预留内存块;双向链表中的一个节点对应一个完整的内存块,通过节点记录与其对应的内存块的地址信息、长度信息以及分配状态,分配状态包括已被分配和未被分配;其中,根据length参数值从GPU进程地址空间的预留内存块中确定出子内存块,包括:判断双向链表中是否存在未被分配且长度信息等于length参数值的节点;若存在,将一个分配状态为未被分配且长度信息等于length参数值的节点所对应的内存块确定为子内存块,并将该节点的分配状态更新为已被分配;若不存在,从双向链表中确定出一个分配状态为未被分配且长度信息大于length参数值的节点作为待分裂节点,从待分裂节点所对应的内存块中划分出子内存块。

在本公开一个实施例中,从待分裂节点所对应的内存块中划分出子内存块,包括:将待分裂节点所对应的内存块划分为第一子内存块和第二子内存块,其中,第一子内存块的长度为length参数值;将第一子内存块确定为子内存块;在双向链表中删除待分裂节点,并添加与第一子内存块对应的节点以及与第二子内存块对应的节点;其中,与第一子内存块对应的节点的分配状态为已被分配,与第二子内存块对应的节点的分配状态为未被分配。

在本公开一个实施例中,使用子内存块进行显存分配,包括:将mmap函数被触发时函数入参中的创建映射addr参数值更新为子内存块的起始地址,得到更新后函数入参;基于更新后函数入参调用mmap函数进行内存映射,以实现显存分配。

在本公开一个实施例中,虚拟地址分配方法还包括:当GPU进程中存在munmap函数被触发,判断触发munmap函数的指令是否为显存释放相关指令;若是,则获取munmap函数被触发时函数入参中的解除映射addr参数值;将双向链表中地址信息与解除映射addr参数值匹配的节点确定为待解除映射节点;将待解除映射节点的分配状态更新为未被分配。

根据本公开的另一个方面,提供一种虚拟地址分配装置,该装置应用于远程调用过程,远程调用过程中存在具有调用关系的CPU进程和GPU进程;虚拟地址分配装置包括:预留内存块确定模块,用于在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块;内存分配模块,用于使用CPU进程地址空间中除了预留内存块之外的剩余地址空间为CPU进程进行内存分配;显存分配模块,用于使用GPU进程地址空间的预留内存块为GPU进程进行显存分配。

本公开的实施例所提供的虚拟地址分配方法,可以首先在CPU进程地址空间和GPU进程地址空间中协商出具有相同虚拟地址的预留内存块,然后在后续的应用执行中,在CPU进程中只分配出预留内存块之外的虚拟地址,以及在GPU进程中只分配出属于预留内存块的虚拟地址。可见,通过本方法可以将多进程场景下的服务端分配的显存地址和客户端分配的CPU内存地址进行分隔,确保为GPU进程分配的显存地址与为CPU进程分配的内存地址不会相同,从而可以避免在CPU进程与GPU进程的数据交互中由于内存地址相同而产生的数据交互无法执行的问题。

应当理解的是,以上的一般描述和后文的细节描述仅是示例性和解释性的,并不能限制本公开。

附图说明

此处的附图被并入说明书中并构成本说明书的一部分,示出了符合本公开的实施例,并与说明书一起用于解释本公开的原理。显而易见地,下面描述中的附图仅仅是本公开的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。

图1示出了可以应用本公开实施例的虚拟地址分配方法的示例性系统架构的示意图;

图2示出了本公开一个实施例的虚拟地址分配方法的流程图;

图3示出了本公开一个实施例的虚拟地址分配方法中协商确定预留内存块的流程图;

图4示出了本公开一个实施例的虚拟地址分配方法中使用预留内存块为GPU进程进行显存分配的流程图;

图5示出了本公开一个实施例的虚拟地址分配方法中确定出子内存块的流程图;

图6示出了本公开一个实施例的虚拟地址分配方法中为GPU进程进行内存分配和内存释放的流程图;

图7示出了本公开一个实施例的虚拟地址分配装置的框图;和

图8示出本公开实施例中一种虚拟地址分配计算机设备的结构框图。

具体实施方式

现在将参考附图更全面地描述示例实施方式。然而,示例实施方式能够以多种形式实施,且不应被理解为限于在此阐述的范例;相反,提供这些实施方式使得本公开将更加全面和完整,并将示例实施方式的构思全面地传达给本领域的技术人员。所描述的特征、结构或特性可以以任何合适的方式结合在一个或更多实施方式中。

此外,附图仅为本公开的示意性图解,并非一定是按比例绘制。图中相同的附图标记表示相同或类似的部分,因而将省略对它们的重复描述。附图中所示的一些方框图是功能实体,不一定必须与物理或逻辑上独立的实体相对应。可以采用软件形式来实现这些功能实体,或在一个或多个硬件模块或集成电路中实现这些功能实体,或在不同网络和/或处理器装置和/或微控制器装置中实现这些功能实体。

此外,术语“第一”、“第二”仅用于描述目的,而不能理解为指示或暗示相对重要性或者隐含指明所指示的技术特征的数量。由此,限定有“第一”、“第二”的特征可以明示或者隐含地包括一个或者更多个该特征。在本公开的描述中,“多个”的含义是至少两个,例如两个,三个等,除非另有明确具体的限定。

图1示出了可以应用本公开实施例的虚拟地址分配方法的示例性系统架构的示意图。

如图1所示,该系统架构可以包括服务器101、网络102和客户端103。网络102用以在客户端103和服务器101之间提供通信链路的介质。网络102可以包括各种连接类型,例如有线、无线通信链路或者光纤电缆等等。

在示例性实施例中,与服务器101进行数据传输的客户端103可以包括但不限于智能手机、台式计算机、平板电脑、笔记本电脑、智能音箱、数字助理、AR(Augmented Reality,增强现实)设备、VR(Virtual Reality,虚拟现实)设备、智能可穿戴设备等类型的电子设备。可选的,电子设备上运行的操作系统可以包括但不限于安卓系统、IOS系统、linux系统、windows系统等。

服务器101可以是独立的物理服务器,也可以是多个物理服务器构成的服务器集群或者分布式系统,还可以是提供图形处理服务、虚拟桌面服务、云服务、云数据库、云计算、云函数、云存储、网络服务、云通信、中间件服务、域名服务、安全服务、CDN(ContentDelivery Network,内容分发网络)、以及大数据和人工智能平台等基础云计算服务的云服务器。在一些实际应用中,服务器101也可以是网络平台的服务器,网络平台例如可以是交易平台、直播平台、社交平台或者音乐平台等,本公开实施例对此不作限定。其中,服务器可以是一台服务器,也可以是多台服务器形成的集群,本公开对于服务器的具体架构不做限定。

在示例性实施例中,客户端103上可以运行主应用程序,并与一个或多个服务器101建立远程调用关系,将主应用程序运行中生成的一些GPU任务通过服务器101来执行;具体地,客户端103可以负责在CPU上执行一系列计算,并处理主应用程序中的请求,诸如显存分配、数据拷贝等,对于显存分配涉及到GPU的操作,则可以发送到服务器101执行。该过程中,客户端103上的进程可以看作是CPU进程,服务器101被调用后产生的涉及到GPU的操作的进程可以看作是GPU进程。在一些实际应用中,主应用程序的涉及远程调用的执行中,可以包括一个CPU进程以及该CPU进程调用的一个或多个GPU进程。

在一些实际应用中,CPU进程和GPU进程也可以都存在于同一设备中,本公开对此不做限定。

在示例性实施例中,用于实现虚拟地址分配方法的过程可以是:在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块;使用CPU进程地址空间中除了预留内存块之外的剩余地址空间为CPU进程进行内存分配;使用GPU进程地址空间的预留内存块为GPU进程进行显存分配。

此外,需要说明的是,图1所示的仅仅是本公开提供的虚拟地址分配方法的一种应用环境。图1中的服务器101、网络102和客户端103的数目仅仅是示意性的,根据实际需要,可以具有任意数目的客户端、网络和服务器。

为了使本领域普通人员更好地理解本公开的技术方案,下面将结合附图及实施例对本公开示例实施例中的虚拟地址分配方法的各个步骤进行更详细的说明。

图2示出了本公开一个实施例的虚拟地址分配方法的流程图。该虚拟地址分配方法可以应用于远程调用过程,远程调用过程中存在具有调用关系的CPU进程和GPU进程;如图2所示,虚拟地址分配方法可以包括以下步骤。

步骤S201,在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块。

其中,CPU进程可以运行在客户端中,GPU进程可以运行在服务端中,CPU进程和GPU进程之间存在的调用关系可以是CPU进程调用GPU进程。可以在CPU进程刚开始调用GPU进程时,也即,在客户端和服务端开始传输数据之前,双方可以共同协商出一块在客户端和服务端中的进程地址空间内都空闲的地址段,作为上述预留内存块。协商后,在客户端和服务端这两个设备中,可以存在具有相同虚拟地址的预留内存块。

步骤S203,使用CPU进程地址空间中除了预留内存块之外的剩余地址空间为CPU进程进行内存分配。

本步骤中,对于客户端而言,在其地址空间内,后续CPU内存的分配可以只映射到剩余的地址空间中,也即,可以确保后续在客户端分配的内存地址不是预留内存块中的地址。

例如,在一些实际应用中,可以将客户端上CPU进程中产生的文本数据映射到客户端上预留内存块之外的剩余地址空间中。

步骤S205,使用GPU进程地址空间的预留内存块为GPU进程进行显存分配。

本步骤中,可以在服务端中强制使用预留内存块中的地址进行显存分配,以保证服务端上为GPU进程所分配的显存地址一定是预留内存块中的地址。例如,在一些实际应用中,可以将服务端上GPU进程中产生的图形处理数据强制映射到服务端上的预留内存块中。

结合前述步骤,这样可以确保为GPU进程分配的显存地址与为CPU进程分配的内存地址不会相同,从而避免在CPU进程与GPU进程的数据交互中由于内存地址相同而产生的数据交互无法执行的问题。

通过本公开的提供的虚拟地址分配方法,可以首先在CPU进程地址空间和GPU进程地址空间中协商出具有相同虚拟地址的预留内存块,然后在后续的应用执行中,在CPU进程中只分配出预留内存块之外的虚拟地址,以及在GPU进程中只分配出属于预留内存块的虚拟地址。可见,通过本方法可以将多进程场景下的服务端分配的显存地址和客户端分配的CPU内存地址进行分隔,确保为GPU进程分配的显存地址与为CPU进程分配的内存地址不会相同,从而可以避免在CPU进程与GPU进程的数据交互中由于内存地址相同而产生的数据交互无法执行,保证了跨进程通信协作执行任务中数据交互的准确性。

类似地,在一些实际应用中,对于多个服务端服务于单个客户端的场景,客户端可以通过和不同的服务端协商不同的地址段,从而将对应于多服务端的地址进行分隔。该场景中,多个服务器相当于有多张显卡,客户端上的主应用程序先使用哪张显卡,客户端就会和此显卡所在的服务端建立远程调用连接,然后进行协商。

在一些实施例中,还可以将分别存在于客户端和服务端的两个预留内存块进行内存映射。

其中,可以通过mmap函数实现映射。mmap(Memory Map)函数是一种提供内存映射文件的机制。它允许将一个文件或者其他类型的对象映射到进程的地址空间中,从而使得文件的内容可以直接在内存中访问,而不需要通过传统的读写文件的方式。

将位于客户端和服务端的两个预留内存块映射后,可以保证跨进程场景下多个进程(包括CPU进程和至少一个GPU进程)中CPU和GPU内存地址的统一性。

在一些实施例中,步骤S201可以包括:分别在CPU进程地址空间和GPU进程地址空间中请求占用第一地址范围的地址空间;若针对第一地址范围均占用成功,则将第一地址范围的地址空间确定为预留内存块。

其中,第一地址范围的地址空间可以是从CPU进程地址空间或GPU进程地址空间中的空闲的地址段中确定出的。第一地址范围的大小可以基于实际情况来确定,例如可以基于此次调用服务端GPU的预估计算量来确定。

可以使用mmap函数进行内存映射以实现请求占用,若mmap函数的返回值是映射区域(即第一地址范围)的起始地址,则意味着占用成功;若mmap函数的返回值是MAP_FAILED(-1),则意味着占用失败。

基于此,在一些实施例中,步骤S201可以进一步包括:若针对第一地址范围未均占用成功,则分别在CPU进程地址空间和GPU进程地址空间中请求占用第二地址范围的地址空间;其中,第二地址范围与第一地址范围不同;若针对第二地址范围均占用成功,则将第二地址范围的地址空间确定为预留内存块。

本实施例中,在确定无法共同针对第一地址范围的地址空间占用成功的情况下,可以切换地址段,针对第二地址范围的地址空间请求占用,直到都占用成功。其中,所谓切换地址段,可以是将CPU进程地址空间或GPU进程地址空间中的一块比较大的虚拟地址段分为多个连续的地址段,从前往后依次尝试。

其中,分别在CPU进程地址空间和GPU进程地址空间中请求占用地址空间的占用顺序可以不固定,可以先在CPU进程所在的客户端中请求占用,也可以先在GPU进程所在的服务端中请求占用。

在一些实际应用中,在调用关系为CPU进程调用GPU进程的情况下,可以先在客户端中请求占用,占用成功后再在服务端中请求占用。这是由于客户端是主应用程序执行的那一侧,用户的业务是不可控的,应用程序可能在调用服务端的GPU资源前已经占用了一些虚拟地址空间;而服务端是被调用的一方,是完全可控的,因此客户端空闲的地址段很大概率在服务端也是空闲,所以由客户端主导地址分配(即先在客户端中请求占用后在服务端中请求占用)的协商效率会更高。

在一些实施例中,步骤S201可以包括:在调用关系为CPU进程调用GPU进程的情况下,在CPU进程地址空间中请求对第一地址范围的地址空间进行第一映射;若第一映射成功,则在GPU进程地址空间中请求对第一地址范围的地址空间进行第二映射;若第二映射成功,则将第一地址范围的地址空间确定为空闲内存块。若第一映射或第二映射失败,则在CPU进程地址空间中请求对第二地址范围的地址空间进行第三映射;其中,第二地址范围与第一地址范围不同;若第三映射成功,则在GPU进程地址空间中请求对第二地址范围的地址空间进行第四映射;若第四映射成功,则将第二地址范围的地址空间确定为空闲地址空间。

图3示出了本公开一个实施例的虚拟地址分配方法中协商确定预留内存块的流程图。如图3所示,协商确定预留内存块的流程可以包括以下步骤。

步骤S301,在客户端中映射内存区域。

步骤S303,判断步骤S301中是否映射成功。若是,则执行步骤S305;若否,则执行步骤S311。

步骤S305,在服务端中映射相同内存区域。

步骤S307,判断步骤S305中是否映射成功。若是,则执行步骤S309;若否,则执行步骤S311。

步骤S309,确定协商成功,将上述内存区域确定为预留内存块。

步骤S311,切换地址段,更新内存区域的起始地址和结束地址。

图3实施例的其它内容可以参照上述其它实施例。

图4示出了本公开一个实施例的虚拟地址分配方法中使用预留内存块为GPU进程进行显存分配的流程图。如图4所示,在一些实施例中,步骤S205可以包括以下步骤。

步骤S401,当GPU进程中存在mmap函数被触发,判断触发mmap函数的指令是否为显存分配相关指令。

步骤S403,若是,则从GPU进程地址空间的预留内存块中确定出子内存块。

本步骤中,可以先截获mmap函数,再确定子内存块,以阻止mmap函数直接被执行。

在一些实施例中,步骤S403可以进一步包括:获取mmap函数被触发时函数入参中的length参数值;根据length参数值从GPU进程地址空间的预留内存块中确定出目标子内存块。

其中,length参数值指示了映射的长度,即所需分配的显存地址大小。可以从预留内存块中找出相同大小的子内存块进行地址分配。

以及,若触发mmap函数的指令不是显存分配相关指令,则意味着此次服务端中的内存分配与GPU数据无关,无需分配显存,那么则可以使用mmap函数被触发时原本的函数入参执行mmap函数。

步骤S405,使用子内存块进行显存分配。

在一些实施例中,步骤S405可以进一步包括:将mmap函数被触发时函数入参中的创建映射addr参数值更新为子内存块的起始地址,得到更新后函数入参;基于更新后函数入参调用mmap函数进行内存映射,以实现显存分配。

其中,在使用子内存块的起始地址替换mmap函数的addr参数值后,可以将mmap函数的参与映射标志位flags设置为MAP_FIXED,这样可以强制将映射区域放置在指定地址上,其中指定地址即子内存块的起始地址。然后再调用mmap函数的方法体以执行mmap,这样映射的显存地址就可以在预期的地址空间(即子内存块)内。

在一些实施例中,可以使用双向链表管理预留内存块;双向链表中的一个节点对应一个完整的内存块,可以通过节点记录与其对应的内存块的地址信息(如起始地址)、长度信息以及分配状态,分配状态包括已被分配和未被分配。

其中,双向链表中的节点被创建后分配状态的默认值为未被分配,当节点对应的内存块被分配出去,则可以将分配状态有未被分配更新为已被分配。当节点的分配状态为未被分配时,其对应的内存块不可被访问,只可被分配;当节点的分配状态为已被分配时,其对应的内存块可被访问,不可被再次分配。

基于此,步骤S403中的“根据length参数值从GPU进程地址空间的预留内存块中确定出子内存块”可以进一步包括:判断双向链表中是否存在未被分配且长度信息等于length参数值的节点;若存在,将一个分配状态为未被分配且长度信息等于length参数值的节点所对应的内存块确定为子内存块,并将该节点的分配状态更新为已被分配;若不存在,从双向链表中确定出一个分配状态为未被分配且长度信息大于length参数值的节点作为待分裂节点,从待分裂节点所对应的内存块中划分出子内存块。

其中,可以将待分裂节点所对应的内存块中的任一长度为length参数值的部分,作为子内存块划分出来。也可以从待分裂节点所对应的内存块的任一端开始(如从起始地址开始,或从结束地址开始),划分出一块长度为length参数值的部分作为子内存块,这样可以保证只将待分裂节点所对应的内存块划分为两个小内存块,可以尽可能地避免碎片存储空间的产生。

进一步地,在一些实施例中,从待分裂节点所对应的内存块中划分出子内存块,可以包括:将待分裂节点所对应的内存块划分为第一子内存块和第二子内存块,其中,第一子内存块的长度为length参数值;将第一子内存块确定为子内存块;在双向链表中删除待分裂节点,并添加与第一子内存块对应的节点以及与第二子内存块对应的节点;其中,与第一子内存块对应的节点的分配状态为已被分配,与第二子内存块对应的节点的分配状态为未被分配。

图5示出了本公开一个实施例的虚拟地址分配方法中确定出子内存块的流程图。如图5所示,确定出子内存块的流程可以包括以下步骤。

步骤S501,判断双向链表中是否存在未被分配且长度信息等于length参数值的节点。若存在,执行步骤S503;若不存在,执行步骤S505。

步骤S503,将一个分配状态为未被分配且长度信息等于length参数值的节点所对应的内存块确定为子内存块,并将该节点的分配状态更新为已被分配。

步骤S505,从双向链表中确定出一个分配状态为未被分配且长度信息大于length参数值的节点作为待分裂节点。

步骤S507,将待分裂节点所对应的内存块划分为第一子内存块和第二子内存块,其中,第一子内存块的长度为length参数值。

步骤S509,将第一子内存块确定为子内存块,并在双向链表中删除待分裂节点,添加与第一子内存块对应的节点以及与第二子内存块对应的节点;其中,与第一子内存块对应的节点的分配状态为已被分配,与第二子内存块对应的节点的分配状态为未被分配。

图5实施例的其它内容可以参照上述其它实施例。

在一些实施例中,虚拟地址分配方法还包括:当GPU进程中存在munmap函数被触发,判断触发munmap函数的指令是否为显存释放相关指令;若是,则获取munmap函数被触发时函数入参中的解除映射addr参数值;将双向链表中地址信息与解除映射addr参数值匹配的节点确定为待解除映射节点;将待解除映射节点的分配状态更新为未被分配。

其中,munmap(unmap memory)函数可以用于解除对内存映射区域的映射,释放相关的资源。在使用了mmap函数实现内存区域映射后,可以使用munmap函数释放被映射的区域。munmap函数中也携带有addr参数,munmap函数中的addr参数用于解除映射,指定了要解除映射的起始地址,该地址通常是mmap函数返回的映射区域的起始地址。

在本方案中,munmap函数中的addr参数会是按前述方式分配出的属于协商好的预留内存块的某一个子内存块的起始地址。因此,可以在双向链表中找到相应的节点,对其分配状态由已被分配更新为未被分配,使其将不再可访问。通过这种方式,可以达到munmap函数的解除映射效果(即munmap函数的addr参数指定的区域不再可访问),并且可以不真的释放这些属于预留内存块的子内存块,进而可以一直管理着这些协商好的地址,当再有显存地址映射需求时,可以再从预留内存块中找出来子内存块进行分配。

以及,若触发munmap函数的指令不是显存释放相关指令,则意味着此次服务端中的内存释放与GPU数据无关,需要释放的区域不属于预留内存块,那么则可以正常执行munmap函数进行内存区域释放。

在一些实施例中,双向链表中节点可以是按照其地址信息由低到高的顺序排列的,基于此,在将待解除映射节点的分配状态更新为未被分配之后,还可以包括:判断待解除节点的前一节点和后一节点中是否存在分配状态也是未被分配的节点;若存在,则可以对同为未被分配的节点进行合并,并更新链表。

其中,由于保证了相邻节点的地址一定是连续的,因此待解除节点与其相邻节点只要同为未被分配,就可以合并。

具体而言,可以删除待解除节点以及与其相邻的同为未被分配的节点,然后在原有位置上添加一个新节点,该新节点的分配状态为未被分配,新节点对应的内存块为删除的节点所对应的内存块所形成的更大的内存块。

在一些实际应用中,在远程调用结束时可以真正释放预留内存块,以及释放双向链表这些节点。

在一些实际应用中,可以设置模块有hook模块和allocate模块对本方法中GPU进程的显存分配和显存释放进行管理。

其中,hook模块可以用于截获系统函数、修改映射地址,allocate模块可以用于管理预留的地址空间(即预留内存块)。

在实际业务场景中,hook模块形态是动态库,在服务端需设置LD_PRELOAD指向该动态库,可以做到高优先加载该动态库,从而达到截获mmap和munmap函数的目的。

其中,LD_PRELOAD是linux操作系统提供的能力,LD_PRELOAD是一个环境变量,用于在运行可执行程序时预先加载指定的动态库,然后再加载目标程序所依赖的其他动态库,这样可以在目标程序执行之前能够注入一些自定义的代码或功能,以对目标程序的行为进行修改或扩展;实际业务场景中,各个模块的形态都是动态库,动态库会暴露各种符号(函数),程序执行会按照优先级进行动态库的加载然后调用库中的函数,而由于LD_PRELOAD指向的库是最高优先级,所以将会被第一个加载。 hook模块就是一个hook.so(动态库),其中暴露了mmap和munmap符号,而这两个函数真正的实现是在libc.so库中,当应用程序进行显存分配和释放时,会分别触发这两个函数,就会优先先调用到hook.so(因为hook.so加载优先级高于libc.so),以此实现高优先加载该动态库。

可以 通过hook模块提供的set_hook( )方法设置是否开启hook功能,其中参数为1是开启,参数为0是关闭,可以在分配和释放显存操作前后分别set_hook(1)和set_hook(0)以控制管理范围。

具体地,set_hook( )选择设置为1或者0取决于后续服务端执行的操作是分配显存还是分配普通内存,是显存分配的话需要设置为1,是普通内存则设置为0。

hook模块可以对显存分配触发的mmap进行监测,当监测到,则会进行地址重分配,本方案中,hook模块是否进行地址重分配(即替换mmap的首选参数addr)的依据是前序是否开启hook。

当监测到mmap被触发时则会将mmap的length参数值传入allocate模块;allocate模块会从预留内存块中分配出一个满足length参数值大小的内存块,并返回该内存块的起始地址;然后由hook模块将该起始地址替换为mmap的首选映射地址,并设置flags为MAP_FIXED,执行mmap,这样映射的显存地址就在预期的地址空间内。

hook模块还可以对显存释放触发的munmap进行监测,当监测到时,则会将munmap中解除映射的地址传入allocate模块,由allocate模块执行预编写的释放方法,进而可以不真正执行munmap,而又达到该地址对应的内存块不再可被访问的效果。

allocate模块可以使用一个双向链表来记录预留内存块的地址和长度,该模块提供了分配(allocate)方法函数和释放(free)方法函数:

分配(allocate)方法函数:推荐一个满足大小(即等于mmap函数入参中length参数值)的内存块,返回该内存块的地址。并将该内存块的标记置为non-free(已被分配),以及更新链表节点的指向。

其中,双向链表节点和内存块可以看作等同,一个节点就表示一个内存块,该节点记录内存块的地址、长度等信息及标记(即分配状态)等信息。所谓的确定子内存块,一种情况是当前allocate模块管理的内存块中存在满足分配大小要求的且标记为free,就直接将其确定为子内存块;另外一种情况是没有满足要求的内存块,则可以先找到一个比较大(大小大于分配要求的大小)且标记为free的内存块,从中切分出一个大小满足要求的内存块作为子内存块。

关于更新链表节点的指向,举例而言,假设原先只有一个内存块a,a对应的节点的前一个节点是空,后一个节点也是空;当需要确定子内存块时,需要切分a,可以将其切分为内存块b和内存块c,这样就不存在内存块a了,只有b和c,那么需要更新b对应的节点的后一个节点是c,c对应的节点的前一个节点是b,以此更新节点的指向。

释放(free)方法函数:释放指定内存块,将内存块标记置为free,同时检测前后相邻节点的状态,如果有为free的节点,则进行内存块合并,并更新链表节点的指向。

此处的更新链表节点的指向与分配(allocate)方法函数中的更新类似,举例而言,假设现在allocate模块管理了四个节点分别为a、b、c和d,a的后一个节点是b,b的后一个节点是c,b的前一个节点是a,…,以此类推,当合并了b、c两个节点成为节点e后,变成了a、e、d这三个节点,因此,需要更新a的后一个节点为e、e的前一个节点为a、e的后一个节点为d,以此更新节点的指向。

双向链表初始只有一个内存块,即预留内存块。当触发mmap后,allocate模块会分配一个子内存块,即调用allocate模块中的分配(allocate)方法,当没有能直接分配的小内存块时,可以将原先的一个大于length参数值的内存块切分为两个小的内存块。比如原先内存块范围是1-10,分配之后的两个内存块分别为1-x和x-10(x介于1-10)。这样,该双向链表中则会增加一个节点。此外,分配出去的小内存块等于已经被占用了,需要将其标记更新为non-free状态,而切分出来的未被使用的小内存块,其标记默认是free(未被分配)的。

上述过程是单个服务端的管理显存地址的方式;对于多服务端场景,客户端可以先跟每个服务端协商不同的地址空间,然后由各个服务端的allocate模块维护各自协商后的地址空间。

图6示出了本公开一个实施例的虚拟地址分配方法中为GPU进程进行内存分配和内存释放的流程图。如图6所示,GPU进程可以运行在服务端上,为GPU进程进行内存分配和内存释放的过程可以包括以下步骤。

步骤S601,设置LD_PRELOAD=hook.so。

步骤S603,设置set_hook( )的参数值。

步骤S605,服务端对显存/内存操作。

步骤S607,hook模块监测到触发mmap。

步骤S609,hook模块截获mmap。

步骤S611,判断是否开启hook。若是,则执行步骤S613,若否,则执行步骤S617。

步骤S613,allocate模块执行分配(allocate)方法函数,从预留内存块中确定出子内存块。

步骤S615,hook模块使用子内存块的起始地址替换mmap函数入参中的addr参数值。

步骤S617,调用mmap函数的方法体,执行内存映射。

步骤S619,将set_hook( )的参数值置0。

步骤S621,hook模块监测到触发munmap。

步骤S623,hook模块截获munmap。

步骤S625,判断是否开启hook。若是,则执行步骤S627,若否,则执行步骤S629。

步骤S627,allocate模块根据munmap函数入参中的addr参数值执行释放(free)方法函数。

步骤S629,调用munmap函数的方法体,执行内存映射。

图6实施例的其它内容可以参照上述其它实施例。

通过上述虚拟地址分配的方式,不仅可以管理显存地址,保证了跨进程场景下多个进程CPU和GPU内存地址的统一性。并且 用法灵活,可以按需管理,可以通过set_hook管理特定程序分配显存的地址。还容 扩展,其中hook模块也可用于截获其他系统函数,注入一些其他的自定义的功能。

需要注意的是,上述附图仅是根据本发明示例性实施例的方法所包括的处理的示意性说明,而不是限制目的。易于理解,上述附图所示的处理并不表明或限制这些处理的时间顺序。另外,也易于理解,这些处理可以是例如在多个模块中同步或异步执行的。

图7示出了本公开一个实施例的虚拟地址分配装置700的框图;该装置可以应用于远程调用过程,远程调用过程中存在具有调用关系的CPU进程和GPU进程;如图7所示,虚拟地址分配装置700包括:预留内存块确定模块701,用于在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块;内存分配模块702,用于使用CPU进程地址空间中除了预留内存块之外的剩余地址空间为CPU进程进行内存分配;显存分配模块703,用于使用GPU进程地址空间的预留内存块为GPU进程进行显存分配。

通过本公开的提供的虚拟地址分配装置,可以首先在CPU进程地址空间和GPU进程地址空间中协商出具有相同虚拟地址的预留内存块,然后在后续的应用执行中,在CPU进程中只分配出预留内存块之外的虚拟地址,以及在GPU进程中只分配出属于预留内存块的虚拟地址。可见,通过本方法可以将多进程场景下的服务端分配的显存地址和客户端分配的CPU内存地址进行分隔,确保为GPU进程分配的显存地址与为CPU进程分配的内存地址不会相同,从而可以避免在CPU进程与GPU进程的数据交互中由于内存地址相同而产生的数据交互无法执行,保证了跨进程通信协作执行任务中数据交互的准确性。

在一些实施例中,预留内存块确定模块701在CPU进程的CPU进程地址空间和GPU进程的GPU进程地址空间中,确定出虚拟地址相同的预留内存块,包括:分别在CPU进程地址空间和GPU进程地址空间中请求占用第一地址范围的地址空间;若针对第一地址范围均占用成功,则将第一地址范围的地址空间确定为预留内存块。

在一些实施例中,预留内存块确定模块701还用于:若针对第一地址范围未均占用成功,则分别在CPU进程地址空间和GPU进程地址空间中请求占用第二地址范围的地址空间;其中,第二地址范围与第一地址范围不同;若针对第二地址范围均占用成功,则将第二地址范围的地址空间确定为预留内存块。

在一些实施例中,显存分配模块703使用GPU进程地址空间的预留内存块为GPU进程进行显存分配,包括:当GPU进程中存在mmap函数被触发,判断触发mmap函数的指令是否为显存分配相关指令;若是,则从GPU进程地址空间的预留内存块中确定出子内存块;使用子内存块进行显存分配。

在一些实施例中,显存分配模块703从GPU进程地址空间的预留内存块中确定出子内存块,包括:获取mmap函数被触发时函数入参中的length参数值;根据length参数值从GPU进程地址空间的预留内存块中确定出目标子内存块。

在一些实施例中,使用双向链表管理预留内存块;双向链表中的一个节点对应一个完整的内存块,通过节点记录与其对应的内存块的地址信息、长度信息以及分配状态,分配状态包括已被分配和未被分配;其中,显存分配模块703根据length参数值从GPU进程地址空间的预留内存块中确定出子内存块,包括:判断双向链表中是否存在未被分配且长度信息等于length参数值的节点;若存在,将一个分配状态为未被分配且长度信息等于length参数值的节点所对应的内存块确定为子内存块,并将该节点的分配状态更新为已被分配;若不存在,从双向链表中确定出一个分配状态为未被分配且长度信息大于length参数值的节点作为待分裂节点,从待分裂节点所对应的内存块中划分出子内存块。

在一些实施例中,显存分配模块703从待分裂节点所对应的内存块中划分出子内存块,包括:将待分裂节点所对应的内存块划分为第一子内存块和第二子内存块,其中,第一子内存块的长度为length参数值;将第一子内存块确定为子内存块;在双向链表中删除待分裂节点,并添加与第一子内存块对应的节点以及与第二子内存块对应的节点;其中,与第一子内存块对应的节点的分配状态为已被分配,与第二子内存块对应的节点的分配状态为未被分配。

在一些实施例中,显存分配模块703使用子内存块进行显存分配,包括:将mmap函数被触发时函数入参中的创建映射addr参数值更新为子内存块的起始地址,得到更新后函数入参;基于更新后函数入参调用mmap函数进行内存映射,以实现显存分配。

在一些实施例中,虚拟地址分配装置还包括显存释放模块704:当GPU进程中存在munmap函数被触发,判断触发munmap函数的指令是否为显存释放相关指令;若是,则获取munmap函数被触发时函数入参中的解除映射addr参数值;将双向链表中地址信息与解除映射addr参数值匹配的节点确定为待解除映射节点;将待解除映射节点的分配状态更新为未被分配。

图7实施例的其它内容可以参照上述其它实施例。

所属技术领域的技术人员能够理解,本发明的各个方面可以实现为系统、方法或程序产品。因此,本发明的各个方面可以具体实现为以下形式,即:完全的硬件实施方式、完全的软件实施方式(包括固件、微代码等),或硬件和软件方面结合的实施方式,这里可以统称为“电路”、“模块”或“系统”。

图8示出本公开实施例中一种虚拟地址分配计算机设备的结构框图。需要说明的是,图示出的电子设备仅仅是一个示例,不应对本发明实施例的功能和使用范围带来任何限制。

下面参照图8来描述根据本发明的这种实施方式的电子设备800。图8显示的电子设备800仅仅是一个示例,不应对本发明实施例的功能和使用范围带来任何限制。

如图8所示,电子设备800以通用计算设备的形式表现。电子设备800的组件可以包括但不限于:上述至少一个处理单元810、上述至少一个存储单元820、连接不同系统组件(包括存储单元820和处理单元810)的总线830。

其中,所述存储单元存储有程序代码,所述程序代码可以被所述处理单元810执行,使得所述处理单元810执行本说明书上述“示例性方法”部分中描述的根据本发明各种示例性实施方式的步骤。例如,所述处理单元810可以执行如图2中所示的方法。

存储单元820可以包括易失性存储单元形式的可读介质,例如随机存取存储单元(RAM)8201和/或高速缓存存储单元8202,还可以进一步包括只读存储单元(ROM)8203。

存储单元820还可以包括具有一组(至少一个)程序模块8205的程序/实用工具8204,这样的程序模块8205包括但不限于:操作系统、一个或者多个应用程序、其它程序模块以及程序数据,这些示例中的每一个或某种组合中可能包括网络环境的实现。

总线830可以为表示几类总线结构中的一种或多种,包括存储单元总线或者存储单元控制器、外围总线、图形加速端口、处理单元或者使用多种总线结构中的任意总线结构的局域总线。

电子设备800也可以与一个或多个外部设备900(例如键盘、指向设备、蓝牙设备等)通信,还可与一个或者多个使得用户能与该电子设备800交互的设备通信,和/或与使得该电子设备800能与一个或多个其它计算设备进行通信的任何设备(例如路由器、调制解调器等等)通信。这种通信可以通过输入/输出(I/O)接口850进行。并且,电子设备800还可以通过网络适配器860与一个或者多个网络(例如局域网(LAN),广域网(WAN)和/或公共网络,例如因特网)通信。如图所示,网络适配器860通过总线830与电子设备800的其它模块通信。应当明白,尽管图中未示出,可以结合电子设备800使用其它硬件和/或软件模块,包括但不限于:微代码、设备驱动器、冗余处理单元、外部磁盘驱动阵列、RAID系统、磁带驱动器以及数据备份存储系统等。

在本公开的示例性实施例中,还提供了一种计算机可读存储介质,其上存储有能够实现本说明书上述方法的程序产品。在一些可能的实施方式中,本发明的各个方面还可以实现为一种程序产品的形式,其包括程序代码,当所述程序产品在终端设备上运行时,所述程序代码用于使所述终端设备执行本说明书上述“示例性方法”部分中描述的根据本发明各种示例性实施方式的步骤。

根据本发明实施方式的用于实现上述方法的程序产品,其可以采用便携式紧凑盘只读存储器(CD-ROM)并包括程序代码,并可以在终端设备,例如个人电脑上运行。然而,本发明的程序产品不限于此,在本文件中,可读存储介质可以是任何包含或存储程序的有形介质,该程序可以被指令执行系统、装置或者器件使用或者与其结合使用。

所述程序产品可以采用一个或多个可读介质的任意组合。可读介质可以是可读信号介质或者可读存储介质。可读存储介质例如可以为但不限于电、磁、光、电磁、红外线、或半导体的系统、装置或器件,或者任意以上的组合。可读存储介质的更具体的例子(非穷举的列表)包括:具有一个或多个导线的电连接、便携式盘、硬盘、随机存取存储器(RAM)、只读存储器(ROM)、可擦式可编程只读存储器(EPROM或闪存)、光纤、便携式紧凑盘只读存储器(CD-ROM)、光存储器件、磁存储器件、或者上述的任意合适的组合。

计算机可读信号介质可以包括在基带中或者作为载波一部分传播的数据信号,其中承载了可读程序代码。这种传播的数据信号可以采用多种形式,包括但不限于电磁信号、光信号或上述的任意合适的组合。可读信号介质还可以是可读存储介质以外的任何可读介质,该可读介质可以发送、传播或者传输用于由指令执行系统、装置或者器件使用或者与其结合使用的程序。

可读介质上包含的程序代码可以用任何适当的介质传输,包括但不限于无线、有线、光缆、RF等等,或者上述的任意合适的组合。

可以以一种或多种程序设计语言的任意组合来编写用于执行本发明操作的程序代码,所述程序设计语言包括面向对象的程序设计语言—诸如Java、C++等,还包括常规的过程式程序设计语言—诸如“C”语言或类似的程序设计语言。程序代码可以完全地在用户计算设备上执行、部分地在用户设备上执行、作为一个独立的软件包执行、部分在用户计算设备上部分在远程计算设备上执行、或者完全在远程计算设备或服务器上执行。在涉及远程计算设备的情形中,远程计算设备可以通过任意种类的网络,包括局域网(LAN)或广域网(WAN),连接到用户计算设备,或者,可以连接到外部计算设备(例如利用因特网服务提供商来通过因特网连接)。

应当注意,尽管在上文详细描述中提及了用于动作执行的设备的若干模块或者单元,但是这种划分并非强制性的。实际上,根据本公开的实施方式,上文描述的两个或更多模块或者单元的特征和功能可以在一个模块或者单元中具体化。反之,上文描述的一个模块或者单元的特征和功能可以进一步划分为由多个模块或者单元来具体化。

此外,尽管在附图中以特定顺序描述了本公开中方法的各个步骤,但是,这并非要求或者暗示必须按照该特定顺序来执行这些步骤,或是必须执行全部所示的步骤才能实现期望的结果。附加的或备选的,可以省略某些步骤,将多个步骤合并为一个步骤执行,以及/或者将一个步骤分解为多个步骤执行等。

通过以上的实施方式的描述,本领域的技术人员易于理解,这里描述的示例实施方式可以通过软件实现,也可以通过软件结合必要的硬件的方式来实现。因此,根据本公开实施方式的技术方案可以以软件产品的形式体现出来,该软件产品可以存储在一个非易失性存储介质(可以是CD-ROM,U盘,移动硬盘等)中或网络上,包括若干指令以使得一台计算设备(可以是个人计算机、服务器、移动终端、或者网络设备等)执行根据本公开实施方式的方法。

根据本公开的一个方面,提供了一种计算机程序产品或计算机程序,该计算机程序产品或计算机程序包括计算机指令,该计算机指令存储在计算机可读存储介质中。计算机设备的处理器从计算机可读存储介质读取该计算机指令,处理器执行该计算机指令,使得该计算机设备执行上述实施例的各种可选实现方式中提供的方法。

本领域技术人员在考虑说明书及实践这里公开的发明后,将容易想到本公开的其它实施方案。本申请旨在涵盖本公开的任何变型、用途或者适应性变化,这些变型、用途或者适应性变化遵循本公开的一般性原理并包括本公开未公开的本技术领域中的公知常识或惯用技术手段。说明书和实施例仅被视为示例性的,本公开的真正范围和精神由所附的权利要求指出。

技术分类

06120116541691