存視圖解析與實(shí)戰(zhàn))
數(shù)據(jù)分析數(shù)據(jù)工程機(jī)器學(xué)習(xí)【免費(fèi)下載鏈接】cudfcuDF - GPU DataFrame Library項(xiàng)目地址https://gitcode.com/gh_mirrors/cu/cudf點(diǎn)擊查看免費(fèi)下載導(dǎo)讀gpumemoryview是 cuDF 的 Cython 層pylibcudf中提供的一個(gè)輕量級(jí)設(shè)備內(nèi)存視圖類它模仿 Python 內(nèi)置memoryview的語義為任何實(shí)現(xiàn)了 CUDA Array InterfaceCAI的設(shè)備對(duì)象提供統(tǒng)一的只讀字節(jié)視圖能力。本文以 gpumemoryview.rst 中掛載的pylibcudf.gpumemoryview模塊文檔為主體結(jié)合其 Cython 實(shí)現(xiàn) gpumemoryview.pyx、類型聲明文件 gpumemoryview.pyi、聲明文件 gpumemoryview.pxd 以及測(cè)試 test_gpumemoryview.py深入講解其設(shè)計(jì)動(dòng)機(jī)、完整 API、內(nèi)部實(shí)現(xiàn)原理以及它在 Column、contiguous_split、transform 等模塊中的真實(shí)調(diào)用場(chǎng)景幫助讀者在 pylibcudf 生態(tài)中正確使用與二次開發(fā)。1. gpumemoryview 是什么GPU 側(cè)的 memoryview在 NumPy / Python 生態(tài)中memoryview允許在不復(fù)制底層緩沖區(qū)的前提下以統(tǒng)一字節(jié)視角訪問主機(jī)內(nèi)存。cuDF 的設(shè)備端數(shù)據(jù)同樣面臨不復(fù)制數(shù)據(jù)、只傳遞指針與大小信息的需求gpumemoryview正是為此而生Minimal representation of a memory buffer. This class aspires to be a GPU equivalent of memoryview for any objects exposing a CUDA Array Interface.從 gpumemoryview.pyx 的類文檔可以看出它的目標(biāo)定位十分明確最小化只保留指針 字節(jié)數(shù) CUDA Array Interface 描述這三類核心信息不做完整memoryview的切片、格式轉(zhuǎn)換等復(fù)雜功能零拷貝構(gòu)造時(shí)僅登記底層對(duì)象的 CAI 描述不搬移任何設(shè)備數(shù)據(jù)演進(jìn)式源碼中明確標(biāo)注了TODO: dlpack support、TODO: Need to respect readonly、TODO: Need to synchronize on stream if present in cai等未完成項(xiàng)說明它是一塊為后續(xù)功能預(yù)留的擴(kuò)展基座。從設(shè)計(jì)上看gpumemoryview在 pylibcudf 中承擔(dān)設(shè)備內(nèi)存的公共輕量句柄角色Column的數(shù)據(jù)緩沖區(qū)、null mask、contiguous_split序列化后的 GPU 數(shù)據(jù)、transform產(chǎn)生的位掩碼等都以gpumemoryview的形式對(duì)外暴露避免每個(gè)模塊各自定義一套指針 長(zhǎng)度的膠水對(duì)象。2. 構(gòu)造規(guī)則任何實(shí)現(xiàn) CUDA Array Interface 的對(duì)象都可以入?yún)?.1 構(gòu)造簽名與校驗(yàn)邏輯def __init__(self, obj: Any): ...構(gòu)造函數(shù)的唯一參數(shù)是obj。從實(shí)現(xiàn)源碼 gpumemoryview.pyx 可以看到嚴(yán)格的校驗(yàn)與推導(dǎo)邏輯強(qiáng)制要求 CAI構(gòu)造時(shí)直接訪問obj.__cuda_array_interface__如果對(duì)象沒有該屬性拋出ValueError錯(cuò)誤信息為gpumemoryview must be constructed from an object supporting the CUDA array interface登記描述把obj與obj.__cuda_array_interface__即cai原樣保存取出數(shù)據(jù)指針self.ptr cai[data][0]即 CAIdata元組中的指針字段推導(dǎo)元素大小從cai[typestr]的第二個(gè)字符起跳過首字節(jié)的字節(jié)序標(biāo)記|//提取 dtype 描述再通過_datatype_from_dtype_desc映射為 pylibcudf 的type_id最后用size_of()得到字節(jié)大小計(jì)算總字節(jié)數(shù)nbytes reduce(operator.mul, cai[shape]) * itemsize。2.2 支持的 dtype 映射表_datatype_from_dtype_descgpumemoryview.pyx維護(hù)了一張 CAI typestr 到 pylibcudfTypeId的映射表這是理解nbytes推導(dǎo)的關(guān)鍵CAI typestr去字節(jié)序后pylibcudf TypeIdu1/u2/u4/u8UINT8/UINT16/UINT32/UINT64i1/i2/i4/i8INT8/INT16/INT32/INT64f4/f8FLOAT32/FLOAT64b1BOOL8M8[s]/M8[ms]/M8[us]/M8[ns]TIMESTAMP_SECONDS/TIMESTAMP_MILLISECONDS/TIMESTAMP_MICROSECONDS/TIMESTAMP_NANOSECONDSm8[s]/m8[ms]/m8[us]/m8[ns]DURATION_SECONDS/DURATION_MILLISECONDS/DURATION_MICROSECONDS/DURATION_NANOSECONDS不在映射表中的 dtype 會(huì)拋出ValueError(fUnsupported dtype: {desc})。由于該函數(shù)被functools.cache裝飾gpumemoryview.pyx相同 dtype 描述只會(huì)解析一次在熱路徑上避免重復(fù)開銷。3. 完整 API 面屬性與方法結(jié)合 gpumemoryview.pyi 的公開類型簽名gpumemoryview對(duì)外暴露的 API 如下3.1 實(shí)例屬性屬性類型說明ptrintuintptr_t設(shè)備內(nèi)存起始地址CAIdata[0]objAny構(gòu)造時(shí)傳入的原始對(duì)象用于持有引用、保證生命周期caidict[str, Any]原始對(duì)象的 CUDA Array Interface 描述如{data: (ptr, readonly), shape: (...), strides: ..., typestr: ..., version: 3}nbytesintuint64_t緩沖區(qū)總字節(jié)數(shù)sizeintnbytes的別名用于滿足 Span 協(xié)議見第 5 節(jié)底層存儲(chǔ)對(duì)應(yīng) gpumemoryview.pxdptr、nbytes是readonly的 C 屬性u(píng)intptr_t/uint64_tobj與cai是readonlyPython 對(duì)象并定義了__weakref__以支持弱引用。3.2 方法def __len__(self) - int: ... def byte_slice(self, s: slice) - gpumemoryview: ... property def __cuda_array_interface__(self) - Mapping[str, Any]: ...__len__返回cai[shape][0]即首維長(zhǎng)度__cuda_array_interface__直接透?jìng)鱯elf.cai因此gpumemoryview自身也可以作為 CAI 對(duì)象被其他庫(kù)Numba、CuPy、rmm 等消費(fèi)byte_slice(s)以字節(jié)為單位返回子視圖這是當(dāng)前最核心的實(shí)用方法詳見第 4 節(jié)。4. byte_slice字節(jié)級(jí)子視圖與生命周期管理byte_slice是gpumemoryview提供的切片能力其實(shí)現(xiàn)細(xì)節(jié)gpumemoryview.pyx值得逐條拆解def byte_slice(self, s: slice) - gpumemoryview: if not isinstance(s, slice): raise TypeError(fbyte_slice requires a slice, not {type(s).__name__}) start, stop, step s.indices(self.nbytes) if step ! 1: raise ValueError(byte_slice only supports step1 slices) length stop - start if length 0: return _slice(self, self.ptr start, 0) return _slice(self, self.ptr start, length)4.1 行為規(guī)則入?yún)⑿r?yàn)傳入非slice對(duì)象拋出TypeError切片步長(zhǎng)不為1時(shí)拋出ValueError越界寬容slice.indices(self.nbytes)會(huì)把負(fù)索引、越界索引標(biāo)準(zhǔn)化長(zhǎng)度 0空區(qū)間或反向區(qū)間時(shí)返回零長(zhǎng)度視圖而不是拋異常返回類型固定子視圖始終是|u1的原始字節(jié)視圖無論父視圖的 dtype 是什么——這是與 Pythonmemoryview的重要差異它只做字節(jié)區(qū)間切分不做類型維度上的切分。4.2 內(nèi)部_slice實(shí)現(xiàn)cdef gpumemoryview _slice(gpumemoryview parent, uintptr_t ptr, uint64_t nbytes): cdef gpumemoryview v gpumemoryview.__new__(gpumemoryview) v.ptr ptr v.nbytes nbytes v.obj parent v.cai {data: (ptr, parent.cai[data][1]), shape: (nbytes,), typestr: |u1, version: 3} return v關(guān)鍵點(diǎn)在于v.obj parent子視圖持有對(duì)父視圖的強(qiáng)引用父視圖又持有對(duì)原始o(jì)bj的強(qiáng)引用從而形成引用鏈保證切片期間底層設(shè)備緩沖區(qū)不會(huì)被釋放。測(cè)試 test_gpumemoryview.py 專門驗(yàn)證了這一行為刪除原Column與父gpumemoryview后只要子視圖s仍存活父視圖就不會(huì)被 GC 回收刪除s后父視圖才被回收。4.3 測(cè)試覆蓋測(cè)試 test_slice 用slice(1, 3)、slice(None, 2)、slice(3, None)、slice(2, 2)、slice(0, 10000)五類切片驗(yàn)證了byte_slice與 NumPy 字節(jié)視圖逐字節(jié)一致test_slice_fails 則驗(yàn)證了TypeError非 slice與ValueErrorstep2兩條異常路徑。5. Span 協(xié)議零開銷的指針 大小抽象gpumemoryview不僅是 CAI 對(duì)象還實(shí)現(xiàn)了 pylibcudf 的Span 協(xié)議。協(xié)議定義在 span.py一個(gè)滿足Span的對(duì)象只需提供ptr: int內(nèi)存地址與size: int字節(jié)數(shù)兩個(gè)屬性gpumemoryview通過size屬性別名nbytes天然滿足該協(xié)議。Span 協(xié)議的意義在于pylibcudf 的Column構(gòu)造接受任何滿足 Span 協(xié)議的對(duì)象column.pyx而不局限于gpumemoryview本身。測(cè)試 test_span.py 明確斷言gmv plc.gpumemoryview(buf) assert is_span(gmv) assert gmv.ptr ! 0在 Cython 熱路徑上ptr/size可以直接作為 C 屬性訪問無 Python 對(duì)象開銷這正是注釋中所說的zero-overhead access in Cython code。6. 在 pylibcudf 中的實(shí)際調(diào)用場(chǎng)景gpumemoryview并非孤立組件它深度嵌入 pylibcudf 的數(shù)據(jù)流中。以下是倉(cāng)庫(kù)源碼中可驗(yàn)證的典型使用點(diǎn)6.1 Column 的 data 與 null_mask 訪問Column的數(shù)據(jù)緩沖區(qū)與 null 位掩碼都以gpumemoryview形式暴露。Column.data()返回的正是包裝底層rmm.DeviceBuffer的gpumemoryview這在測(cè)試中反復(fù)出現(xiàn)col plc.Column.from_array(np.arange(10, dtypeu1)) gv col.data() # gpumemoryview gv.byte_slice(slice(2, 5))底層機(jī)制column.pyx_OwnerWithCAI與_OwnerMaskWithCAI兩個(gè)輔助類把column_view的head指針 /null_mask指針包裝成 CAI 描述typestr統(tǒng)一為|u1的字節(jié)流shape按元素大小或位掩碼分配字節(jié)數(shù)計(jì)算隨后這些 CAI 對(duì)象被傳入gpumemoryview(...)構(gòu)造。device_buffer_size()的實(shí)現(xiàn)column.pyx也正是通過累加self.data().nbytes、self.null_mask().nbytes與各子列的字節(jié)數(shù)來統(tǒng)計(jì)設(shè)備內(nèi)存占用。6.2 contiguous_split 序列化數(shù)據(jù)的釋放contiguous_split的PackedColumns.release()contiguous_split.pyx返回tuple[memoryview, gpumemoryview]序列化的元數(shù)據(jù)作為主機(jī)memoryview序列化的 GPU 數(shù)據(jù)作為設(shè)備gpumemoryview包裝一個(gè)rmm.DeviceBuffer。調(diào)用后所有權(quán)轉(zhuǎn)移給調(diào)用方PackedColumns自身變?yōu)榭铡?.3 transform 模塊的位掩碼產(chǎn)出transform模塊的nans_to_nulls與bools_to_masktransform.pyx都返回tuple[gpumemoryview, int]——第一個(gè)元素是包裝新 null 掩碼 / 位掩碼的gpumemoryview第二個(gè)元素是新的 null 計(jì)數(shù)。這類算法結(jié)果直接以設(shè)備視圖形式返回的模式避免了不必要的主機(jī)往返拷貝。6.4 IO 與列工廠parquet_io_utils.pyx 用gpumemoryview(owner)持有 Parquet 元數(shù)據(jù)解碼所依賴的設(shè)備緩沖Column.from_buffercolumn.pyx與from_array等工廠方法內(nèi)部均通過gpumemoryview(buff)把設(shè)備緩沖轉(zhuǎn)成列數(shù)據(jù)視圖。7. 設(shè)計(jì)邊界與已知限制從源碼注釋可以明確看到當(dāng)前版本的邊界應(yīng)作為使用前提知曉不支持 DLPack源碼標(biāo)注TODO: dlpack support跨框架零拷貝互操作需走 CAI忽略只讀標(biāo)記cai[data][1]readonly 標(biāo)志在構(gòu)造時(shí)被讀取但暫未執(zhí)行寫保護(hù)TODO: Need to respect readonly未同步流若 CAI 中攜帶 stream 信息構(gòu)造時(shí)不主動(dòng)同步TODO: Need to synchronize on stream if present in caibyte_slice的 TODO 同樣提到Need to propagate stream from parent.cai if present僅支持步長(zhǎng)為 1 的切片byte_slice不支持 strided 訪問。此外gpumemoryview定義了__hash__ Nonegpumemoryview.pyx即不可哈希——這與它作為可變緩沖區(qū)視圖的語義一致。8. 快速上手示例以下代碼均可在安裝 pylibcudf 后直接運(yùn)行pylibcudf 已通過init.py 將gpumemoryview暴露為頂層符號(hào)import pylibcudf as plc后即可使用plc.gpumemoryviewimport rmm import pylibcudf as plc # 1. 用 rmm.DeviceBuffer 構(gòu)造 gpumemoryview buf rmm.DeviceBuffer(size1024) gv plc.gpumemoryview(buf) # 2. 核心屬性 assert gv.ptr ! 0 # 設(shè)備指針 assert gv.nbytes 1024 # 字節(jié)數(shù) assert gv.size gv.nbytes # Span 協(xié)議別名 print(gv.cai[typestr]) # 原始對(duì)象的 dtype 描述 # 3. 字節(jié)切片返回 |u1 字節(jié)視圖保持父緩沖存活 sub gv.byte_slice(slice(0, 64)) assert sub.nbytes 64 # 4. 從 Column 獲取數(shù)據(jù)視圖 col plc.Column.from_array([1, 2, 3, 4, 5], dtypeplc.DataType(plc.TypeId.INT32)) col_data col.data() # gpumemoryview print(col_data.nbytes) # 20 5 * 4 字節(jié) # 5. 異常路徑 try: plc.gpumemoryview(object()) # 不支持 CAI 的對(duì)象 except ValueError as e: print(e) # gpumemoryview must be constructed from ...9. 總結(jié)gpumemoryview是 pylibcudf 設(shè)備內(nèi)存抽象的基石組件它以 CUDA Array Interface 為統(tǒng)一輸入?yún)f(xié)議以指針 字節(jié)數(shù) CAI 描述的最小結(jié)構(gòu)提供零拷貝的 GPU 內(nèi)存視圖并借助 Span 協(xié)議融入Column、contiguous_split、transform等核心模塊的數(shù)據(jù)流。理解它的構(gòu)造規(guī)則dtype 映射、nbytes 推導(dǎo)、切片語義純字節(jié)級(jí)、生命周期托管與已知限制無 DLPack、無流同步是在 pylibcudf 層面做高性能數(shù)據(jù)處理與二次開發(fā)的基礎(chǔ)。若需深入閱讀推薦從以下路徑繼續(xù)核心實(shí)現(xiàn)python/pylibcudf/pylibcudf/gpumemoryview.pyx類型與聲明python/pylibcudf/pylibcudf/gpumemoryview.pyi、python/pylibcudf/pylibcudf/gpumemoryview.pxd測(cè)試驗(yàn)證python/pylibcudf/tests/test_gpumemoryview.py、python/pylibcudf/tests/test_span.py集成示例python/pylibcudf/pylibcudf/column.pyx、python/pylibcudf/pylibcudf/contiguous_split.pyx、python/pylibcudf/pylibcudf/transform.pyx贊分享數(shù)據(jù)分析數(shù)據(jù)工程機(jī)器學(xué)習(xí)【免費(fèi)下載鏈接】cudfcuDF - GPU DataFrame Library項(xiàng)目地址https://gitcode.com/gh_mirrors/cu/cudf點(diǎn)擊查看免費(fèi)下載相關(guān)推薦CUDA Python 進(jìn)程間共享 GPU 內(nèi)存實(shí)戰(zhàn)基于 cuda.core IPC 內(nèi)存池的 ipcMemoryPool 示例全解析CUDA Python 進(jìn)程間共享 GPU 內(nèi)存實(shí)戰(zhàn)基于 cuda.core IPC 內(nèi)存池的 ipcMemoryPool 示例全解析 本指南深入解析 NVI示例工程cuda-samples memMapIPCDrv 深度解析基于 cuMemMap 與 Driver API 的多進(jìn)程跨 GPU 內(nèi)存共享實(shí)戰(zhàn)cuda samples memMapIPCDrv 深度解析基于 cuMemMap 與 Driver API 的多進(jìn)程跨 GPU 內(nèi)存共享實(shí)戰(zhàn) 導(dǎo)讀 memM示例工程基于 RAPIDS cuGraph 與 cuda.core 的 GPU PageRank 實(shí)戰(zhàn)CUDA Python Samples 深度解析基于 RAPIDS cuGraph 與 cuda.core 的 GPU PageRank 實(shí)戰(zhàn)CUDA Python Samples 深度解析 本指南以 cu示例工程創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考