Vortex GPGPU的硬件設計和代碼結構分析

文章目錄

  • 前言
  • 一、GPGPU是什么?
    • 1.1 GPU和GPGPU之間的差異
    • 1.2 GPU和CPU之間的集成方式
    • 1.3 GPU包含什么(列舉和VMIPS向量體系結構的差異)
  • 二、Vortex GPGPU是什么?
    • 2.1 Vortex GPGPU的技術邊界和驗證環境
    • 2.2 Vortex GPGPU的指令集設計(對比GPU的指令集)
    • 2.3 Vortex GPGPU Core的6級流水微架構設計
    • 2.4 Vortex GPGPU的微架構設計
    • 2.5 Vortex GPGPU的Cache串行流水線設計和Cache多端口設計方法
  • 三、Vortex GPGPU代碼包含什么?
    • 3.1 Vortex GPGPU的代碼結構
    • 3.2 Vortex GPGPU的握手協議
    • 3.3 Vortex GPGPU代碼中slave/master規范
    • 3.4 Vortex GPGPU代碼支持的debug
  • 總結


前言

這次開始針對Vortex GPGPU進行架構分析、硬件代碼分析、仿真代碼分析和運行時代碼分析。

Vortex GPGPU的官方文檔可以見:Vortex GPGPU

Vortex GPGPU的github可見:github,其中vortex包含源碼和必要的.md文件,其中vortex_tutorials包含作者在MICRO頂會上匯報的slide

本系列文章首先參考了知乎帖子,在略微深入了解Vortex GPGPU之后就覺得這可能是學習GPGPU系統工作的好機會。同時也為下一個研究工作做準備工作。


一、GPGPU是什么?

1.1 GPU和GPGPU之間的差異

顧名思義,Vortex GPGPU是一種簡化版本的GPGPU。在此之前,可以簡單回顧GPU的基本知識。(個人建議如果要深入研究GPGPU架構,還是先去把《計算機體系結構:量化研究方法》這一本書內關于數據級并行的知識去回顧一遍)由于GPU除了包含用于加速深度學習中矩陣乘的tensor core和支持其他計算的cuda core之外,還包含圖形渲染等技術。GPU在處理視覺密集型任務,如視頻游戲、三維動畫、圖形設計和視頻編輯時表現出色。此外,GPU的并行計算能力在科學模擬、數據分析、深度學習和機器學習等領域表現出色。

GPGPUGPU的一個概念,指的是將GPU用于除了圖形渲染之外的通用計算任務。GPGPU利用GPU的并行處理能力來加速科學模擬、數據分析和機器學習等計算密集型任務。這種技術允許開發者通過使用專門的編程框架,如CUDAOpenCL,來編寫能夠在GPU上執行的代碼,從而利用GPU的并行架構來加速計算。換句話說,GPGPU專注于使用GPU進行非圖形的通用計算任務

1.2 GPU和CPU之間的集成方式

注意GPU圖靈完備的,圖靈完備是指理論上只要提供足夠多的時間和內存,任何計算都可以完成。但是這并不代表GPU可以脫離CPU而存在,這是因為GPU并不是一個獨立的計算設備,往往需要和CPU集成在一個芯片內。CPU負責GPU上的計算啟動,并將數據傳輸到GPU上。關于兩者的架構圖根據場景分為2類:
在這里插入圖片描述
圖源《General-Purpose Graphics Processor Architecture》

圖1.1(a)顯示一個包含CPU和GPU的典型系統圖,此處GPU“獨立GPU”,其中也包括用于連接CPUGPU的總線如PCIECPUGPU分別帶有獨立的DRAM內存空間CPU的內存空間稱為“系統內存System Memory”GPU的內存空間稱為“設備內存Device Memory”。并且,“系統內存”“設備內存”通常會使用不同的DRAM技術,比如CPU使用DDR(這是因為CPU優先優化DDR的訪問延遲),GPU使用GDDR(這是因為GPU優先優化GDDR的訪問吞吐量)。

圖1.1(b)是一個典型的集成CPU和GPU的邏輯圖,比如AMDBristol Ridge APU或者移動設備的GPU“移動GPU”),此處的CPUGPU使用單一的DRAM內存空間,因此必須使用相同的內存技術,由于集成CPU和GPU的芯片出現在低功耗移動設備上,所以對這種內存的優化往往針對功耗展開(LPDDR)。

1.3 GPU包含什么(列舉和VMIPS向量體系結構的差異)

現在來看看GPU包含了什么?
在這里插入圖片描述
在這里插入圖片描述
包含指令緩存warp調度程序SIMD車道或者說線程處理器各個層次的存儲器互連網絡等。

一個高度抽象的全架構圖如下:
在這里插入圖片描述

類似于向量體系結構GPU有類似概念。

網格:在GPU上執行的可向量化循環,由一個或者多個可以并行執行的線程塊組成。
線程塊block:可以在多線程SIMD處理器上執行的向量化循環,由1個或者多個SIMD指令線程組成。它們可以通過局部存儲器通信。
CUDA線程:對應于1個SIMD車道上執行的1個元素。
Warp:一種傳統線程,僅包含多線程SIMD處理器上執行的SIMD指令。
PTX:在多個SIMD車道上執行的1條SIMD指令。
SM流式多處理器:多線程SIMD處理器執行SIMD指令的線程,和其他SIMD處理器無關。
Warp調度程序:當SIMD指令線程做好準備后,用于調度發射這些線程的硬件,包括一個計分板,用于跟蹤SIMD線程執行。

關于threadblockwarp之間的差異見:
在這里插入圖片描述

另外注意GPU有2級硬件調度程序

  1. 線程塊調度程序:將線程塊分配給多線程SIMD處理器,確保線程塊被分配給其局部存儲器擁有相應數據的處理器;
  2. SIMD處理器內部的SIMD線程調度程序(就是Warp調度程序),用以調度何時運行SIMD指令線程。

當然GPU向量體系結構這兩者也是有差異的:

GPU 向量體系結構
共同點1、可以解決數據級并行問題;2、都擁有Gather-Scatter數據傳送;3、都支持mask寄存器;
差異點1、GPU的寄存器數量要比VMIPS多;2、由于沒有一種接近的標量處理器,GPU有時會在運行時以硬件實現一些功能,VMIPS通常在編譯時用軟件來實現這些功能;3、與大多數VMIPS不同的是,GPU還依賴單個“多線程SIMD處理器“中的”多線程“來隱藏存儲器延遲;

展開SIMD車道
在這里插入圖片描述
其余關于GPU怎么處理分支,為什么引入mask寄存器等之后有需補充。

二、Vortex GPGPU是什么?

2.1 Vortex GPGPU的技術邊界和驗證環境

在這里插入圖片描述
以上是Vortex GPGPU團隊提出的GPGPU架構,整個系統包括Host端和GPGPU Processor端,Host端通過設計兩種不同平臺的驅動來支持AMDOpenCLNVIDIACUDA,事實上作者開發了不止一種驅動,根據底層環境分為四種,后面再展開!在CUDAOpenCL運行時之上就是兩類程序。而在Processor端,作者做了層級設計,包括計算和存儲。存儲包含設備內存共享memoryRegister File,計算層面則通過設計多個Core實現高度數據級并行,圖示中的AFU是用于Host端給GPGPUmulti-banking DRAM填充數據的單元。Core的架構細節包括Warp調度程序單元取指譯碼寄存器堆ALUFPULSUSFU共享存儲。彼此之間的連接關系見后面。

在這里插入圖片描述
以上是Vortex GPGPU設計的驗證環境。

1、最右側是作者團隊設計的一個周期精確Vortex GPGPU模擬器,基于SIMX Driver驅動支持Vortex應用程序的運行。
2、從最右側過來,左邊第一個是純Vortex GPGPU的驗證環境,作者借助Verilator這個開源波形驗證工具向上搭建RTLSIM驅動來支持Vortex應用程序的運行。
3、再往左邊過來就是,使用AFU實現基本的數據可供給的系統,作者依舊借助Verilator這個開源工具向上搭建VLSIM驅動來支持Vortex應用程序的運行。
4、最左側就是在FPGA平臺上基于OPAE驅動來支持Vortex應用程序的運行。

這樣的驗證環境對我本人來說,是全新的。因此,對我而言,有愈發學習框架和代碼的必要性。(此前,我只知道最左側的驗證環境和軟件開發流程

2.2 Vortex GPGPU的指令集設計(對比GPU的指令集)

在這里插入圖片描述
上述只列舉了部分RISC-V指令集擴展,主要是控制流指令
對比《計算機體系結構:量化研究方法》上的指令集:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2.3 Vortex GPGPU Core的6級流水微架構設計

在這里插入圖片描述
首先這個和超標量處理器類似,屬于多發射的處理器。作者自己定調是6級順序發射-亂序接收的GPGPU。每一級流水功能見下面圖片:
在這里插入圖片描述
這是調度階段,包括前述提到的Warp調度程序Warp Table。關于IPDOM(Immediate Postdominator) TableInflight Tracker,根據官網論文的細節看:
IPDOM Table是為了解決SIMT(單指令多線程)處理器中的控制流分歧問題。具體來說是因為:

控制流分歧導致性能降低:控制流分歧發生在同一個硬件warp中的線程想要執行不同的指令路徑時。由于線程可能因為條件判斷、循環等操作而產生不同的執行流程,這會導致SIMT處理器中的某些線程空閑,從而降低流水線的利用率。如果不加以處理,控制流分歧會導致處理器性能的顯著下降。

IPDOM Table怎么解決這個問題:為了解決這個問題,引入了IPDOM棧。IPDOM棧的作用是跟蹤warp中線程的執行狀態,以便在發生控制流分歧時能夠恢復到正確的執行路徑。具體來說,每個warp都有一個私有的線程掩碼寄存器,該寄存器存儲當前正在運行的線程的掩碼。當執行到分割指令時,當前線程掩碼的狀態、新線程掩碼的逆,以及下一條指令的地址(PC+4)會被推入到IPDOM棧中。當執行合并指令時,會從IPDOM棧中彈出這些信息,以恢復到正確的執行狀態。

IPDOM Table引入的好處:引入IPDOM棧的目的是為了簡化硬件設計,同時有效處理控制流分歧。通過維護一個棧來跟蹤和恢復執行狀態,可以在不顯著增加硬件復雜度的情況下,解決控制流分歧帶來的性能問題。這種設計允許SIMT處理器更高效地處理線程執行中的條件分支和循環,提高了處理器的整體性能和利用率。

Inflight Tracker主要是為了跟蹤in flight指令,也就是跟蹤執行中的指令。

Warp Scheduler:
1、Schedule the next PC into the pipeline
2、Track stalled, active warpsIPDOM Stack
1、Save split/join states for divergent threadsInflight Tracker
1、Track in-flight instructions

在這里插入圖片描述
這是取指階段,包括設計Cache,處理ICache請求和響應。作者額外設計了預防死鎖的設計(具體細節看代碼的時候展開)。

1、Retrieve instructions from memory
2、Handle I-cache requests/responses

在這里插入圖片描述
這是譯碼階段,主要負責分析指令的各個field,從而確定操作類型操作數

1、Decode fetched instructions
2、Notify warp scheduler on control instructions

在這里插入圖片描述
這是發射階段,包括指令buffer、計分板、寄存器堆和操作數分發。

IBuffer
1、Store decoded instructions in separate per-warp queuesScoreboard
1、Track in-use registers
2、Check register use for decoded instructionsOperands Collector
1、Fetch the operands for issued instructions from the register file

在這里插入圖片描述
這是執行階段,包括四大類Cluster

ALU Unit
1、Handle arithmetic and branch operationsFPU Unit
1、Handle floating-point operationsLSU Unit
1、Handle load/store operationsSFU Unit
1、Handle warp control operations
2、Handle Control Status Registers (CSRs) operations

注意執行階段還包括:DispatchGather單元。
在這里插入圖片描述

在這里插入圖片描述
這是回收階段,用于獲取執行完的結果,并完成寫回到cache的操作。

Commit
1、Write result back to the register file and update the Scoreboard.

2.4 Vortex GPGPU的微架構設計

在這里插入圖片描述
計算部分的層次不過多解釋!

2.5 Vortex GPGPU的Cache串行流水線設計和Cache多端口設計方法

在這里插入圖片描述
這是個很典型的cache設計,包括TagData部分。可以先簡單回顧Cache的流水設計,以下圖來自《超標量處理器設計》:
在這里插入圖片描述
一個4路組相聯的cache設計如上,訪存地址分為TagIndexBlock OffsetIndex用于選中4路中的哪一行,也就是選中Tag Memory中某一行,隨后使用Tag來確定是否命中了4路中的某一路,如果命中,則接下來在Data Memory對應的路中根據Block offset選中某個cacheline data block
用于cache的并行化訪問流水(這里的并行指的是對Tag MemoryData Memory的并行訪問,同理后面提到的串行也是這兩者的串行訪問)
在這里插入圖片描述
在這里插入圖片描述
一般來說,會傾向于選擇串行訪問,原因是減少了MUX的數量,因為在現代CPU中,L1 ICache一般采用4路組相聯(我們以intel i4為例),L1 DCache一般采用8路組相聯L2 Cache同樣會采用8路組相聯。因此高相聯度的cache必然會帶來多路選擇器,而串行訪問明顯降低了對2個memory訪問延遲。當然缺陷也是明顯的,就是增加了load指令的延遲,因為多了一拍。

世界線收束一下!
在這里插入圖片描述
單從這張圖可以看出作者采用了Tag MemoryData Memory串行流水線設計。與此同時,作者提到為了適應多發射的需要,引入virtual multi-porting的設計。通常cache因為面積本來就很大,很少考慮True multi-porting設計。因為端口數量增加會導致面積增加。盡管如此,但是還是能接受,因為對于ICache而言,需要每個周期讀取多條指令,多端口設計基本可以保證每拍都可以取出指令。當然發射的指令數量完全取決于一次取多少cacheline block字節的對齊程度

在超標量處理器中,會有一些部件考慮使用True multi-porting,比如Register FileROBIssue Queue,但這些部件容量本身就不大。

相比之下,DCache采用這個方案對訪問延遲和面積都有極大的消極影響。一般的處理方案是multi-banking,以AMD Opteron為例:
在這里插入圖片描述
multi-banking的形式有利于分割開物理存儲,減少訪問競爭。一張更形象的圖是:
在這里插入圖片描述
使用多體交叉的方式來支持多端口訪問。

至于這里提到的virtual multi-porting設計方法,不太理解為什么作者將DCacheICache都進行了同樣處理(這一點先存疑,但感覺大概率是進行了同樣操作,后續等讀完代碼后再來澄清這個問題)。為什么這么設計,作者也提到了優勢,可能具體有多好還得回到代碼中去看看。

三、Vortex GPGPU代碼包含什么?

3.1 Vortex GPGPU的代碼結構

在這里插入圖片描述
在這里插入圖片描述
這里提到在FPGA上的部署,我簡單看了作者代碼,大概率是可以支持Vortex GPGPUZYNQ構建SoC,作者并未套用Xilinx提供的axi full封裝代碼,而是自己重構了。這可能是本源碼的第不知道多少個值得學習的地方。
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
一個是基于Intel的開發板,一個是基于xilinx的開發板。作者提到了具體支持的板子類型:
在這里插入圖片描述
世界線收束!
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

3.2 Vortex GPGPU的握手協議

在這里插入圖片描述
只是截個圖,保證后面看代碼的時候沒遺漏細節!

3.3 Vortex GPGPU代碼中slave/master規范

在這里插入圖片描述

3.4 Vortex GPGPU代碼支持的debug

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述


總結

本文簡單回顧GPU和CPU之間的集成方式,GPU和GPGPU之間的差異,同時根據經典書籍展開GPU的基本知識,并與VMIPS進行對比。隨后展開Vortex GPGPU的架構設計細節,并同時深入分析了作者設計的4種驗證環境。最后簡單展開Vortex GPGPU的源碼結構。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/42062.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42062.shtml
英文地址,請注明出處:http://en.pswp.cn/web/42062.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安卓穩定性之crash詳解

目錄 前言一、Crash 的基本原理二、Crash 分析思路三、實例分析四、預防措施五、參考鏈接 前言 在開發和測試 Android 應用程序時,遇到應用程序崩潰是很常見的情況。 Android 崩潰指的是應用程序因為異常或錯誤而無法正常執行,并且導致應用強制關閉。 一…

p11函數和遞歸

遞歸與迭代 求n的階乘。&#xff08;不考慮溢出&#xff09; int Fac1(int n) {int i0;int ret1;for(i1;i<n;i){ret*i;}return ret; } int main(){//求n的階乘int n0;int ret0;scanf("%d",&n);retFac1(n);printf("%d\n",ret);return 0; } int Fac…

什么是激光導航和視覺導航技術

激光導航和視覺導航技術是現代導航系統中的兩種重要技術&#xff0c;它們在多個領域&#xff0c;如掃地機器人、無人機、機器人導航等中都有廣泛應用。以下是對這兩種技術的詳細介紹&#xff1a; 一、激光導航技術 1. 定義與原理 激光導航技術是一種利用激光束進行精確測量和…

ChatGPT:||是短路運算符,那么|、、是什么?

ChatGPT&#xff1a;||是短路運算符&#xff0c;那么|、&、&&是什么? 在Java中&#xff0c;邏輯運算符&&和||是短路邏輯運算符&#xff0c;而&和|是非短路邏輯運算符。 && 和 || 是短路邏輯運算符。當使用這些運算符時&#xff0c;如果第一個…

解決 Docker 容器鏡像拉取難題:全面指南

一、引言 在使用 Docker 容器的過程中&#xff0c;經常會遇到鏡像拉取慢甚至無法下載的問題&#xff0c;這給開發和部署工作帶來了不小的困擾。本文將深入探討這一問題的原因&#xff0c;并提供多種有效的解決方案。 二、問題原因分析 網絡限制 本地網絡帶寬不足或存在網絡擁…

unity知識點 專項四 一文徹底說清楚(錨點(anchor)、中心點(pivot)、位置(position)之間的關系)

一 概述 想要使UI控件在屏幕中達到正確的顯示效果&#xff0c;比如自適應屏幕尺寸、固定邊距等等&#xff0c;首先要理清楚幾個基本概念和設置&#xff1a;錨點(anchor)、中心點(pivot)、位置(position)、UI縮放模式、父物件的transform設置 二 Anchor、Pivot與Position 2…

網絡連接線相關問題

問題1&#xff1b; 直通線為什么兩頭都是T568B&#xff1f;是否可以兩臺T5568A&#xff1f;或者任意線序&#xff0c;只需兩頭一致&#xff1f; 不行&#xff0c;施工規范規定。&#xff08;原因&#xff1b;網線最長距離100m&#xff0c;實際用起來要把網線包管&#xff0c;走…

【分布式系統】Filebeat+Kafka+ELK 的服務部署

目錄 一.實驗準備 二.配置部署 Filebeat 三.配置Logstash 四.驗證 一.實驗準備 結合之前的博客中的實驗 主機名ip地址主要軟件es01192.168.80.101ElasticSearches02192.168.80.102ElasticSearches03192.168.80.103ElasticSearch、Kibananginx01192.168.80.104nginx、Logs…

iperf3: error - unable to connect to server: No route to host

1.確認iperf3版本是否統一。 2.確認防火墻是否關閉。 關閉防火墻 : systemctl stop firewalld 查看防火墻狀態: systemctl status firewalld 3.重新建起鏈接

Java進階----接口interface

接口 接口概述 接口是一種規范&#xff0c;使用接口就代表著要在程序中制定規范. 制定規范可以給不同類型的事物定義功能&#xff0c;例如&#xff1a; 利用接口&#xff0c;給飛機、小鳥制定飛行規范&#xff0c;讓其都具備飛行的功能&#xff1b;利用接口&#xff0c;給鼠…

SMU Summer 2024 Contest Round 1

A.Hcode OnlineJudge 給出一個N面骰子和整數K&#xff0c;擲出1-N之間的每個數的概率相同&#xff0c;每次擲出一次&#xff0c;記為成績&#xff0c;若成績小于K&#xff0c;則開始拋硬幣&#xff0c;硬幣朝上則數翻倍&#xff0c;反之則為0&#xff0c;概率都為0.5。當數大于…

自動駕駛算法———車道檢測(一)

“ 在本章中&#xff0c;我將指導您構建一個簡單但有效的車道檢測管道&#xff0c;并將其應用于Carla 模擬器中捕獲的圖像。管道將圖像作為輸入&#xff0c;并產生車道邊界的數學模型作為輸出。圖像由行車記錄儀&#xff08;固定在車輛擋風玻璃后面的攝像頭&#xff09;捕獲。…

【ZIP壓縮大揭秘】輕松掌握ZIP分卷壓縮包的高效解壓秘籍!

在這個信息爆炸的時代&#xff0c;文件大小常常成為我們分享與存儲的絆腳石。幸運的是&#xff0c;ZIP分卷壓縮技術如同一把鑰匙&#xff0c;巧妙地將龐然大物分解成小巧易管理的部分。但面對這一串分卷壓縮包&#xff0c;你是否也曾迷茫于如何高效解壓&#xff0c;恢復文件的完…

解碼Python字符串:‘r‘、‘b‘、‘u‘和‘f‘前綴的全面指南

&#x1f4d6; 正文 1 字符串前加’r’ 表示原始字符串&#xff0c;消除轉義 print(abc\nde) # abc # deprint(rabc\nde) # abc\nde在下面這個列子中&#xff0c;如果不在路徑字符串前面加r那么&#xff0c;路徑中的空格就會出現問題 print(rD:\01 programming\09python\py…

全志A527 T527 cat /proc/cupinfo沒有Serial問題

1.前言 我們有些客戶是使用cpuinfo節點去獲取系統的cpuid的,如下: cat /proc/cupinfo processor : 0 BogoMIPS : 48.00 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp CPU impleme…

系統吃swap問題排查

目錄 背景 問題 分析并解決 1.控制線程數 2.更換IO組件 3.Linux進程信息文件分析 總結加餐 參考文檔 背景 隔壁業務組系統是簡單的主從結構&#xff0c;寫索引的服務(主)叫primary&#xff0c; 讀索引并提供搜索功能的服務(從)叫replica。業務線同步數據并不是平滑的&…

離散化及其在 Pandas 中的實現方法

目錄 1.什么是離散化&#xff1f; 2.離散化類型 3.示例代碼 3.1連續變量離散化 3.2定性變量離散化 4.運行結果 4.1連續變量離散化 4.2定性變量離散化 1.什么是離散化&#xff1f; 離散化是將連續數據或分類數據轉換為離散類別的過程&#xff0c;方便后續的數據分析和機…

static的理論學習

在說到static之前&#xff0c;需要先明確變量類型&#xff1a; 而在聊到變量類型之前我們可以將變量的兩個屬性好好學一學 變量的兩個屬性 作用域&#xff08;scope&#xff09;&#xff1a; 從內存的角度來看&#xff0c;就是變量存放在棧&#xff08;stack&#xff09;中&…

在 JavaScript 中,??(雙問號運算符)和 ?.(可選鏈運算符)區別

在 JavaScript 中&#xff0c;??&#xff08;雙問號運算符&#xff09;和 ?.&#xff08;可選鏈運算符&#xff09;是兩種不同的運算符&#xff0c;用于處理不同的情況&#xff1a; 雙問號運算符 (??): ?? 運算符是空值合并運算符&#xff08;Nullish Coalescing Oper…

Android C++系列:Linux進程(一)

1. 進程概念 我們知道,每個進程在內核中都有一個進程控制塊(PCB)來維護進程相關的信 息,Linux內核的進程控制塊是task_struct結構體。現在我們全面了解一下其中都有哪 些信息。 進程id。系統中每個進程有唯一的id,在C語言中用pid_t類型表示,其實就是一個非 負整數。進程的…