Android ION記憶體分配

来源:https://www.cnblogs.com/willhua/archive/2018/11/27/10029280.html
-Advertisement-
Play Games

The Android ION memory allocator "英文原文" ION heaps ION設計的目標 為了避免記憶體碎片化,或者為一些有著特殊記憶體需求的硬體,比如GPUs、display controller以及camera等,在系統啟動的時候,會為他們預留一些memory pools ...


The Android ION memory allocator

英文原文

ION heaps

ION設計的目標

為了避免記憶體碎片化,或者為一些有著特殊記憶體需求的硬體,比如GPUs、display controller以及camera等,在系統啟動的時候,會為他們預留一些memory pools,這些memory pools就由ION來管理。通過ION就可以在硬體以及user space之間實現zero-copy的記憶體share。

ION的實現

ION通過ION heaps來展示presents它對應的memory pools。不同的Android硬體可能會要求不同的ION heaps實現,預設的ION驅動會提供如下三種不同的ION heaps實現:

  1. ION_HEAP_TYPE_SYSTEM: memory allocated via vmalloc_user()
  2. ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kzalloc
    . ION_HEAP_TYPE_CARVEOUT: carveout memory is physically contiguous and set aside at boot.
    開發者可以自己實現更多的ION heaps。比如NVIDIA就提交了一種ION_HEAP_TYPE_IOMMU的heap,這種heap帶有IOMMU功能。
    不管哪一種ION heaps實現,他們都必須實現如下介面:
   struct ion_heap_ops {
    int (*allocate) (struct ion_heap *heap,
             struct ion_buffer *buffer, unsigned long len,
             unsigned long align, unsigned long flags);
    void (*free) (struct ion_buffer *buffer);
    int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer,
             ion_phys_addr_t *addr, size_t *len);
    struct scatterlist *(*map_dma) (struct ion_heap *heap,
             struct ion_buffer *buffer);
    void (*unmap_dma) (struct ion_heap *heap, 
             struct ion_buffer *buffer);
    void * (*map_kernel) (struct ion_heap *heap, 
             struct ion_buffer *buffer);
    void (*unmap_kernel) (struct ion_heap *heap, 
             struct ion_buffer *buffer);
    int (*map_user) (struct ion_heap *heap, struct ion_buffer *buffer,
             struct vm_area_struct *vma);
   };

簡單來說,介面的各個函數功能如下:

  • allocate()free()分別用來從heap中分配或者釋放一個ion_buffer對象
  • 對於物理連續的記憶體,phys()用來得到ion_buffer對象的物理記憶體地址及其大小。如果heap沒有提供物理連續的記憶體,那麼它也可以不用提供這個介面。其中,ion_phys_addr_t將來會被定義在/include/linux/types.h中的phys_addr_t替代。
  • map_dma()unmap_dma()分別來用使ion_buffer對象為DMA(Direct Memory Access,直接記憶體存取。顧名思義,不占用cpu資源,從一個硬體存儲區域把一部分連續的數據複製到另一個硬體存儲區域)做好準備或者取消做好準備
  • map_kernel()unmap_kernel()分別用來把physical memory映射(map)到內核虛擬地址空間(kernel virtual address space)或者取消映射
  • map_user()用來把physical memory映射(map)到用戶記憶體空間(user space)。為什麼沒有對應的unmap_user()呢?因為,這個映射用一個file descriptor來表示,當這個file descriptor關閉的時候,這個映射關係就自動取消了。

在user space使用ION

使用場景

典型的,在用戶空間使用的設備訪問庫(user space device access libraries)一般使用ION來分配大塊連續的media buffers。比如,still camera library分配一個capture buffer來供camera device使用。當這個buffer填滿video data的時候,這個library就能把這塊buffer傳遞給kernel,然後讓JPEG硬編碼模塊來處理。

具體使用細節

在user space 的C/C++程式能夠能夠分配ION記憶體之前,它必須獲得訪問/dev/ion的許可權。通過調用open("/dev/ion", O_RDONLY)就可獲得一個以handle形式返回的file descriptor,這個file descriptor用來代表一個ION client。註意,雖然傳給open一個O_RDONLY參數,但是你仍然可對這塊memory進行寫操作。在一個user process中最多有一個client。當有了一個client之後,就可以開始分配ION記憶體。為了分配記憶體,client必須填滿下麵的ion_allocation_data結構,handle除外,因為它是output參數。其他三個參數分別指明記憶體的大小、對齊方式以及flags。flags是一個bit mask,用來說明可以從哪些heaps中分配想要的記憶體。其決定順序由系統啟動時,通過ion_device_add_heap()添加的heap順來決定。比如,ION_HEAP_TYPE_CARVEOUT是在ION_HEAP_TYPE_CONTIG之前被add的,那麼如果flags = ION_HEAP_TYPE_CONTIG | ION_HEAP_TYPE_CARVEOUT,那麼就是先嘗試分配ION_HEAP_TYPE_CARVEOUT類型的heap,如果不行,再嘗試分配ION_HEAP_TYPE_CONTIG類型的heap。()

   struct ion_allocation_data {
        size_t len;
        size_t align;
        unsigned int flags;
        struct ion_handle *handle;
   }

user space通過ioctl()系統介面來與ION交互。在client填充ion_allocatoin_data結構之後,就可以通過調用int ioctl(int client_fd, ION_IOC_ALLOC, struct ion_allocation_data *allocation_data)來allocate a buffer。這個調用介紹之後,分配的buffer會通過ion_allocatoin_datahandle來返回,但是CPU不可以訪問這個buffer。這個handle只可以通過調用int ioctl(int client_fd, ION_IOC_SHARE, struct ion_fd_data *fd_data);來獲得一個用來share的file descriptor。這裡,client_fd參數是前面通過open獲得的一個對應/dev/ion file descriptor,fd_data是如下的數據結構,其handle對應ion_allocation_data::handle,是input參數;fd則是output參數,可以用來share。
當一個user process中的client分享(share)了這個fd之後,在其他user process中(當然,也可share給創建這個fd的client自己),為了獲得這個shared buffer,先必須通過調用open("/dev/ion", O_RDONLY)獲得一個client。(註:ION通過線程的PID來track各個client, 尤其是process中的"group leader"線程的PID。在相同的process中重覆調用open("/dev/ion", O_RDONLY)只會獲得指向kernel同一個client的another file descriptor)。獲得client之後,然後再通過mmap()函數來把這個fd映射到address space of process(mmap函數參考1參考2)。如果要釋放這個fd對應的buffer,在調用mmap()的process中,先要通過munmap()來取消mmap()的效果。然後在之前share這個fd的client中,需要通過int ioctl(int client_fd, ION_IOC_FREE, struct ion_handle_data *handle_data);來關閉這個fd對應的file descriptor。其中,ion_handle_data表示前面通過ION_IOC_ALLOC命令獲得的handle,其定義如下:

     struct ion_handle_data {
         struct ion_handle *handle;
     }

這個ION_IOC_FREE命令會導致對應的handle的計數減1。當handle計數為0的時候,其指向的ion_handle對象就會被銷毀,並且相關的ION bookkeeping數據結構也會更新。

Demo

在這個Demo中,fd在同一個client中被share使用:來源

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

#include "/home/developer/kernel3.4/goldfish/include/linux/ion.h"

void main()
{
    struct ion_fd_data fd_data;
    struct ion_allocation_data ionAllocData;
    ionAllocData.len=0x1000;
    ionAllocData.align = 0;
    ionAllocData.flags = ION_HEAP_TYPE_SYSTEM;

    int fd=open("/dev/ion",O_RDWR);
    ioctl(fd,ION_IOC_ALLOC, &ionAllocData);
    fd_data.handle = ionAllocData.handle;
    ioctl(fd,ION_IOC_SHARE,&fd_data); 
    int *p = mmap(0,0x1000,PROT_READ|PROT_WRITE,MAP_SHARED,fd_data.fd,0);
    p[0]=99;
    perror("test");
    printf("hello all %d\n",p[0]);
}

在kernel中share ION buffer

在kernel中支持multiple clients,每一個使用ION功能的driver都可以在kernel中對應一個client。一個kernel driver通過調用struct ion_client *ion_client_create(struct ion_device *dev, unsigned int heap_mask, const char *debug_name)來獲得一個ION client handle(註意,前面在user space中通過open("/dev/ion", O_RDONLY)返回的client是int類型)。dev參數是一個和/dev/ion相關的global ION deviceheap_mask參數和之前提到的ion_allocation_dataflags成員一樣的含義。
當在user space中通過ION_IOC_SHARE命令得到一個buffer的file descriptor並把它傳遞給kernel之後,kernel driver通過調用struct ion_handle *ion_import_fd(struct ion_client *client, int fd_from_user);來把這個fd變成一個ion_handle對象,這個對象就是這個driver中對相應的buffer一個client-local reference。ion_import_fd方法會根據這個buffer的物理地址來查找:在本client中是否已經obtained一個對應此buffer的ion_handle,如果是的話,那麼就可以簡單的增加這個ion_handle的引用計數即可。
有些硬體只能通過physical addresses來操作physically-contiguous buffers,那麼,這些對應的drivers就需要通過調用int ion_phys(struct ion_client *client, struct ion_handle *handle, ion_phys_addr_t *addr, size_t *len)來把ion_handle轉變成一個physical buffer。當然,如果這個buffer不是physically contiguous,那麼這個調用就會失敗。
當處理一個來自client的調用時,ION會validates 輸入的 file descriptor, client and handle arguments。比如ION會確保 file descriptor是由ION_IOC_SHARE命令創建的;比如當ion_phys()調用時,ION會檢測這個buffer是否在這個client對應有訪問許可權list中,如果不是,那麼就會返回錯誤。這樣的驗證機制能夠減少可能的unwanted accesses以及疏忽的記憶體泄露。
ION通過debugfs提供可視化的debug,它通過在/sys/kernel/debug/ion下麵,使用stored files來記錄相應的heaps和clients,並使用symbolic names或者PIDs來標誌。

比較ION和DMABUF

本節部分翻譯。

  • IONDMABUF都是通過傳遞一個匿名file descriptor對象,給其他client一個基於引用計數的訪問許可權,從而達到分享記憶體的目的。
  • ION通過一個可分享和追蹤的方式從預留的memory pool中分配記憶體。
  • DMABUF更多的專註於buffer導入、導出以及同步的方式來實現在NON-ARM架構上的buffer的分享。
  • ION目前只支持Android kernel
  • ION所有的user-space program都可以通過/dev/ion介面來分配ION記憶體。但是在Android會通過驗證user和group IDs的方式來阻止對ION的非授權訪問。

參考

The Android ION memory allocator
Good PDF
Integrating the ION memory allocator
ION.C
ION.H
DEMO
CSDN


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Redis-事務 Redis 事務可以一次執行多個命令, 並且帶有以下兩個重要的保證: 事務的上個步驟: 事務相關指令: 執行事務出現的四種情況: redis事務的三個特性: watch監控 watch監控表示對需要操作的key添加一個樂觀鎖,防止另一個用戶進行修改,導致結果錯誤。 悲觀鎖 顧名思義 ...
  • 解決方法: 修改D:\app\‘admin’\product\11.2.0\dbhome_1\NETWORK\ADMIN\路徑下的listener.ora和tnsnames.ora文件配置中的host為當前修改後的主機名 HOST = Gnar(當前主機名) ...
  • 可以使用--ignore-table=dbname.tablename 忽略一張表 ...
  • ```sql CREATE TABLE IF NOT EXISTS ( INT NOT NULL AUTO_INCREMENT, VARCHAR(45) NOT NULL, VARCHAR(2048) NULL, VARCHAR(45) NOT NULL, TIMESTAMP NOT NULL DE ...
  • MySQL資料庫語法 資料庫管理系統(DBMS)的概述 1. 什麼是DBMS:數據的倉庫 方便查詢 可存儲的數據量大 保證數據的完整、一致 安全可靠 2. DBMS的發展:今天主流資料庫為關係型資料庫管理系統(RDBMS 使用表格存儲數據) 3. 常見DBMS:Orcale、MySQL、SQL Se ...
  • --上一月,上一年 select add_months(sysdate,-1) last_month,add_months(sysdate,-12) last_year from dual; --下一月,下一年 select add_months(sysdate,1) last_month,add_... ...
  • ---https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_8003.htm drop user geovin; drop user geovindu; create user geovindu identified by... ...
  • 一、簡介: ListView,列表視圖,直接繼承了AbsListView,是一個以垂直方式在項目中顯示View視圖的列表。ListView的數據項,來自一個繼承了ListAdapter介面的適配器。 二、新建一個包listview並新建ListViewActivity.java活動: 三、在Andr ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...