量子実験で、同じ間隔のパルスを何度も出したい。時刻を正確に指定できても、CPUが次の出力命令を作るのに手間取れば、予定に間に合わないことがあります。実験制御システムARTIQのDMA(Direct Memory Access)は、先に作った出力イベントの列をメモリーへ記録し、専用回路から再生する仕組みです。再生時に何が繰り返され、何が繰り返されないのかを知ると、使いどころが見えてきます。
簡単にまとめると?
- DMAに記録するのは、時刻付きの出力イベントです。再生のたびにPythonの計算や入力測定をやり直すわけではありません。
- 記録中は時刻の基準が0になり、再生時の開始時刻へ重ねられます。末尾の待ち時間も、次の再生開始までの間隔に関わります。
- 高速な呼び出しに使うハンドルは、次の記録・削除で無効になります。記録をすべて終えてから取得する順序が大切です。
CPUが毎回作る出力列を、一度記録して使う
ARTIQのRTIO(Real-Time Input/Output)は、「いつ、どの出力を、どう変えるか」というイベントを受け取り、指定時刻に信号を変えます。CPUが命令を処理する瞬間と、端子の信号が変わる瞬間は別です。出力予定が現実の時計より先にあれば準備できますが、予定時刻を過ぎてからイベントを渡すと、RTIOUnderflowという例外になります。[1]
パルス間隔を詰めるほど、CPUには短い時間で次々とイベントを用意する力が要ります。DMAでは、この列をあらかじめSDRAMへ保存し、再生時は専用のDMA回路からRTIOへ送ります。同じ出力列を使う場面では、CPUが一件ずつ作る負担を減らせます。[2][3]
ただし、DMAが記録するのはプログラムそのものではありません。記録処理の中で値を計算して出力を選んだ場合、残るのはそのときに決まった出力イベントです。再生中の測定結果に応じて列の途中を組み替える用途とは分けて考えます。入力を読む処理もDMAへ記録されず、その場の実時間の入力処理として扱われます。[2]
記録の0時刻を、再生を始める位置へ重ねる
record()で記録区間へ入ると、予定時刻を示すカーソルが0になります。区間を出ると、記録を始める前のカーソルへ戻ります。記録中に進めた時間が、そのまま外側の予定時刻へ足されるわけではありません。[3][4]
たとえば、次の8 µs分の出力列を作るとします。これは時刻の読み方を示す仮想例で、装置で測った波形ではありません。
| 記録内の時刻 | 出力 | 100 µsから再生した場合 |
|---|---|---|
| 0 µs | Highにする | 100 µs |
| 2 µs | Lowにする | 102 µs |
| 5 µs | Highにする | 105 µs |
| 6 µs | Lowにする | 106 µs |
| 8 µs | 待ち時間の終わり | 次のカーソルは108 µs |
再生開始を100 µsから200 µsへ変えても、記録内の間隔は変わりません。また、最後にLowへ変える6 µsと、列の長さである8 µsは違います。最後の2 µsの待ち時間を含めてカーソルが進むので、間に別の遅延を入れず再生を続けるなら、次の列は108 µsから始まります。実装でも、開始時のカーソルを再生へ渡した後、記録した長さだけカーソルを進めています。[4]
ハンドルを取るのは、記録を終えてから
記録には名前を付けられます。playback("名前")で呼び出すほか、get_handle()で取得したハンドルをplayback_handle()へ渡す方法もあります。ハンドルは、記録を再生するための位置や長さなどをまとめた値です。繰り返し再生では名前から探す手間を省けますが、その有効期間をプログラム側で管理します。[3]
ここで注意したいのが、ハンドルを取った後に別の名前の列を記録しても、古いハンドルは無効になることです。公式仕様の有効期間は、次にrecord()またはerase()を呼ぶまで。参照した実装は、記録・削除のたびに共通の世代番号を進め、再生時に一致を確かめています。[3][4]
「列Aを記録→Aのハンドル取得→列Bを記録→Aを再生」という順序では、Aのハンドルをそのまま使えません。「列Aと列Bを記録→両方のハンドルを取得→再生」なら、記録による無効化を挟まずに使えます。途中で列を記録し直す場合は、その後に必要なハンドルを取り直します。同じ名前での記録は以前の列を上書きするので、名前だけで旧内容の保持を期待しないことも大切です。[3]
「再生関数が戻った」と「信号が出終わった」は違う
playback()は、列全体をRTIOの出力バッファへ渡すまで待ちます。これは、最後の信号が端子から出る時刻まで待つこととは違います。出力は予定時刻に実行されるため、後続処理で実時間の完了を待ちたい場合は、最後のイベント以後の時刻をcore.wait_until_mu()へ渡す、という区別が必要です。[1][3]
DMAを使っても、イベントの並び方や出力チャンネルの制約は残ります。同じ時刻付近へ出力を詰めすぎたり、時刻の順序に問題があったりする場合まで、記録と再生だけで解消できるわけではありません。まず、CPUによるイベント生成が追い付かないのか、それとも出力列自体に問題があるのかを分けると、対策を選びやすくなります。[1][2]
記録はカーネルの呼び出しをまたいで使えますが、装置の再起動をまたいでは残りません。再起動後は列を記録し直してから再生します。[2] 同じ列を繰り返す部分をDMAへ任せ、測定結果を見て次の列を選ぶ部分は別に組み立てる。その境目を決めることが、時間の詰まった実験手順を読みやすく保つ助けになります。
出典
参照版:ARTIQ公式ドキュメント 9.9698+a7303a7、2026年10月26日取得。以下は同じプロジェクトの仕様・実装を照合したもので、複数の独立した性能実験ではありません。装置の実測や性能倍率の検証は行っていません。
- ARTIQ Real-Time I/O concepts — Timeline and output events、Seamless handover and synchronization、エラーとバッファの説明。
- Getting started with the core device — Direct Memory Access (DMA) — 記録・再生、入力と再起動時の扱い。
- Core real-time drivers — CoreDMA — 各メソッドの仕様。
- Source code for artiq.coredevice.dma — 記録時間、再生時刻、ハンドルの世代管理。
