Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (はじめに)







# はじめに


Linux では DMA Bufferを mmap した時に、ある条件が揃うと CPU Cache が無効になり、パフォーマンスが極端に落ちる場合があります。そこで、何故そのようなことが起こるのか説明します。少し長くなるので、次のように記事を幾つかに分けて投稿します。



1.  __はじめに(この記事)__  
2. [Cache Coherence 問題]
3. [Cache Aliasing 問題]
4. [Linux Kernel の Cache 問題の扱い]
5. [Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる]
6. [Raspberry Pi の例]
7. [RISC-V CPU の注意点]
8. [所感]



1〜3は、コンピューターアーキテクチャの基本的な事項を、簡単に説明したものです。すでにご存じの方は読み飛ばしてください。

4 はこれらの問題を Linux Kernel 内でどのように扱っているかを説明します。

5 がこれらの記事群の結論です。結論だけ知りたい方はここだけ読んでください。



この記事では、まずタイトルの「Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある」を説明する際に登場する主要なコンポーネントの紹介と、DMA Buffer と mmap などの基本的な知識について説明します。すでにご存じの方は読み飛ばしてください。


# 基礎知識



## 主要コンポーネントの紹介


ここでは、「Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある」 のを説明する際に登場するコンポーネントを紹介します。なお、実際のコンピューターシステムはもっと複雑ですが、この記事では説明に必要な分だけを簡潔にモデル化しています。



この簡潔版コンピューターモデルでは、次の図で示すように、各コンポーネントを４つに分類しています。


![Fig.1 Introduction of main components](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0%2F24981%2Fba20641d-2ebd-67ad-94e6-905bbf009b54.jpeg "Fig.1 Introduction of main components")

Fig.1 Introduction of main components

<br />



  * CPU: Central Processing Unit   
ここでは Linux が動く CPU を指します。   
CPU には仮想アドレスを物理アドレスに変換する MMU(Memory Management Unit）とメモリアクセスを高速に見せるための CACHE が含まれます。特に CACHE はこの話題の主役になります。
  * MEMORY:   
ここでは Linux が管理するメモリを指します。
  * DEVICE:   
ここでは、CPU 以外の機能ユニットを十把一絡げに DEVICE と称します。   
USB I/F や Net I/F 等の I/O ユニット、GPU や NPU などのアクセラレータ等も、ここでは DEVICE に分類します。   
さらに CPU は積んでいるけど Linux が動作していないようなサブシステムもここでは DEVICE に分類しています。
  * InterConnect:   
CPU、MEMORY、DEVICE を相互接続するユニットです。   
ここでは説明を単純にするために、一つの箱で表現していますが、実際のコンピューターシステムはもっと複雑です。   
一般的には相互接続する際には AXI、TileLink、PCI-Express、CLX などのプロトコルが使われます。InterConnect はこれらのプロトコルで CPU、MEMORY、DEVICE を相互接続します。




## DMA バッファとは


CPU が DEVICE とデータのやり取りする方法は大きく二つあります。



一つ目は DEVICE の持つレジスタやメモリに CPU が直接アクセスする方法です。通常、DEVICE は CPU からアクセスできるレジスタを持っており、CPU がこれらのレジスタにアクセスすることによって DEVICE の制御を行います。このレジスタを経由してデータを転送することが可能です。

しかし、このレジスタをアクセスしてデータを転送する方法には問題があります。それは、CPU にとってレジスタアクセスが非常に遅いことです。例えば、CPUがレジスタにアクセスする際に数マイクロ秒かかることはざらにありますが、これは 1GHz で動作する CPU にとっては数千命令を実行する時間に相当します。こんな速度で大量のデータを転送していては、CPU の無駄遣いと言わざるを得ません。



そこで MEMORY に DEVICE がアクセスできるバッファを用意しておいて、DEVICE が直接 MEMORY にアクセスすることで CPU によるデータ転送を行わないようにする方法が考えられます。これをDMA (Direct Memory Access) 方式と言い、MEMORY上にある DEVICE がアクセスできるバッファを DMA バッファと呼びます。


![Fig.2 DMA(Direct Memory Access) and DMA Buffer](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0%2F24981%2F1bd43aa4-4e8c-dd7b-a196-7cb7bab9863b.jpeg "Fig.2 DMA(Direct Memory Access) and DMA Buffer")

Fig.2 DMA(Direct Memory Access) and DMA Buffer

<br />



Linux では DMA バッファは Linux Kernel の管理下におかれます。これは仮想記憶と紐づけるためです。通常 DEVICE が MEMORY にアクセスする際は物理アドレスが用いられます。一方、仮想記憶方式では CPU が MEMORY にアクセスする際は仮想アドレスが用いられます。これらの異なるアドレス空間を取り持っているハードウェアが MMU であり、それを管理しているのが Linux Kernel だからです。

また、Linux では DMA バッファは Kernel 空間に配置されます。ユーザー空間上のバッファだと、場合によってはメモリの再配置などによって物理アドレスが替わることがありますが、これは DEVICE が DMA する際に問題になります。そこで Linux では DMA バッファは Kernel 空間に配置してしまって動かないようにしています。

Linux では DMA バッファの管理は DMA Mapping API で行われます。


## mmap とは


前節で Linux では DMA バッファは Linux Kernel の管理下におかれ Kernel 空間に配置されると説明しました。では、ユーザープログラムが DEVICE とデータを転送する際にはどうするのでしょうか。

まず最も簡単なのが、ユーザープログラム上にあるデータを Linux Kernel が DMA バッファにコピーする方式です。

コピー方式ではデータのコピーが発生しますが、このデータのコピーは CPU がメモリにアクセスすることで行われます。したがって CPU に負荷がかかるため、性能上問題があります。




![Fig.3 Copy data between DMA Buffer and User Data Area](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0%2F24981%2Fbbb6b4d7-722c-f677-c5cf-222b469f66b6.jpeg "Fig.3 Copy data between DMA Buffer and User Data Area")

Fig.3 Copy data between DMA Buffer and User Data Area

<br />



そこでもう一つの方法として mmap 方式が考えられました。これは Kernel 空間に割り当てられた DMA バッファをユーザープログラムからアクセスできるように User Space に仮想アドレスを割り当てる方法です。このようにすれば、ユーザープログラムが直接 DMA バッファにアクセスすることができるようになり、余計なコピーが発生しません。


![Fig.4 Mmap DMA Buffer to User Space](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0%2F24981%2F0c4a06bb-4a8a-e2ba-1473-a7769bd6655e.jpeg "Fig.4 Mmap DMA Buffer to User Space")

Fig.4 Mmap DMA Buffer to User Space

<br />


# まとめ


この記事では、「Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある」のを説明する際に登場するコンポーネントと DMA Buffer と mmap について説明しました。

本来、DEVICE にデータを効率的に転送する方法である、DMA Buffer と mmap ですが、何故かCPU Cache が無効になり却って性能が落ちる場合があるのです。

次の記事 [『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題とは何か)』] では、その原因の一つである Cache Coherence 問題 について説明します。




# 補足



## モチベーション


これらの記事は、筆者が [『Kernel/VM探検隊@北陸 Part 6』] で説明した内容を記事にしたものです。一応、動画としても残っているのですが、筆者のプレゼンテーションがあまりにも下手くそで何を言ってるのかさっぱり判らないので、少なくとも資料として残しておこうと思った次第です。




# 参考


*  『Kernel/VM探検隊@北陸 Part 6』@connpass   
https://kernelvm.connpass.com/event/297033
* 『Kernel/VM探検隊@北陸 Part 6』@YouTube   
https://www.youtube.com/watch?v=fp-LZl0GIFs


[はじめに]: https://qiita.com/ikwzm/items/aa7e2373705872ccf764 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (はじめに)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (はじめに)』]: https://qiita.com/ikwzm/items/aa7e2373705872ccf764 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (はじめに)』@Qiita"
[Cache Coherence 問題]: https://qiita.com/ikwzm/items/f60281491cc83f29c019 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題とは何か)』@Qiita"
[Cache Coherence 問題とは何か]: https://qiita.com/ikwzm/items/f60281491cc83f29c019 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題とは何か)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題とは何か)』]: https://qiita.com/ikwzm/items/f60281491cc83f29c019 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題とは何か)』@Qiita"
[Cache Coherence 問題の解決方法]: https://qiita.com/ikwzm/items/6d3225e4cbdbbabcabd5 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題の解決方法)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題の解決方法)』]: https://qiita.com/ikwzm/items/6d3225e4cbdbbabcabd5 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Coherence 問題の解決方法)』@Qiita"
[Cache Aliasing 問題]: https://qiita.com/ikwzm/items/1b8dc72e04d0fa031a0f "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題とは何か)』@Qiita"
[Cache Aliasing 問題とは何か]: https://qiita.com/ikwzm/items/1b8dc72e04d0fa031a0f "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題とは何か)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題とは何か)』]: https://qiita.com/ikwzm/items/1b8dc72e04d0fa031a0f "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題とは何か)』@Qiita"
[Cache Aliasing 問題の解決方法]: https://qiita.com/ikwzm/items/b3c24f04121a0d2deefd "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題の解決方法)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題の解決方法)』]: https://qiita.com/ikwzm/items/b3c24f04121a0d2deefd "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題の解決方法)』@Qiita"
[Linux Kernel の Cache 問題の扱い]: https://qiita.com/ikwzm/items/f32985890b2013ef5528 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Linux Kernel の Cache 問題の扱い)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Linux Kernel の Cache 問題の扱い)』]: https://qiita.com/ikwzm/items/f32985890b2013ef5528 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Linux Kernel の Cache 問題の扱い)』@Qiita"
[Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる]: https://qiita.com/ikwzm/items/0f77072158ce842018fc "『Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる』@Qiita"
[『Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる』]: https://qiita.com/ikwzm/items/0f77072158ce842018fc "『Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる』@Qiita"
[Raspberry Pi の例]: https://qiita.com/ikwzm/items/f8bcb82cfdb818bdb07d "『Raspberry Pi では DMA Buffer をmmap する際に CPU Cache が無効になる』@Qiita"
[『Raspberry Pi では DMA Buffer をmmap する際に CPU Cache が無効になる』]: https://qiita.com/ikwzm/items/f8bcb82cfdb818bdb07d "『Raspberry Pi では DMA Buffer をmmap する際に CPU Cache が無効になる』@Qiita"
[RISC-V CPU の注意点]: https://qiita.com/ikwzm/items/3c6b15029780be57f3a9 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (RISC-V CPU の注意点)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (RISC-V CPU の注意点)』]: https://qiita.com/ikwzm/items/3c6b15029780be57f3a9 "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (RISC-V CPU の注意点)』@Qiita"
[所感]: https://qiita.com/ikwzm/items/46f00c39b7d92c06654e "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (所感)』@Qiita"
[『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (所感)』]: https://qiita.com/ikwzm/items/46f00c39b7d92c06654e "『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (所感)』@Qiita"
[『Kernel/VM探検隊@北陸 Part 6』]: https://kernelvm.connpass.com/event/297033/ "『Kernel/VM探検隊@北陸 Part 6』"