もともと、Linux Kernelのソースコードの一部なので、GPLv2扱いになる(はずの認識)。
https://www.kernel.org/doc/html/latest/index.html
Licensing documentation
The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text.
https://www.kernel.org/doc/html/latest/process/license-rules.html#kernel-licensing
https://www.kernel.org/doc/html/latest/timers/timekeeping.html
を読んでいく。
Clock sources, Clock events, sched_clock() and delay timers
This document tries to briefly explain some basic kernel timekeeping abstractions. It partly pertains to the drivers usually found in drivers/clocksource in the kernel tree, but the code may be spread out across the kernel.
このドキュメントでは、いくつかの基本的なKernelの、timekeeping abstractionsについて、簡単に説明をするものである。これはkernel treeにおいて通常drivers/clocksourceに配置される通常見つけられるドライバーと部分的に関連する。しかし、コードはカーネル全体に横断している場合がある。
If you grep through the kernel source you will find a number of architecture-specific implementations of clock sources, clockevents and several likewise architecture-specific overrides of the sched_clock() function and some delay timers.
kernel sourceをgrepすると、clock sourceやclockeventがアーキテクチャ依存な実装の数々を見つけることができるだろう。また、sche_clock() functionやいくつかのdelay timersに対して、アーキテクチャ依存なオーバーライドも見つけられるだろう。
To provide timekeeping for your platform, the clock source provides the basic timeline, whereas clock events shoot interrupts on certain points on this timeline, providing facilities such as high-resolution timers.
sched_clock() is used for scheduling and timestamping, and delay timers provide an accurate delay source using hardware counters.
あなたのプラットフォームにtimekeepingを提供するために、clock sourceは基本的なtimelineを提供する。クロックイベントはこのタイムラインの特定ポイントで、割り込みを発生させ、高解像度ライマーなどの機能を提供する。
shed_clock()はスケジューリングとタイムスタンプに使用される。delay timerは、ハードウェアカウンターを利用して正確な遅延ソースを提供する。
Clock sources
The purpose of the clock source is to provide a timeline for the system that tells you where you are in time. For example issuing the command 'date' on a Linux system will eventually read the clock source to determine exactly what time it is.
clock sourceの目的とは、システムのタイムラインを提供し、現在の時刻をあなたに通知する事です。例えば、linux systemにおいて'date' コマンドが実行されたら、厳密な現在時刻を特定するために、最終的にはclock sourceを読み出します。
Typically the clock source is a monotonic, atomic counter which will provide n bits which count from 0 to (2^n)-1 and then wraps around to 0 and start over.
It will ideally NEVER stop ticking as long as the system is running. It may stop during system suspend.
一般的にclock sourceは単調なアトミックカウンターです。n bitが与えられたときに0から(2^n)-1までカウントし、0にラップしてやり直します。
The clock source shall have as high resolution as possible, and the frequency shall be as stable and correct as possible as compared to a real-world wall clock. It should not move unpredictably back and forth in time or miss a few cycles here and there.
clock sourceは可能な限り高い分解能を持ち、周波数は現実世界のwall clockと比較してできるだけ安定で正確である必要があります。
It must be immune to the kind of effects that occur in hardware where e.g. the counter register is read in two phases on the bus lowest 16 bits first and the higher 16 bits in a second bus cycle with the counter bits potentially being updated in between leading to the risk of very strange values from the counter.
ハードウェアで発生する影響を受けないようにする必要があります。例えば、カウンターレジスターがバスの先に下位16bit、後で上位16bitの読み取る場合、カウンタービットは更新される恐れがあります。その時、カウンターからは奇妙な値が得られるリスクがあります。
When the wall-clock accuracy of the clock source isn't satisfactory, there are various quirks and layers in the timekeeping code for e.g. synchronizing the user-visible time to RTC clocks in the system or against networked time servers using NTP, but all they do basically is update an offset against the clock source, which provides the fundamental timeline for the system.
These measures does not affect the clock source per se, they only adapt the system to the shortcomings of it.
clock sourceのwall-clockとしての精度が満足いかない場合、timekeeping codeでは、様々なquirks(癖)やlayerがあります。ユーザーに見える時刻をシステム内のRTCクロックやNTPを使ってネットワーク化されたタイムサービスで同期することができます。ただし、これらは、システムの基本的なtimelineを提供するクロックソースに対するオフセットを更新するだけです。これらは、クロックソース自体に影響しません。システムをその欠点に適応させるだけです。
The clock source struct shall provide means to translate the provided counter into a nanosecond value as an unsigned long long (unsigned 64 bit) number.
clock source structは、与えられたカウンター値を、unsigned long long ( unsigned 64bit ) numberとしてnanosecond valueを変換する手段を提供します。
Since this operation may be invoked very often, doing this in a strict mathematical sense is not desirable: instead the number is taken as close as possible to a nanosecond value using only the arithmetic operations multiply and shift, so in clocksource_cyc2ns() you find:
この演算は非常に頻繁に呼び出されるため、厳密な数学的な意味で実行することは望ましくありません。代替手段として、算術演算の乗算とシフトのみを利用して、数値をナノ秒にできだけ近づけます。例えば、clocksource_cyc2ns() では以下を見つけることができます。
ns ~= (clocksource * mult) >> shift
You will find a number of helper functions in the clock source code intended to aid in providing these mult and shift values, such as clocksource_khz2mult(), clocksource_hz2mult() that help determine the mult factor from a fixed shift, and clocksource_register_hz() and clocksource_register_khz() which will help out assigning both shift and mult factors using the frequency of the clock source as the only input.
mult と shift valueの算出を支援する事を目的とした、clock source codeの中で、いくつものヘルパー関数を見つけることができるでしょう。例えば、 clocksource_khz2mult(), clocksource_hz2mult() は、固定されたshiftからmult 係数を決定するためのヘルパーです。clocksource_register_hz() と clocksource_register_khz() は、クロックソースの周波数を唯一の入力として用いて、shiftとmult係数を計算します。
For real simple clock sources accessed from a single I/O memory location there is nowadays even clocksource_mmio_init() which will take a memory location, bit width, a parameter telling whether the counter in the register counts up or down, and the timer clock rate, and then conjure all necessary parameters.
単一のI/O メモリアロケーションから、真に単純なクロックソースの場合、現在clocksource_mmio_init()があります。これは、メモリの位置、bit幅、レジスター値がカウントアップかカウントダウンかを示すぱためーたそしてタイマークロックレートを与えると、必要なすべてのパラメータを呼び出します。
Since a 32-bit counter at say 100 MHz will wrap around to zero after some 43 seconds, the code handling the clock source will have to compensate for this.
32 bit counterで100MHzで動く場合、0から43秒経過するとwrapします。クロックソースを処理するコードはこれを補正する必要があります。
That is the reason why the clock source struct also contains a 'mask' member telling how many bits of the source are valid. This way the timekeeping code knows when the counter will wrap around and can insert the necessary compensation code on both sides of the wrap point so that the system timeline remains monotonic.
これが、clock source 構造体に、"mask" memberが保持される理由になります。timekeeping codeでは、カウンターがwrap aroundするタイミングを認識し、必要となる補正コードをwrap pointの両端に挿入し、システムのtimelineが単調増加するようにします。
Clock events
Clock events are the conceptual reverse of clock sources: they take a desired time specification value and calculate the values to poke into hardware timer registers.
クロックイベントは、クロックソースの逆概念です。必要な時間指定値を取得し、ハードウェアタイマーレジスタに書き込む値を計算します。
Clock events are orthogonal to clock sources. The same hardware and register range may be used for the clock event, but it is essentially a different thing. The hardware driving clock events has to be able to fire interrupts, so as to trigger events on the system timeline. On an SMP system, it is ideal (and customary) to have one such event driving timer per CPU core, so that each core can trigger events independently of any other core.
クロックイベントは、クロックソースと直工しています。同じハードウェアとレジスタ範囲をクロックイベントは利用できますが、基本的には異なる。クロックイベントをドライブするハードウェアは、割り込みを発動させることで、system timelineにイベントを発動させます。SMPシステムでは、CPU Core事にそうしたタイマーを1つもつことが理想(かつ慣習)であり、各コアが他のコアとは独立してイベントをトリガーすることができます。
You will notice that the clock event device code is based on the same basic idea about translating counters to nanoseconds using mult and shift arithmetic, and you find the same family of helper functions again for assigning these values. The clock event driver does not need a 'mask' attribute however: the system will not try to plan events beyond the time horizon of the clock event.
クロックイベントデバイスのコードは、multとshift計算を用いたカウンター値をnano secondsに変換する基本的な考え方を有しており、これらの値を算出するための同じファミリーのヘルパー関数があります。ただし、クロックイベントドライバーには、"mask" 属性は必要ありません。システムは、クロックイベントの時間範囲を超えたイベントを計画しようとはしません。
sched_clock()
In addition to the clock sources and clock events there is a special weak function in the kernel called sched_clock(). This function shall return the number of nanoseconds since the system was started. An architecture may or may not provide an implementation of sched_clock() on its own. If a local implementation is not provided, the system jiffy counter will be used as sched_clock().
カーネルには、clock sourceとclock eventに加えて、sched_clock()という"弱い"関数があります。この関数は、システムが開始してからのnanosecondsを返すものです。architectureは、それ自体が、sched_clock()を実装してもしなくてもよいです。もし、ローカル実装がなされなかった場合、system jiffy counterが、sched_clock()のように扱われます。
As the name suggests, sched_clock() is used for scheduling the system, determining the absolute timeslice for a certain process in the CFS scheduler for example. It is also used for printk timestamps when you have selected to include time information in printk for things like bootcharts.
その名前が暗示するように、sched_clock()はシステムのスケジューリングに適用されます。例えば、CFS schedulerの特定プロセスにおける絶対タイムスライスの特定に用いられます。また、boot chardなどの情報をprintkに含める場合に、printk timestampにも用いられます。
Compared to clock sources, sched_clock() has to be very fast: it is called much more often, especially by the scheduler. If you have to do trade-offs between accuracy compared to the clock source, you may sacrifice accuracy for speed in sched_clock(). It however requires some of the same basic characteristics as the clock source, i.e. it should be monotonic.
clock sourceと比較して、sched_clock()は非常に高速でなければなりません。この関数は非常に多くの回数が呼ばれます。特にschedulerから呼ばれます。もし、クロックソースと比較して精度とのトレードオフを行う必要がある場合には、sched_clock()では精度よりも速度を優先すべきです。ただし、クロックソースと同じ基本的な特性が求められます。例えば、単調増加であることなど。
The sched_clock() function may wrap only on unsigned long long boundaries, i.e. after 64 bits. Since this is a nanosecond value this will mean it wraps after circa 585 years. (For most practical systems this means "never".)
sched_clock()関数は、unsigned long long boundary、つまり64bit以降でラップします。これは、nano second valueであるため、wrapは585年後になります(ほとんどの実際のシステムでは、これは"決して起きない"を意味します)。
If an architecture does not provide its own implementation of this function, it will fall back to using jiffies, making its maximum resolution 1/HZ of the jiffy frequency for the architecture. This will affect scheduling accuracy and will likely show up in system benchmarks.
architecureがこの関数を独自実装しない場合、jiffiesを使ってfall backします。つまり、その最大解像度を、architecureのjiffy frequencyの1/HZにします。これはスケジューリングの精度に影響し、システムのベンチマークに現れるかもしれません。
The clock driving sched_clock() may stop or reset to zero during system suspend/sleep. This does not matter to the function it serves of scheduling events on the system. However it may result in interesting timestamps in printk().
システムのサスペンド/スリープ中に、sched_clock()を起動するクロックが停止またはゼロにリセットされる場合があります。これは、システムでイベントをスケジュールする機能には関係ありません。ただし、printk()のtimestampが興味深い結果になるかもしれません。
The sched_clock() function should be callable in any context, IRQ- and NMI-safe and return a sane value in any context.
sched_clock()関数は、任意のコンテクストで動作できなければならず、IRQ-, NMI-safeであり、かつ、任意のコンテクストで正しい値を返さねばなりません。
Some architectures may have a limited set of time sources and lack a nice counter to derive a 64-bit nanosecond value, so for example on the ARM architecture, special helper functions have been created to provide a sched_clock() nanosecond base from a 16- or 32-bit counter. Sometimes the same counter that is also used as clock source is used for this purpose.
一部のアーキテクチャでは、タイムソースのセットが制限されており、64 bit nanosecondの値を算出するのに適切なカウンタがない場合があります。例えば、ARM architectureの場合には、sche_clock() が、16 もしくは 32bit counterからnano secondを算出できるようになっています。クロックソースで使われる同じカウンターがこの目的で使われる場合もあります。
On SMP systems, it is crucial for performance that sched_clock() can be called independently on each CPU without any synchronization performance hits.
Some hardware (such as the x86 TSC) will cause the sched_clock() function to drift between the CPUs on the system. The kernel can work around this by enabling the CONFIG_HAVE_UNSTABLE_SCHED_CLOCK option. This is another aspect that makes sched_clock() different from the ordinary clock source.
SMPシステムでは、sched_clock()が同期パフォーマンスに影響を与えることなく、それぞれのCPUで独立して呼び出せることが求められる。一部のハードウェア(x86 TSCなど)では、sched_clock()関数をシステム上のCPU間でドリフトさせます。カーネルは、CONFIG_HAVE_UNSTABLE_SCHED_CLOCK optionを有効にすることで、ワークアラウンドを有効かできます。これは、sche_clock()がclock sourceと異なる別の側面です。
Delay timers (some architectures only)
On systems with variable CPU frequency, the various kernel delay() functions will sometimes behave strangely. Basically these delays usually use a hard loop to delay a certain number of jiffy fractions using a "lpj" (loops per jiffy) value, calibrated on boot.
CPU周波数が可変であるシステムおいては、カーネルのdelay()関数が想定していない動作をすることがあります。基本的に、これらdelayはブート時に調整された"lpj" ( loops per jiffy)値を用いて、特定の数だけ遅延させます。
Let's hope that your system is running on maximum frequency when this value is calibrated: as an effect when the frequency is geared down to half the full frequency, any delay() will be twice as long. Usually this does not hurt, as you're commonly requesting that amount of delay or more. But basically the semantics are quite unpredictable on such systems.
この値を調整されている場合、システムが最大周波数で動作していることを期待しましょう。周波数が最大周波数の半分に調整されると、delay()は2倍の長さになります。通常delayでは「それ以上」を要求しているので、問題はありません。しかし、基本的にそのようおなシステムでは、セマンティクスは全く予想できないものになります。
Enter timer-based delays. Using these, a timer read may be used instead of a hard-coded loop for providing the desired delay.
timer-basedのdelayを導入しましょう、これを用いるとハードコードされたループの代わりに、タイマーを読み取って必要な遅延を実現できます。
This is done by declaring a struct delay_timer and assigning the appropriate function pointers and rate settings for this delay timer.
これは、struct delay_timerを宣言し、この遅延タイマーに適切な関数ポインターとrateを設定する事で、実現できます。
This is available on some architectures like OpenRISC or ARM.
これは、OpenRISCやARMのようなarchitectureで有効です。