オシロスコープを使用していくつかのピンを切り替えると、8バイトのUARTパケットが送信されてからブロッキング読み取りが返されるまで1〜2秒の遅延が発生することがあります。パケットは1秒の部分であり、数ミリ秒のジッター。strace
を使用してシステム呼び出しのタイミングも測定し(以下を参照)、結果はI/O測定と一致しました。
このレイテンシーがUARTドライバーにあるのか、それとも他のタスクが-20のniceness値を持つ私のタスクにぶつかっているのかを判断しようとしています。ドライバーについて疑問に思っている理由はこのコードの以前のバージョンでは、UARTを使用して、毎秒約26 kBのパケットを送信していました(ドライバーバッファーは4 kBです)。
プロセスは、pyserial
を使用するPythonスクリプトです。この失敗した場合、strace
はepoll_wait
とclock_gettime
の間の時間を報告します。 3秒以上として。
0.000883 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=8589934599}}) = -1 EEXIST (File exists)
0.000681 clock_gettime(CLOCK_MONOTONIC, {92406, 209555006}) = 0
0.000655 epoll_wait(3, {}, 64, 98) = 0
3.004082 clock_gettime(CLOCK_MONOTONIC, {92409, 214251206}) = 0
繰り返されるアクションは次のとおりです。8バイトのパケットを受信して、LinuxにSPIを介してNバイトを読み取るように要求します。 SPIを実行します。 8バイトのパケットを読み取って、SPI要求が正常に完了したかどうかを確認します。SPI転送には約40ミリ秒かかります。正常なパターンは、要求パケット間で約40ミリ秒です。そして結果パケット。そしてそれが次の要求を受け取るまで〜960ms。
Duchess: strace -r -e read -p 7564
Process 7564 attached
0.000000 read(7, "\355\336\255\336\20d\0\0", 8) = 8
0.049142 read(7, "\255\336\355\336\1\0\0\0", 8) = 8
0.950381 read(7, "\355\336\255\336\20d\0\0", 8) = 8
0.050035 read(7, "\255\336\355\336\1\0\0\0", 8) = 8
0.949962 read(7, "\355\336\255\336\20d\0\0", 8) = 8
0.049601 read(7, "\255\336\355\336\1\0\0\0", 8) = 8
0.950417 read(7, "\355\336\255\336\20d\0\0", 8) = 8
0.049654 read(7, "\255\336\355\336\1\0\0\0", 8) = 8
0.950507 read(7, "\355\336\255\336\20d\0\0", 8) = 80.950516 read(7, "\355\336\255\336\20d\0\0", 8) = 8 [SPI Request]
0.049944 read(7, "\255\336\355\336\1\0\0\0", 8) = 8 [Success]
2.196903 read(7, "\355\336\255\336\20d\0\0", 8) = 8 [SPI Request]
0.048876 read(7, "\255\336\355\336\0\0\0\0", 8) = 8 [Failure]
0.015570 read(7, "\355\336\255\336\20d\0\0", 8) = 8 [SPI Request]
0.053889 read(7, "\255\336\355\336\0\0\0\0", 8) = 8 [Failure]
0.634720 read(7, "\355\336\255\336\20d\0\0", 8) = 8 [SPI Request]
0.050070 read(7, "\255\336\355\336\1\0\0\0", 8) = 8 [Success]
strace
は、必要なレベルの詳細を提供しない可能性があります。何が起こっているかをより正確に示すには、おそらくSystemTap、sysdig、または同様のカーネルレベルのデバッグが必要になります。たとえば、SystemTapがインストールされていて、必要なすべてのdebuginfoとセットアップの詳細が処理されている場合、次のように開始できます。
probe begin
{
printf("%-16s %s\n", "TIME", "WHAT");
}
probe tty.{ioctl,receive}
{
if (pid() != target()) next;
printf("%d ttyx %s\n", gettimeofday_us(), name);
}
probe tty.poll
{
if (pid() != target()) next;
printf("%d ttypoll %s\n", gettimeofday_us(), file_name);
}
probe tty.{read,write}
{
if (pid() != target()) next;
printf("%d ttyio %s %d\n", gettimeofday_us(), file_name, nr);
}
probe syscall.{read,write,epoll_*}
{
if (pid() != target()) next;
printf("%d syscall %s\tenter\n", gettimeofday_us(), name);
}
probe syscall.{read,write,epoll_*}.return
{
if (pid() != target()) next;
printf("%d syscall %s\treturn\n", gettimeofday_us(), name);
}
経由でそれを実行します
$ Sudo stap -x "$(pidof ...)" filecontainingtheabovecode.stp
シリアルテストプログラム および 添付のArduino の場合、次のように表示されます。
TIME WHAT
1516997916648359 syscall read enter
1516997916648366 ttyio ttyACM0 4096
1516997916652456 syscall read return
1516997916652465 syscall read enter
1516997916652470 ttyio ttyACM0 4096
1516997916656459 syscall read return
1516997916656497 syscall write enter
1516997916656503 ttyio 4 21
1516997916656511 syscall write return
...
上記で遅延がどこにあるかが示されていない場合は、他の関心のあるプローブポイント(スケジューラ、I/Oスケジューラ、IRQ?)についてSystemTapタップセットのドキュメントを参照する必要がある場合もあります。そして、おそらくタイミングを古いバージョンのコード/ドライバー/システムと比較するために...