0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

在BuildRelay中會調(diào)用Codegen函數(shù)

電子設(shè)計 ? 來源:電子設(shè)計 ? 作者:電子設(shè)計 ? 2022-02-08 16:02 ? 次閱讀

作者:安平博,Xilinx高級工程師;來源:AI加速微信公眾號

接著上一章繼續(xù)深入代碼,在BuildRelay中會調(diào)用Codegen函數(shù)。這個函數(shù)實現(xiàn)在src/relay/backend/graph_runtime_codegen.cc中。Codegen實現(xiàn)了內(nèi)存的分配,IR節(jié)點到TIR節(jié)點的轉(zhuǎn)換,tir圖節(jié)點的一個調(diào)度優(yōu)化。內(nèi)存分配由函數(shù)relay.backend.GraphPlanMemory來實現(xiàn),VisitExpr對節(jié)點進行遍歷并進行節(jié)點信息的記錄。LowerExternalfunctions完成ir節(jié)點到tir節(jié)點的轉(zhuǎn)化以及schedule的優(yōu)化。

pIYBAGAJmYKAeKUpAAOkJNgC9IE642.png

內(nèi)存分配

通過GetPackedFunc函數(shù)來獲得注冊到global map的內(nèi)存分配函數(shù)GraphPlanMemory。我們看一下文件src/relay/backend/graph_plan_memory.cc中對內(nèi)存的處理。

o4YBAGAJmcKARl1CAACGZg0dj7U340.png

在處理內(nèi)存分配中主要使用了StorageAllocaBaseVisitor,StorageAllocaInit,StorageAllocator這三個類。StorageAllocaBaseVisitor是一個基類,實現(xiàn)了對每個節(jié)點的訪問,并分配token,但是token中信息是在派生類中處理的。定義了一個StorageToken的結(jié)構(gòu)體,用于表示申請到內(nèi)存的大小,類型等信息。在內(nèi)存處理程序中,主要就是為每個節(jié)點分配這個token,同時定義token的內(nèi)部信息。內(nèi)存分配結(jié)果是一個節(jié)點和token的映射表。

o4YBAGAJmgGAEqo-AADcglyV-4Y415.png

StorageAllocator類中Plan函數(shù)為:

o4YBAGAJmkGASccNAAKmVvtXPgY414.png

關(guān)鍵是前兩行代碼,第一行代碼初始化了storageToken,賦予了其設(shè)備類型和數(shù)據(jù)類型信息。第二行代碼遍歷每個節(jié)點,并且為每個節(jié)點分配內(nèi)存空間。在內(nèi)存初始化函數(shù)GetInitTokenMap中,首先收集每個節(jié)點的的設(shè)備信息。調(diào)用鏈為CollectDeviceInfo -> GetDeviceMap(src/relay/transforms/device_annotation.cc)。在構(gòu)建relay圖結(jié)構(gòu)的時候,每個節(jié)點是有設(shè)備號信息的,GetDeviceMap就是按照post-DFS順序獲得節(jié)點的設(shè)備號信息。當然并不是所有節(jié)點都有設(shè)備號信息,所以還需要根據(jù)節(jié)點之間的關(guān)系來推斷出設(shè)備號。比如下圖,add,sqrt,log節(jié)點被標注為1,2,3號設(shè)備,那么可以用兩種方式來推斷其它節(jié)點設(shè)備號。

1) 從一個copy節(jié)點由下而上遍歷一直到遇到下一個copy,比如可以推斷出add,x,y節(jié)點的設(shè)備號和copy1一樣;
2) 從最后一個copy節(jié)點向下遍歷,那么可以推斷出substract,exp設(shè)備號和copy3一樣。

pIYBAGAJmpqAIGavAACO4hsCsQ8586.png

設(shè)備號獲得后,this->run會調(diào)用基類的run函數(shù),基類run函數(shù)會調(diào)用派生類的CreateToken函數(shù)。CreateToken會申請StorageToken空間并且賦予設(shè)備號和數(shù)據(jù)類型,然后返回一個token_map_。和節(jié)點遍歷相關(guān)函數(shù)為Run->GetToken->VisitExpr。VisitExpr會最終調(diào)用StorageAllocaInit類中定義的VisitExpr_函數(shù)來遍歷節(jié)點。

節(jié)點內(nèi)存初始化完成后,回到StorageAllocator類中,run會調(diào)用其定義的CreateToken函數(shù)。

pIYBAGAJmt6AE8_gAALBr5QvaFI549.png

分配內(nèi)存空間會有兩種情況,一種是can_realloc一種是不能can_realloc的。先看不can_realloc的,GetMemorySize是根據(jù)token中記錄的數(shù)據(jù)類型和shape信息來獲得數(shù)據(jù)的大小,Alloc函數(shù)就是為tok分配字節(jié)數(shù)量?,F(xiàn)在看can_realloc的情況,Request中首先獲取節(jié)點數(shù)據(jù)的大小。然后從free_中查詢能夠滿足size的節(jié)點,如果有比該節(jié)點size大的就選擇大的空閑區(qū)間分配,如果沒有大的空間分配,選擇最接近的空間分配。然后最終返回一個token_map_。

codegen

第一步是對ir節(jié)點進行遍歷,轉(zhuǎn)換成codegen中定義的基礎(chǔ)節(jié)點。我們先看以下codegen中定義的節(jié)點類型,GraphNode是基礎(chǔ)節(jié)點,GraphInputNode, GraphOpNode繼承自這個基礎(chǔ)節(jié)點。這些節(jié)點中主要提供了一些節(jié)點屬性,比如name,op類型等。還提供了dmlc接口,可以實現(xiàn)可視化。

遍歷func的parameters,將parameters轉(zhuǎn)換到graph的input節(jié)點。通過AddNode添加這些input節(jié)點,并且將轉(zhuǎn)換后的graphInputNode加入var_map_中,var_map_中是expr到graphNode的映射。

接下來是節(jié)點遍歷,heads_=VisitExpr(func->body)。節(jié)點遍歷過程中會將func中的節(jié)點轉(zhuǎn)換為graphNode。對于varNode,因為已經(jīng)記錄在var_map_中,直接返回引用。ConstantNode會轉(zhuǎn)換為GraphInputNode,tuppleNode會返回每個字段的graphNode。在遍歷節(jié)點過程中,會將graphNode都添加到nodes_中。

重點看一下對CallNode的處理,只支持op是functionNode類型的。

pIYBAGAJmx6AF101AAGj_ZQNbQ8072.png

Function生成時,走兩個分支,一個是外部codegen,一個是通用分支。對應(yīng)外部function codegen的處理為:

pIYBAGAJm2CAfy9BAANCOTr1_2U471.png

首先創(chuàng)建一個CCacheKey類型作為_CompileEngineLower函數(shù)的參數(shù)傳入。具體CcacheKey有什么作用,以后再深入研究吧。_CompileEngineLower的實現(xiàn)在文件src/relay/backend/compile_engine.cc中。調(diào)用鏈為Lower -> LowerInternal(key)->cached_func。定義了一個cache_node并封裝成cached_func返回。這塊具體的操作并不是很理解,可能還需要熟悉cachedFuncNode的作用。

o4YBAGAJm7yAUjp_AAKzrtE_tdQ078.png

然后通過GraphAddCallNode將其加入nodes_中。在GraphAddCallNode中還會對op->args進行深入遍歷。

內(nèi)部func處理如下:

o4YBAGAJm_uALky3AAGAfeWt9Xs683.png

也是通過相同的pf0和pf1函數(shù)。CcacheKey的創(chuàng)建過程一樣,但是在lowerInternal中不一樣。

o4YBAGAJnD6ATZm6AAStQTbokG4194.png

首先創(chuàng)建了一個schedule,schedule的具體實現(xiàn)很復雜目前還不夠理解。

如果是copy節(jié)點,那么不進行l(wèi)ower處理,直接返回CachedFunc封裝。不是copy節(jié)點,如果我們在python中自己定義了lower函數(shù)就調(diào)用python中的,如果沒有就會調(diào)用TVM中的lower函數(shù)。Lower函數(shù)在src/driver/driver_api.cc文件中。在這里調(diào)用了很多tir的passes來進行一個節(jié)點轉(zhuǎn)換。這塊后邊再詳細看。

審核編輯:何安

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4332

    瀏覽量

    62666
收藏 人收藏

    評論

    相關(guān)推薦

    HAL庫的函數(shù)調(diào)用示例

    HAL(Hardware Abstraction Layer,硬件抽象層)庫是STM32等微控制器中常用的庫,它為開發(fā)者提供了訪問和控制硬件設(shè)備的接口。以下是一些常用的HAL庫函數(shù)及其調(diào)用示例: 一
    的頭像 發(fā)表于 12-02 14:01 ?433次閱讀

    RTOS V1.4版本SDK作為TCP Server沒有調(diào)用斷開連接的回調(diào)函數(shù),為什么?

    espconn_regist_connectcb所注冊的函數(shù)。 espconn_regist_connectcb所注冊的函數(shù)里面調(diào)用espconn_regist_disconcb
    發(fā)表于 07-18 08:31

    websocket.c RTOS演示中缺少對wifi_connect()的調(diào)用怎么辦?

    RTOS SDK 1.3 中,有一個名為 /examples/websocket_demo/websocket/websocket.c 的示例。函數(shù)中有一個名為 websocket_task
    發(fā)表于 07-18 06:37

    ESP8266收到重傳的UDP數(shù)據(jù)包,則udp接收回調(diào)函數(shù)會調(diào)用兩次,怎么解決?

    我們使用 esp8266 開發(fā)了一個網(wǎng)格系統(tǒng)。 在所有開發(fā)完成時,我們發(fā)現(xiàn)了一個關(guān)鍵問題。 如果ESP8266收到重傳的 UDP 數(shù)據(jù)包,則 udp 接收回調(diào)函數(shù)會調(diào)用兩次。 (*. 收到兩個
    發(fā)表于 07-18 06:29

    點擊j-link下載之后,不會調(diào)用出j-link.exe,沒有反應(yīng)怎么解決?

    點擊j-link下載之后,不會調(diào)用出j-link.exe,沒有反應(yīng),有大神遇到這種情況嗎,怎么解決,求助
    發(fā)表于 07-18 06:12

    wifisoftAP的程序調(diào)用start_webserver(); 函數(shù),結(jié)果設(shè)備不斷復位,是什么情況?

    wifisoftAP的程序調(diào)用start_webserver(); 函數(shù),結(jié)果 設(shè)備不斷復位,這個什么情況? 開始的輸出信息
    發(fā)表于 06-19 06:47

    ESP32S2使用VSCODE編譯,總是會調(diào)用build->bootLoader->config->sdkconfig.h文件為什么?

    ESP32S2使用VSCODE編譯,調(diào)用sdkconfig.h頭文件時,總是會調(diào)用 build->bootLoader->config->
    發(fā)表于 06-07 06:48

    FreeRTOS如何在中斷中調(diào)用內(nèi)存分配函數(shù)?

    最近在玩FreeRTOS,遇到一個問題,就是不知如何在中斷中調(diào)用內(nèi)存分配函數(shù)。pvPortMalloc函數(shù)中會調(diào)用xTaskResumeAll,而這個
    發(fā)表于 05-08 08:25

    函數(shù)多層調(diào)用的主要注意事項分析

    應(yīng)用方案設(shè)計中,開發(fā)者經(jīng)常會碰到某個子函數(shù)需要多次多級調(diào)用的情況。
    的頭像 發(fā)表于 03-27 15:36 ?895次閱讀
    子<b class='flag-5'>函數(shù)</b>多層<b class='flag-5'>調(diào)用</b>的主要注意事項分析

    回調(diào)函數(shù)(callback)是什么?回調(diào)函數(shù)的實現(xiàn)方法

    回調(diào)函數(shù)是一種特殊的函數(shù),它作為參數(shù)傳遞給另一個函數(shù),并在被調(diào)用函數(shù)執(zhí)行完畢后被調(diào)用?;卣{(diào)
    發(fā)表于 03-12 11:46 ?2954次閱讀

    函數(shù)指針與回調(diào)函數(shù)的應(yīng)用實例

    通常我們說的指針變量是指向一個整型、字符型或數(shù)組等變量,而函數(shù)指針是指向函數(shù)函數(shù)指針可以像一般函數(shù)一樣,用于調(diào)用
    的頭像 發(fā)表于 03-07 11:13 ?405次閱讀
    <b class='flag-5'>函數(shù)</b>指針與回調(diào)<b class='flag-5'>函數(shù)</b>的應(yīng)用實例

    內(nèi)聯(lián)函數(shù)定義 為什么需要內(nèi)聯(lián)函數(shù)

    inline關(guān)鍵字是C99標準的型關(guān)鍵字,其作用是將函數(shù)展開,把函數(shù)的代碼復制到每一個調(diào)用處。
    的頭像 發(fā)表于 02-19 12:20 ?551次閱讀

    softuneV6中如何調(diào)用指向串口的printf函數(shù)?

    如題,想在環(huán)境中監(jiān)測數(shù)據(jù),請問如何調(diào)用函數(shù)?謝謝!
    發(fā)表于 02-19 06:48

    linux用gdb調(diào)試遇到函數(shù)調(diào)用怎么辦?

    linux用gdb調(diào)試遇到函數(shù)調(diào)用怎么辦? Linux上使用GDB調(diào)試時,遇到函數(shù)調(diào)用是一個常見的情況。
    的頭像 發(fā)表于 01-31 10:33 ?725次閱讀

    Linux內(nèi)核中信號相關(guān)的系統(tǒng)調(diào)用

    ,sys_sigaction()和sys_rt_sigaction()幾乎相同,因此C庫中包含的sigaction()包裝函數(shù)最終會調(diào)用sys_rt_sigaction()而不是sys_sigaction()。
    的頭像 發(fā)表于 01-20 09:34 ?748次閱讀