はじめに
Linux では DMA Bufferを mmap した時に、ある条件が揃うと CPU Cache が無効になり、パフォーマンスが極端に落ちる場合があります。そこで、何故そのようなことが起こるのか説明します。少し長くなるので、次のように記事を幾つかに分けて投稿します。
- はじめに
- Cache Coherence 問題
- Cache Aliasing 問題
3.1 Cache Aliasing 問題とは何か(この記事 )
3.2 Cache Aliasing 問題の解決方法 - Linux Kernel の Cache 問題の扱い
- Linux では Cache Coherence Hardware を持っていないとDMA Buffer をmmap する際に CPU Cache が無効になる
- Raspberry Pi の例
- RISC-V CPU の注意点
- 所感
1〜3は、コンピューターアーキテクチャの基本的な事項を、簡単に説明したものです。すでにご存じの方は読み飛ばしてください。
4 はこれらの問題を Linux Kernel 内でどのように扱っているかを説明します。
5 がこれらの記事群の結論です。結論だけ知りたい方はここだけ読んでください。
この記事では「Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある」原因の一つである Cache Aliasing 問題とは何かを説明します。すでにご存じの方は読み飛ばしてください。
Cache Aliasing 問題とは何か
Cache Aliasing 問題とは、仮想記憶をサポートしたコンピューターシステムにおいて、同じ物理アドレスに複数の異なる仮想アドレスを割り当てた際に発生するキャッシュの問題のことです。この Cache Aliasing 問題には、キャッシュの一貫性の問題とキャッシュ効率の問題の二つがありますが、ここではキャッシュの一貫性の問題を説明します。
キャッシュの実装例
ここではまず、Cache Aliasing 問題を説明するために、キャッシュの実装例を示します。
キャッシュの基本構成
一般的に CPU の CACHE は 下図のように、複数のキャッシュラインを保持する RAM で構成されています。ここでのキャッシュラインとは、キャッシュの状態を保持しておくフラグ部、アドレスの上位部分を保持しておくタグ部、MEMORY 上のデータを保持しておくデータ部を一組にしたものです。
Fig.1 Example of CACHE structure
指定されたアドレスが CACHE にあるかどうかを判定する時は、下図のように行います。まず、アドレスを3部分に分割します。
Fig.2 Example of Address structure
最下位の Pos 部は、CACHE LINE のデータ部の位置を示します。通常 、一つのCACHE LINE のデータ部は MEMORY 上の数バイト分を保持します。ちなみにこの容量のことを CACHE LINE SIZE と呼びます。この容量は CPU によって異なり、例えば Cortex-A53 の L1-Cache のCACHE LINE SIZE は64バイトです。この場合、Pos 部は6ビットあります。
2番目の Index 部は、RAM に格納されているCACHE LINE のうちの、どの CACHE LINE かを示します。この Index 部で示す内容を RAM から読み出します。
3番目の Tag 部は、Index 部によって RAM から読み出された CACHE LINE が、指定されたアドレスのものかを判定する際に使用されます。指定されたアドレスの Tag 部と、RAMから読み出された CACHE LINE の TAG 部と比較して、一致すれば、RAM から読み出された CACHE LINE は指定されたアドレスのものと判定されます。
キャッシュの実装例(PIPT方式)
ここではまず、CACHE の実装例の一つとして PIPT(Physically Indexed P hysically T agged) 方式を説明します。PIPT 方式とはその名前の通り、下の図のように、仮想アドレスを物理アドレスに変換してから CACHE LINE を読む方式のことです。
Fig.3 PIPT(Physically Indexed Physically Tagged)
PIPT方式の特徴は、まず仮想アドレスを物理アドレスに変換してから RAMをアクセスすることです。そのため、指定されたアドレスが CACHE にあるかどうかを判定するのに、3ステップ必要になります。
キャッシュの実装例(VIPT方式)
もう一つ、CACHE の実装例の一つとして VIPT(Virtually Indexed Physically Tagged)方式を説明します。VIPT 方式では、下の図のように、 CACHE LINE を読む際は、仮想アドレスの Index をそのまま使います。そして CACHE LINE を読むのと同時並行で仮想アドレスを物理アドレスに変換します。
Fig.4 VIPT(Virtually Indexed Physically Tagged)
VIPT 方式の特徴は、指定されたアドレスが CACHE にあるかどうかを判定するのに、PIPT 方式より1ステップ速い2ステップで済むことです。
このように、一見良さげな VIPT 方式ですが、現在のモダンな CPU ではほとんど採用されていません。何故ならば、問題点がいくつかあるからです。そのうちの一つが次節で説明する Cache Aliasing 問題です。
Cache Aliasing とは
まず、次の図のように、同じ物理アドレスに複数の異なる仮想アドレスを割り当てることを考えます。
Fig.5 Assign multiple Virtual Address Areas to a single Physical Area
キャッシュが PIPT(Physically Indexed Physically Tagged)方式の場合は、次の図のように、仮想アドレスをまず物理アドレスに変換してから RAM から CACHE LINE を読み出すため、どちらの仮想アドレスの場合も必ず同じ CACHE LINE を指します。
Fig.6 In the case of PIPT
ところがキャッシュが VIPT(Virtually Indexed Physically Tagged) 方式の場合は、CACHE LINE を読み出すために仮想アドレスの Index をそのまま使います。そのため、次の図のように、異なる仮想アドレスからのアクセスの場合、それぞれが異なる CACHE LINE を指すことがあります。
Fig.7 In the case of VIPT
このように、同じ物理アドレスに複数の異なる仮想アドレスを割り当てた際に異なる CACHE LINE が割り当てられた状態を Cache Aliasing と言います。
この Cache Aliasing が引き起こす問題のことを Cache Aliasing 問題と言います。Cache Aliasing 問題のもっともやっかいなものが、CACHE LINE 間の一貫性(Coherency) 問題です。判りやすい例を挙げると、ある仮想アドレスを使って書き込んだ内容が、別の仮想アドレスを使って読んだときに、ちゃんと書き込んだデータが読めるかということです。
まとめ
この記事では、「Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある」のを説明する際に、知っておいてほしい Cache Aliasing 問題とは何かについて説明しました。
Cache Aliasing 問題とは、仮想記憶をサポートしたコンピューターシステムにおいて、同じ物理アドレスに複数の異なる仮想アドレスを割り当てた際に、キャッシュが VIPT 方式で実装されている場合は、キャッシュの一貫性に問題が発生することです。
次の記事 『Linux で DMA Bufferを mmap した時に CPU Cacheが無効になる場合がある (Cache Aliasing 問題の解決方法)』 では、この Cache Aliasing 問題の解決方法を説明します。