DAY87:閱讀Interoperability between Runtime and Driver APIs

I.4. Interoperability between Runtime and Driver APIs

An application can mix runtime API code with driver API code.

If a context is created and made current via the driver API, subsequent runtime calls will pick up this context instead of creating a new one.

If the runtime is initialized (implicitly as mentioned in CUDA C Runtime), cuCtxGetCurrent() can be used to retrieve the context created during initialization. This context can be used by subsequent driver API calls.

Device memory can be allocated and freed using either API. CUdeviceptr can be cast to regular pointers and vice-versa:

In particular, this means that applications written using the driver API can invoke libraries written using the runtime API (such as cuFFT, cuBLAS, ...).

All functions from the device and version management sections of the reference manual can be used interchangeably.

本文備註/經驗分享:

今天的章節是Driver API簡介的最後一篇,如同我們之前所說的,你需要學會了以前的一些Runtime API中沒有的概念:CUDA Context、Module,以及kernel在Driver API下的啓動。實際上,除了這三者外,其他的東西基本上只有函數名字的不同,而用法基本一樣的(例如cu開頭和cuda開頭)。 則今天的章節則是Driver API和Runtime API互操作。 在首天的Context章節裏面,你已經知道CUDA Context能否實現卡上分配的資源的隔離,同時你也知道runtime api會自動隱式初始化,自動使用一個context的。 那麼問題就來了,我能否在同時使用了Driver API和Runtime API的應用裏面,能否在Driver API和Runtime API的各自的context裏面(例如前者是手工創建的,後者是自動的),將資源互相共享?從而使得Driver API能使用Runtime API裏面的東西,或者相反?例如本章節給出了一個問題,我能否使用cublas(基於runtime api),在一個driver api應用裏面? 實際上是可以的。 存在多種辦法來完成這個共享,一個是最直接想到的笨辦法,內存是通用的,於是產生了: Driver API的Context <---> 系統內存 <----> Runtime API的Context 例如你可以將一個Runtime API的Context中有效的buffer中的數據傳到內存,在從內存傳到另外一個Driver API的Context的buffer中。這種辦法,的確可以工作,但是很低效。因爲你引入了兩次無辜的傳輸。 但這個是一個直接的思路,例如看我們論壇的: http://bbs.gpuworld.cn/thread-59078-1-2.html http://bbs.gpuworld.cn/thread-59076-1-2.html 類似這兩個帖子中的問題。都是很直接的想法。但是實際上,如果這些用戶閱讀了今天的章節,樓主們會有更好的做法: (1)Driver API和Runtime API可以共享同一個Context: 這主要又分爲Driver API先建立Context,並設定成當前線程的當前Context(第一個Driver API中建立該Context的Host線程會自動設定,其他線程需要手工),然後任何後續的Runtime API將取消自行的隱形建立過程,而是就地使用該Context。 和分成:Runtime API先初始化,然後Driver API獲取Runtime API所創建的默認Context,並使用它(cuCtxGetCurrent,在本Host線程的之前調用任何常規Runtime API函數後)。 通過這兩種方式中的任何一種,將使得該應用的Host進程中,能夠讓Runtime API和Driver API共享CUDA Context的。這樣就規避了數據不能共用的問題 (主要是分配的顯存)。 那麼除了緩衝區(顯存)外,其他的Driver API特有的Module和kernel指針對象,能否在Runtime API中共享,這個倒是不能的。因爲Runtime API將全自動管理它們。 但好在很少有需要將同一個kernel用兩種不同的方式分別從Runtime和Driver API中啓動的情況存在,所以這一般不是個問題。而較大的緩衝區的共享確實額外重要的。所以能否使用同一個context,共享緩衝區中的數據,就一般情況下足夠了。 這是第一點。 除了讓Runtime API和Driver API共享一個Context,能否互相利用數據外,本章節的互操作還有另外的一個重要的用戶。 重要的用途: 隨着CUDA的應用越來越廣泛,很多第三方的庫都在使用CUDA,特別是Runtime API。而這些第三方的庫在開發的時候,可能沒有注意到和調用者,或者其他的類似的利用了CUDA的庫之間的和平共處的問題,例如剛纔發的兩個帖子中所說的: 很多第三方的庫,同時在使用的時候,它們習慣性的假如cudaDeviceReset()(注意你沒看錯)。從而導致另外一個庫提示“Driver正在卸載”,或者“未知錯誤”之類的奇葩現象,這個就需要你自行處理了。使用第三方的庫,那麼就要付出使用的代價。 此時通過利用Driver API的這種Context互操作的方式,特別是在我們拿不到這些第三方庫的代碼,無法對它們進行修改的情況下,可以進行安全的調用: 例如Driver API中可以創建一個空白Context,然後用這個空白Context作爲當前Host線程的當前Context,再調用這些第三方的庫,這樣就可以讓它們隨意的折騰了。比較安全。 很多類似的用法都可以想到。 實際上,這就是Driver API所帶來的基本福利,你擁有更強和更細微的控制力。如同剛纔說過的,主要的3大點Driver API引入的不同(Context/Module/Kernel啓動),後兩個你無法直接在Runtime API裏共享,可能很多人也用不到;但是前者的Context的控制能力,所有的CUDA Runtime API用戶應當稍微學會一點,還是很有用的。所以這幾天的Driver API章節,你至少應當將第一天的,和第二天的內容看完。 例如剛纔論壇上的兩個問題,再例如很多人問的,爲何我在CUDA (Runtime API)的應用中,首次調用某些cuda開頭的函數(例如cudaMalloc), 總會卡上一段時間,爲何後續的同樣的函數調用,就快了很多?這個如果你閱讀了這些天的章節,你至少應該知道,這裏面存在runtime ap在自動進行初始化context,自動載入module之類的過程,這些過程中在手冊調用某些cuda開頭的函數,或者cudaDeviceReset()後,都會自動觸發,這樣你就不會迷茫的四處懷疑了。 實際上,不僅僅是今天章節的內容,用戶還應當看一下CUDA Runtime的隱形主Context的概念(網上就有),還應當看一下cuDevicePrimaryCtxt*()開頭的driver api函數,獲取更詳細的信息。 這樣到今天,Driver API的簡介就告一段落。如同剛纔所說,你至少應當看一下前兩天的內容,很有用途的。 雖然說Driver API用起來比較麻煩,但如同我們第一天說的,它帶來的更大的靈活性,更大的平臺和語言適應能力,更好的安全控制(例如今天的例子),都是嚴肅的CUDA使用者應當考慮的問題。 再次舉個例子說,某聯機的應用,服務器段發佈了一次動態更新(GPU上的kernel代碼),如果你使用傳統的自動更新方式 + CUDA Runtime API,你只能保存更新到exe,然後下次啓動的時候應用,但是如果你使用了Driver API,隨時可以從網絡傳來新的Module,然後你的應用完成在內存中,不停機的,舊Module卸載,新Module載入,外加新的kernel啓動的過程,一切都是熱更新的,沒有停機過程,你看這就是另外一個靈活性的例子。

有不明白的地方,請在本文後留言

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章