mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
Merge pull request #14002 from luiscape:luis/allign-clocks-in-capprofiling
PiperOrigin-RevId: 968200399
This commit is contained in:
@@ -93,7 +93,7 @@ func Boot() (*kernel.Kernel, error) {
|
|||||||
// Create timekeeper.
|
// Create timekeeper.
|
||||||
tk := kernel.NewTimekeeper()
|
tk := kernel.NewTimekeeper()
|
||||||
params := kernel.NewVDSOParamPage(k.MemoryFile(), vdso.ParamPage.FileRange())
|
params := kernel.NewVDSOParamPage(k.MemoryFile(), vdso.ParamPage.FileRange())
|
||||||
tk.SetClocks(time.NewCalibratedClocks(), params)
|
tk.SetClocks(time.NewCalibratedClocks(false), params)
|
||||||
|
|
||||||
creds := auth.NewRootCredentials(auth.NewRootUserNamespace())
|
creds := auth.NewRootCredentials(auth.NewRootUserNamespace())
|
||||||
|
|
||||||
|
|||||||
@@ -1936,6 +1936,15 @@ func (k *Kernel) MonotonicClock() ktime.SampledClock {
|
|||||||
return k.timekeeper.monotonicClock
|
return k.timekeeper.monotonicClock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MonotonicRawClock returns the system CLOCK_MONOTONIC_RAW clock. When it is
|
||||||
|
// not enabled as a distinct clock this is the same as MonotonicClock.
|
||||||
|
func (k *Kernel) MonotonicRawClock() ktime.SampledClock {
|
||||||
|
if k.timekeeper.monotonicRawClock != nil {
|
||||||
|
return k.timekeeper.monotonicRawClock
|
||||||
|
}
|
||||||
|
return k.timekeeper.monotonicClock
|
||||||
|
}
|
||||||
|
|
||||||
// Syslog returns the syslog.
|
// Syslog returns the syslog.
|
||||||
func (k *Kernel) Syslog() *syslog {
|
func (k *Kernel) Syslog() *syslog {
|
||||||
return &k.syslog
|
return &k.syslog
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ type Timekeeper struct {
|
|||||||
// monotonicClock is a ktime.Clock based on timekeeper's Monotonic.
|
// monotonicClock is a ktime.Clock based on timekeeper's Monotonic.
|
||||||
monotonicClock *timekeeperClock
|
monotonicClock *timekeeperClock
|
||||||
|
|
||||||
|
// monotonicRawClock is a ktime.Clock based on timekeeper's MonotonicRaw.
|
||||||
|
// It is non-nil only when the clock source tracks a distinct
|
||||||
|
// CLOCK_MONOTONIC_RAW; otherwise CLOCK_MONOTONIC_RAW aliases
|
||||||
|
// CLOCK_MONOTONIC. It is derived by SetClocks, anew on restore.
|
||||||
|
monotonicRawClock *timekeeperClock `state:"nosave"`
|
||||||
|
|
||||||
// bootTime is the realtime when the system "booted". i.e., when
|
// bootTime is the realtime when the system "booted". i.e., when
|
||||||
// SetClocks was called in the initial (not restored) run.
|
// SetClocks was called in the initial (not restored) run.
|
||||||
bootTime ktime.Time
|
bootTime ktime.Time
|
||||||
@@ -158,6 +164,14 @@ func (t *Timekeeper) SetClocks(c sentrytime.Clocks, params *VDSOParamPage) {
|
|||||||
|
|
||||||
t.clocks = c
|
t.clocks = c
|
||||||
|
|
||||||
|
// Serve CLOCK_MONOTONIC_RAW as a distinct clock iff the clock source
|
||||||
|
// tracks it (see NewCalibratedClocks). Deriving this from the source keeps
|
||||||
|
// boot and restore coherent: a restored sandbox follows its current
|
||||||
|
// configuration, not the checkpointed one.
|
||||||
|
if c.MonotonicRawEnabled() {
|
||||||
|
t.monotonicRawClock = &timekeeperClock{tk: t, c: sentrytime.MonotonicRaw}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the offset of the monotonic clock from the base Clocks.
|
// Compute the offset of the monotonic clock from the base Clocks.
|
||||||
//
|
//
|
||||||
// In a fresh (not restored) sentry, monotonic time starts at zero.
|
// In a fresh (not restored) sentry, monotonic time starts at zero.
|
||||||
@@ -213,20 +227,30 @@ func (t *Timekeeper) update(parked bool) {
|
|||||||
// Call Update within a Write block to prevent the VDSO from using the old
|
// Call Update within a Write block to prevent the VDSO from using the old
|
||||||
// params between Update and Write.
|
// params between Update and Write.
|
||||||
if err := t.params.Write(func() vdsoParams {
|
if err := t.params.Write(func() vdsoParams {
|
||||||
monotonicParams, monotonicOk, realtimeParams, realtimeOk := t.clocks.Update(parked)
|
res := t.clocks.Update(parked)
|
||||||
|
|
||||||
var p vdsoParams
|
var p vdsoParams
|
||||||
if monotonicOk {
|
if res.MonotonicOk {
|
||||||
p.monotonicReady = 1
|
p.monotonicReady = 1
|
||||||
p.monotonicBaseCycles = int64(monotonicParams.BaseCycles)
|
p.monotonicBaseCycles = int64(res.Monotonic.BaseCycles)
|
||||||
p.monotonicBaseRef = int64(monotonicParams.BaseRef) + t.monotonicOffset
|
p.monotonicBaseRef = int64(res.Monotonic.BaseRef) + t.monotonicOffset
|
||||||
p.monotonicFrequency = monotonicParams.Frequency
|
p.monotonicFrequency = res.Monotonic.Frequency
|
||||||
}
|
}
|
||||||
if realtimeOk {
|
if res.RealtimeOk {
|
||||||
p.realtimeReady = 1
|
p.realtimeReady = 1
|
||||||
p.realtimeBaseCycles = int64(realtimeParams.BaseCycles)
|
p.realtimeBaseCycles = int64(res.Realtime.BaseCycles)
|
||||||
p.realtimeBaseRef = int64(realtimeParams.BaseRef)
|
p.realtimeBaseRef = int64(res.Realtime.BaseRef)
|
||||||
p.realtimeFrequency = realtimeParams.Frequency
|
p.realtimeFrequency = res.Realtime.Frequency
|
||||||
|
}
|
||||||
|
if t.monotonicRawClock == nil {
|
||||||
|
p.monotonicRawAlias = 1
|
||||||
|
} else if res.MonotonicRawOk {
|
||||||
|
// Raw tracks absolute host CLOCK_MONOTONIC_RAW, so unlike
|
||||||
|
// monotonic its base ref is published without monotonicOffset.
|
||||||
|
p.monotonicRawReady = 1
|
||||||
|
p.monotonicRawBaseCycles = int64(res.MonotonicRaw.BaseCycles)
|
||||||
|
p.monotonicRawBaseRef = int64(res.MonotonicRaw.BaseRef)
|
||||||
|
p.monotonicRawFrequency = res.MonotonicRaw.Frequency
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -397,6 +421,9 @@ func (t *Timekeeper) GetTime(c sentrytime.ClockID) (int64, error) {
|
|||||||
}
|
}
|
||||||
<-t.restored
|
<-t.restored
|
||||||
}
|
}
|
||||||
|
if c == sentrytime.MonotonicRaw && t.monotonicRawClock == nil {
|
||||||
|
c = sentrytime.Monotonic
|
||||||
|
}
|
||||||
|
|
||||||
// update the calibration if needed and keep the timekeeper calibrated
|
// update the calibration if needed and keep the timekeeper calibrated
|
||||||
// during the read
|
// during the read
|
||||||
|
|||||||
@@ -28,13 +28,20 @@ import (
|
|||||||
// mockClocks is a sentrytime.Clocks that simply returns the times in the
|
// mockClocks is a sentrytime.Clocks that simply returns the times in the
|
||||||
// struct.
|
// struct.
|
||||||
type mockClocks struct {
|
type mockClocks struct {
|
||||||
monotonic int64
|
monotonic int64
|
||||||
realtime int64
|
realtime int64
|
||||||
|
monotonicRaw int64
|
||||||
|
monotonicRawEnabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements sentrytime.Clocks.Update. It does nothing.
|
// Update implements sentrytime.Clocks.Update. It does nothing.
|
||||||
func (*mockClocks) Update(parked bool) (monotonicParams sentrytime.Parameters, monotonicOk bool, realtimeParam sentrytime.Parameters, realtimeOk bool) {
|
func (*mockClocks) Update(parked bool) sentrytime.UpdateResult {
|
||||||
return
|
return sentrytime.UpdateResult{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonotonicRawEnabled implements sentrytime.Clocks.MonotonicRawEnabled.
|
||||||
|
func (c *mockClocks) MonotonicRawEnabled() bool {
|
||||||
|
return c.monotonicRawEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTime implements sentrytime.Clocks.GetTime.
|
// GetTime implements sentrytime.Clocks.GetTime.
|
||||||
@@ -44,6 +51,11 @@ func (c *mockClocks) GetTime(id sentrytime.ClockID) (int64, error) {
|
|||||||
return c.monotonic, nil
|
return c.monotonic, nil
|
||||||
case sentrytime.Realtime:
|
case sentrytime.Realtime:
|
||||||
return c.realtime, nil
|
return c.realtime, nil
|
||||||
|
case sentrytime.MonotonicRaw:
|
||||||
|
if c.monotonicRawEnabled {
|
||||||
|
return c.monotonicRaw, nil
|
||||||
|
}
|
||||||
|
return 0, linuxerr.EINVAL
|
||||||
default:
|
default:
|
||||||
return 0, linuxerr.EINVAL
|
return 0, linuxerr.EINVAL
|
||||||
}
|
}
|
||||||
@@ -64,7 +76,7 @@ func stateTestClocklessTimekeeper(tb testing.TB) (*Timekeeper, *VDSOParamPage) {
|
|||||||
|
|
||||||
func stateTestTimekeeper(tb testing.TB) *Timekeeper {
|
func stateTestTimekeeper(tb testing.TB) *Timekeeper {
|
||||||
t, params := stateTestClocklessTimekeeper(tb)
|
t, params := stateTestClocklessTimekeeper(tb)
|
||||||
t.SetClocks(sentrytime.NewCalibratedClocks(), params)
|
t.SetClocks(sentrytime.NewCalibratedClocks(false), params)
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,3 +165,44 @@ func TestTimekeeperMonotonicJumpBackwards(t *testing.T) {
|
|||||||
t.Errorf("GetTime got %d want 100000", now)
|
t.Errorf("GetTime got %d want 100000", now)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestTimekeeperMonotonicRawEnabled tests that when the clock source tracks a
|
||||||
|
// distinct CLOCK_MONOTONIC_RAW, GetTime exposes it directly (absolute, not
|
||||||
|
// starting at zero), while CLOCK_MONOTONIC is unaffected.
|
||||||
|
func TestTimekeeperMonotonicRawEnabled(t *testing.T) {
|
||||||
|
c := &mockClocks{
|
||||||
|
monotonic: 100000,
|
||||||
|
monotonicRaw: 999999,
|
||||||
|
monotonicRawEnabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
tk, params := stateTestClocklessTimekeeper(t)
|
||||||
|
tk.SetClocks(c, params)
|
||||||
|
defer tk.Destroy()
|
||||||
|
|
||||||
|
// Monotonic is unaffected: still starts at zero.
|
||||||
|
if now, err := tk.GetTime(sentrytime.Monotonic); err != nil || now != 0 {
|
||||||
|
t.Errorf("GetTime(Monotonic) got (%d, %v) want (0, nil)", now, err)
|
||||||
|
}
|
||||||
|
// MonotonicRaw exposes the raw source's absolute value.
|
||||||
|
if now, err := tk.GetTime(sentrytime.MonotonicRaw); err != nil || now != 999999 {
|
||||||
|
t.Errorf("GetTime(MonotonicRaw) got (%d, %v) want (999999, nil)", now, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTimekeeperMonotonicRawDisabled tests that when the clock source does not
|
||||||
|
// track CLOCK_MONOTONIC_RAW, it aliases CLOCK_MONOTONIC.
|
||||||
|
func TestTimekeeperMonotonicRawDisabled(t *testing.T) {
|
||||||
|
c := &mockClocks{
|
||||||
|
monotonic: 100000,
|
||||||
|
}
|
||||||
|
|
||||||
|
tk, params := stateTestClocklessTimekeeper(t)
|
||||||
|
tk.SetClocks(c, params)
|
||||||
|
defer tk.Destroy()
|
||||||
|
|
||||||
|
// MonotonicRaw aliases Monotonic: both start at zero.
|
||||||
|
if now, err := tk.GetTime(sentrytime.MonotonicRaw); err != nil || now != 0 {
|
||||||
|
t.Errorf("GetTime(MonotonicRaw) got (%d, %v) want (0, nil)", now, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ type vdsoParams struct {
|
|||||||
realtimeBaseCycles int64
|
realtimeBaseCycles int64
|
||||||
realtimeBaseRef int64
|
realtimeBaseRef int64
|
||||||
realtimeFrequency uint64
|
realtimeFrequency uint64
|
||||||
|
|
||||||
|
monotonicRawAlias uint64
|
||||||
|
monotonicRawReady uint64
|
||||||
|
monotonicRawBaseCycles int64
|
||||||
|
monotonicRawBaseRef int64
|
||||||
|
monotonicRawFrequency uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// VDSOParamPage manages a VDSO parameter page.
|
// VDSOParamPage manages a VDSO parameter page.
|
||||||
|
|||||||
@@ -123,9 +123,10 @@ func getClock(t *kernel.Task, clockID int32) (ktime.Clock, error) {
|
|||||||
switch clockID {
|
switch clockID {
|
||||||
case linux.CLOCK_REALTIME, linux.CLOCK_REALTIME_COARSE:
|
case linux.CLOCK_REALTIME, linux.CLOCK_REALTIME_COARSE:
|
||||||
return t.Kernel().RealtimeClock(), nil
|
return t.Kernel().RealtimeClock(), nil
|
||||||
|
case linux.CLOCK_MONOTONIC_RAW:
|
||||||
|
return t.Kernel().MonotonicRawClock(), nil
|
||||||
case linux.CLOCK_MONOTONIC, linux.CLOCK_MONOTONIC_COARSE,
|
case linux.CLOCK_MONOTONIC, linux.CLOCK_MONOTONIC_COARSE,
|
||||||
linux.CLOCK_MONOTONIC_RAW, linux.CLOCK_BOOTTIME:
|
linux.CLOCK_BOOTTIME:
|
||||||
// CLOCK_MONOTONIC approximates CLOCK_MONOTONIC_RAW.
|
|
||||||
// CLOCK_BOOTTIME is internally mapped to CLOCK_MONOTONIC, as:
|
// CLOCK_BOOTTIME is internally mapped to CLOCK_MONOTONIC, as:
|
||||||
// - CLOCK_BOOTTIME should behave as CLOCK_MONOTONIC while also
|
// - CLOCK_BOOTTIME should behave as CLOCK_MONOTONIC while also
|
||||||
// including suspend time.
|
// including suspend time.
|
||||||
|
|||||||
@@ -105,6 +105,12 @@ func TimerCreate(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uin
|
|||||||
sevp := args[1].Pointer()
|
sevp := args[1].Pointer()
|
||||||
timerIDp := args[2].Pointer()
|
timerIDp := args[2].Pointer()
|
||||||
|
|
||||||
|
// Linux's clock_monotonic_raw k_clock only defines clock_getres and
|
||||||
|
// clock_get_timespec, so timer_create(CLOCK_MONOTONIC_RAW) is rejected.
|
||||||
|
if clockID == linux.CLOCK_MONOTONIC_RAW {
|
||||||
|
return 0, nil, linuxerr.EOPNOTSUPP
|
||||||
|
}
|
||||||
|
|
||||||
c, err := getClock(t, clockID)
|
c, err := getClock(t, clockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
|
|||||||
@@ -234,22 +234,41 @@ type CalibratedClocks struct {
|
|||||||
|
|
||||||
// realtime is the realtime equivalent of monotonic.
|
// realtime is the realtime equivalent of monotonic.
|
||||||
realtime *CalibratedClock
|
realtime *CalibratedClock
|
||||||
|
|
||||||
|
// monotonicRaw tracks the host CLOCK_MONOTONIC_RAW clock. It is nil unless
|
||||||
|
// enabled via NewCalibratedClocks.
|
||||||
|
monotonicRaw *CalibratedClock
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCalibratedClocks creates a CalibratedClocks.
|
// NewCalibratedClocks creates a CalibratedClocks. If monotonicRawEnabled is
|
||||||
func NewCalibratedClocks() *CalibratedClocks {
|
// true, host CLOCK_MONOTONIC_RAW is additionally tracked as a distinct clock
|
||||||
return &CalibratedClocks{
|
// (addressable as MonotonicRaw).
|
||||||
|
func NewCalibratedClocks(monotonicRawEnabled bool) *CalibratedClocks {
|
||||||
|
c := &CalibratedClocks{
|
||||||
monotonic: NewCalibratedClock(Monotonic),
|
monotonic: NewCalibratedClock(Monotonic),
|
||||||
realtime: NewCalibratedClock(Realtime),
|
realtime: NewCalibratedClock(Realtime),
|
||||||
}
|
}
|
||||||
|
if monotonicRawEnabled {
|
||||||
|
c.monotonicRaw = NewCalibratedClock(MonotonicRaw)
|
||||||
|
}
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements Clocks.Update.
|
// Update implements Clocks.Update.
|
||||||
func (c *CalibratedClocks) Update(parked bool) (Parameters, bool, Parameters, bool) {
|
func (c *CalibratedClocks) Update(parked bool) UpdateResult {
|
||||||
monotonicParams, monotonicOk := c.monotonic.Update(parked)
|
var res UpdateResult
|
||||||
realtimeParams, realtimeOk := c.realtime.Update(parked)
|
res.Monotonic, res.MonotonicOk = c.monotonic.Update(parked)
|
||||||
|
res.Realtime, res.RealtimeOk = c.realtime.Update(parked)
|
||||||
|
if c.monotonicRaw != nil {
|
||||||
|
res.MonotonicRaw, res.MonotonicRawOk = c.monotonicRaw.Update(parked)
|
||||||
|
}
|
||||||
|
|
||||||
return monotonicParams, monotonicOk, realtimeParams, realtimeOk
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// MonotonicRawEnabled implements Clocks.MonotonicRawEnabled.
|
||||||
|
func (c *CalibratedClocks) MonotonicRawEnabled() bool {
|
||||||
|
return c.monotonicRaw != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTime implements Clocks.GetTime.
|
// GetTime implements Clocks.GetTime.
|
||||||
@@ -259,6 +278,11 @@ func (c *CalibratedClocks) GetTime(id ClockID) (int64, error) {
|
|||||||
return c.monotonic.GetTime()
|
return c.monotonic.GetTime()
|
||||||
case Realtime:
|
case Realtime:
|
||||||
return c.realtime.GetTime()
|
return c.realtime.GetTime()
|
||||||
|
case MonotonicRaw:
|
||||||
|
if c.monotonicRaw != nil {
|
||||||
|
return c.monotonicRaw.GetTime()
|
||||||
|
}
|
||||||
|
return 0, linuxerr.EINVAL
|
||||||
default:
|
default:
|
||||||
return 0, linuxerr.EINVAL
|
return 0, linuxerr.EINVAL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ type ClockID int32
|
|||||||
|
|
||||||
// These are the supported Linux clock identifiers.
|
// These are the supported Linux clock identifiers.
|
||||||
const (
|
const (
|
||||||
Realtime ClockID = iota
|
Realtime ClockID = 0
|
||||||
Monotonic
|
Monotonic ClockID = 1
|
||||||
|
MonotonicRaw ClockID = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
// String implements fmt.Stringer.String.
|
// String implements fmt.Stringer.String.
|
||||||
@@ -34,6 +35,8 @@ func (c ClockID) String() string {
|
|||||||
return "Realtime"
|
return "Realtime"
|
||||||
case Monotonic:
|
case Monotonic:
|
||||||
return "Monotonic"
|
return "Monotonic"
|
||||||
|
case MonotonicRaw:
|
||||||
|
return "MonotonicRaw"
|
||||||
default:
|
default:
|
||||||
return strconv.Itoa(int(c))
|
return strconv.Itoa(int(c))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,21 @@
|
|||||||
|
|
||||||
package time
|
package time
|
||||||
|
|
||||||
|
// UpdateResult holds the timekeeping parameters produced by Clocks.Update.
|
||||||
|
//
|
||||||
|
// Each *Ok field reports whether the corresponding *Params were successfully
|
||||||
|
// calibrated and may be published to the VDSO. MonotonicRaw is only populated
|
||||||
|
// by clock sources that track a distinct CLOCK_MONOTONIC_RAW; otherwise
|
||||||
|
// MonotonicRawOk is false.
|
||||||
|
type UpdateResult struct {
|
||||||
|
Monotonic Parameters
|
||||||
|
MonotonicOk bool
|
||||||
|
Realtime Parameters
|
||||||
|
RealtimeOk bool
|
||||||
|
MonotonicRaw Parameters
|
||||||
|
MonotonicRawOk bool
|
||||||
|
}
|
||||||
|
|
||||||
// Clocks represents a clock source that contains both a monotonic and realtime
|
// Clocks represents a clock source that contains both a monotonic and realtime
|
||||||
// clock.
|
// clock.
|
||||||
type Clocks interface {
|
type Clocks interface {
|
||||||
@@ -23,11 +38,18 @@ type Clocks interface {
|
|||||||
// Update should be called at approximately ApproxUpdateInterval.
|
// Update should be called at approximately ApproxUpdateInterval.
|
||||||
//
|
//
|
||||||
// parked indicates that the clock was not read for at least ApproxUpdateInterval
|
// parked indicates that the clock was not read for at least ApproxUpdateInterval
|
||||||
Update(parked bool) (monotonicParams Parameters, monotonicOk bool, realtimeParam Parameters, realtimeOk bool)
|
Update(parked bool) UpdateResult
|
||||||
|
|
||||||
// GetTime returns the current time in nanoseconds for the given clock.
|
// GetTime returns the current time in nanoseconds for the given clock.
|
||||||
//
|
//
|
||||||
// Clocks implementations must support at least Monotonic and
|
// Clocks implementations must support at least Monotonic and
|
||||||
// Realtime.
|
// Realtime.
|
||||||
GetTime(c ClockID) (int64, error)
|
GetTime(c ClockID) (int64, error)
|
||||||
|
|
||||||
|
// MonotonicRawEnabled reports whether this clock source tracks a distinct
|
||||||
|
// CLOCK_MONOTONIC_RAW, i.e. whether GetTime(MonotonicRaw) returns the
|
||||||
|
// host's absolute CLOCK_MONOTONIC_RAW rather than aliasing Monotonic.
|
||||||
|
//
|
||||||
|
// It must return the same value for the lifetime of the Clocks.
|
||||||
|
MonotonicRawEnabled() bool
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-1
@@ -545,6 +545,23 @@ func getRootCredentials(spec *specs.Spec, conf *config.Config, userNs *auth.User
|
|||||||
return creds
|
return creds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shouldEnableClockMonotonicRaw reports whether CLOCK_MONOTONIC_RAW should be
|
||||||
|
// exposed as a distinct clock tracking the host's CLOCK_MONOTONIC_RAW, rather
|
||||||
|
// than aliasing CLOCK_MONOTONIC as it does by default.
|
||||||
|
//
|
||||||
|
// This exists for GPU profiling: profilers such as Nsight Systems/CUPTI anchor
|
||||||
|
// the GPU timeline in the host's CLOCK_MONOTONIC_RAW domain, which drifts from
|
||||||
|
// CLOCK_MONOTONIC by NTP frequency adjustment. When nvproxy grants
|
||||||
|
// CapProfiling, the sandbox must therefore serve a CLOCK_MONOTONIC_RAW in that
|
||||||
|
// same (absolute, unadjusted) domain. It is enabled only in that case.
|
||||||
|
func shouldEnableClockMonotonicRaw(spec *specs.Spec, conf *config.Config) bool {
|
||||||
|
if !specutils.NVProxyEnabled(spec, conf) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
caps, err := specutils.NVProxyDriverCapsAllowed(conf)
|
||||||
|
return err == nil && caps&nvconf.CapProfiling != 0
|
||||||
|
}
|
||||||
|
|
||||||
// New initializes a new kernel loader configured by spec.
|
// New initializes a new kernel loader configured by spec.
|
||||||
// New also handles setting up a kernel for restoring a container.
|
// New also handles setting up a kernel for restoring a container.
|
||||||
func New(args Args) (*Loader, error) {
|
func New(args Args) (*Loader, error) {
|
||||||
@@ -733,7 +750,7 @@ func New(args Args) (*Loader, error) {
|
|||||||
// Create timekeeper.
|
// Create timekeeper.
|
||||||
tk := kernel.NewTimekeeper()
|
tk := kernel.NewTimekeeper()
|
||||||
params := kernel.NewVDSOParamPage(l.k.MemoryFile(), vdso.ParamPage.FileRange())
|
params := kernel.NewVDSOParamPage(l.k.MemoryFile(), vdso.ParamPage.FileRange())
|
||||||
tk.SetClocks(time.NewCalibratedClocks(), params)
|
tk.SetClocks(time.NewCalibratedClocks(shouldEnableClockMonotonicRaw(args.Spec, args.Conf)), params)
|
||||||
args.StartupTimer.Reached("timekeeper configured")
|
args.StartupTimer.Reached("timekeeper configured")
|
||||||
|
|
||||||
if err := enableStrace(args.Conf); err != nil {
|
if err := enableStrace(args.Conf); err != nil {
|
||||||
|
|||||||
@@ -479,15 +479,16 @@ func (r *restorer) restore(l *Loader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the state.
|
// Load the state.
|
||||||
|
clocks := time.NewCalibratedClocks(shouldEnableClockMonotonicRaw(l.root.spec, l.root.conf))
|
||||||
r.timer.Reached("loading kernel")
|
r.timer.Reached("loading kernel")
|
||||||
if r.extractRootFsMode {
|
if r.extractRootFsMode {
|
||||||
if err := l.k.ExtractRootfsUpperLayer(ctx, r.stateFile, r.asyncMFLoader, nil, time.NewCalibratedClocks(), r.rootFsOutputTar); err != nil {
|
if err := l.k.ExtractRootfsUpperLayer(ctx, r.stateFile, r.asyncMFLoader, nil, clocks, r.rootFsOutputTar); err != nil {
|
||||||
return fmt.Errorf("failed to extract rootfs upper layer: %w", err)
|
return fmt.Errorf("failed to extract rootfs upper layer: %w", err)
|
||||||
}
|
}
|
||||||
r.timer.Reached("rootfs upper layer extracted")
|
r.timer.Reached("rootfs upper layer extracted")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := l.k.LoadFrom(ctx, r.stateFile, r.asyncMFLoader, nil, l, time.NewCalibratedClocks(), &vfs.CompleteRestoreOptions{}, r.timer.Fork("kernel load")); err != nil {
|
if err := l.k.LoadFrom(ctx, r.stateFile, r.asyncMFLoader, nil, l, clocks, &vfs.CompleteRestoreOptions{}, r.timer.Fork("kernel load")); err != nil {
|
||||||
return fmt.Errorf("failed to load kernel: %w", err)
|
return fmt.Errorf("failed to load kernel: %w", err)
|
||||||
}
|
}
|
||||||
r.timer.Reached("kernel loaded")
|
r.timer.Reached("kernel loaded")
|
||||||
|
|||||||
+4
-2
@@ -35,10 +35,12 @@ int __common_clock_gettime(clockid_t clock, struct timespec* ts) {
|
|||||||
ret = ClockRealtime(ts);
|
ret = ClockRealtime(ts);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CLOCK_MONOTONIC_RAW:
|
||||||
|
ret = ClockMonotonicRaw(ts);
|
||||||
|
break;
|
||||||
|
|
||||||
case CLOCK_BOOTTIME:
|
case CLOCK_BOOTTIME:
|
||||||
// Fallthrough, CLOCK_BOOTTIME is an alias for CLOCK_MONOTONIC
|
// Fallthrough, CLOCK_BOOTTIME is an alias for CLOCK_MONOTONIC
|
||||||
case CLOCK_MONOTONIC_RAW:
|
|
||||||
// Fallthrough, CLOCK_MONOTONIC_RAW is an alias for CLOCK_MONOTONIC
|
|
||||||
case CLOCK_MONOTONIC_COARSE:
|
case CLOCK_MONOTONIC_COARSE:
|
||||||
// Fallthrough, CLOCK_MONOTONIC_COARSE is an alias for CLOCK_MONOTONIC
|
// Fallthrough, CLOCK_MONOTONIC_COARSE is an alias for CLOCK_MONOTONIC
|
||||||
case CLOCK_MONOTONIC:
|
case CLOCK_MONOTONIC:
|
||||||
|
|||||||
+60
-8
@@ -41,6 +41,12 @@ struct params {
|
|||||||
int64_t realtime_base_cycles;
|
int64_t realtime_base_cycles;
|
||||||
int64_t realtime_base_ref;
|
int64_t realtime_base_ref;
|
||||||
uint64_t realtime_frequency;
|
uint64_t realtime_frequency;
|
||||||
|
|
||||||
|
uint64_t monotonic_raw_alias;
|
||||||
|
uint64_t monotonic_raw_ready;
|
||||||
|
int64_t monotonic_raw_base_cycles;
|
||||||
|
int64_t monotonic_raw_base_ref;
|
||||||
|
uint64_t monotonic_raw_frequency;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a pointer to the global parameter page.
|
// Returns a pointer to the global parameter page.
|
||||||
@@ -91,6 +97,14 @@ inline uint64_t cycles_to_ns(uint64_t frequency, uint64_t cycles) {
|
|||||||
return ((unsigned __int128)cycles * mult) >> 32;
|
return ((unsigned __int128)cycles * mult) >> 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compute_time projects a calibrated clock's base to now_cycles.
|
||||||
|
inline int64_t compute_time(int64_t base_ref, int64_t base_cycles,
|
||||||
|
uint64_t frequency, int64_t now_cycles) {
|
||||||
|
int64_t delta_cycles =
|
||||||
|
(now_cycles < base_cycles) ? 0 : now_cycles - base_cycles;
|
||||||
|
return base_ref + cycles_to_ns(frequency, delta_cycles);
|
||||||
|
}
|
||||||
|
|
||||||
// ClockRealtime() is the VDSO implementation of clock_gettime(CLOCK_REALTIME).
|
// ClockRealtime() is the VDSO implementation of clock_gettime(CLOCK_REALTIME).
|
||||||
int ClockRealtime(struct timespec* ts) {
|
int ClockRealtime(struct timespec* ts) {
|
||||||
struct params* params = get_params();
|
struct params* params = get_params();
|
||||||
@@ -116,10 +130,8 @@ int ClockRealtime(struct timespec* ts) {
|
|||||||
return sys_clock_gettime(CLOCK_REALTIME, ts);
|
return sys_clock_gettime(CLOCK_REALTIME, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t delta_cycles =
|
*ts = ns_to_timespec(
|
||||||
(now_cycles < base_cycles) ? 0 : now_cycles - base_cycles;
|
compute_time(base_ref, base_cycles, frequency, now_cycles));
|
||||||
int64_t now_ns = base_ref + cycles_to_ns(frequency, delta_cycles);
|
|
||||||
*ts = ns_to_timespec(now_ns);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,10 +161,50 @@ int ClockMonotonic(struct timespec* ts) {
|
|||||||
return sys_clock_gettime(CLOCK_MONOTONIC, ts);
|
return sys_clock_gettime(CLOCK_MONOTONIC, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t delta_cycles =
|
*ts = ns_to_timespec(
|
||||||
(now_cycles < base_cycles) ? 0 : now_cycles - base_cycles;
|
compute_time(base_ref, base_cycles, frequency, now_cycles));
|
||||||
int64_t now_ns = base_ref + cycles_to_ns(frequency, delta_cycles);
|
return 0;
|
||||||
*ts = ns_to_timespec(now_ns);
|
}
|
||||||
|
|
||||||
|
// ClockMonotonicRaw() is the VDSO implementation of
|
||||||
|
// clock_gettime(CLOCK_MONOTONIC_RAW).
|
||||||
|
//
|
||||||
|
// When aliasing, it serves CLOCK_MONOTONIC in the VDSO. Otherwise, if the raw
|
||||||
|
// params are not yet calibrated, it falls back to a syscall for the brief
|
||||||
|
// startup/restore window; otherwise it is computed in the VDSO from the raw
|
||||||
|
// params.
|
||||||
|
int ClockMonotonicRaw(struct timespec* ts) {
|
||||||
|
struct params* params = get_params();
|
||||||
|
uint64_t seq;
|
||||||
|
uint64_t alias;
|
||||||
|
uint64_t ready;
|
||||||
|
int64_t base_ref;
|
||||||
|
int64_t base_cycles;
|
||||||
|
uint64_t frequency;
|
||||||
|
int64_t now_cycles;
|
||||||
|
|
||||||
|
do {
|
||||||
|
seq = read_seqcount_begin(¶ms->seq_count);
|
||||||
|
alias = params->monotonic_raw_alias;
|
||||||
|
ready = params->monotonic_raw_ready;
|
||||||
|
base_ref = params->monotonic_raw_base_ref;
|
||||||
|
base_cycles = params->monotonic_raw_base_cycles;
|
||||||
|
frequency = params->monotonic_raw_frequency;
|
||||||
|
now_cycles = cycle_clock();
|
||||||
|
} while (read_seqcount_retry(¶ms->seq_count, seq));
|
||||||
|
|
||||||
|
if (alias) {
|
||||||
|
// CLOCK_MONOTONIC_RAW aliases CLOCK_MONOTONIC, served in the VDSO.
|
||||||
|
return ClockMonotonic(ts);
|
||||||
|
}
|
||||||
|
if (!ready) {
|
||||||
|
// The sandbox kernel ensures that we won't compute a time later than this
|
||||||
|
// once the params are ready.
|
||||||
|
return sys_clock_gettime(CLOCK_MONOTONIC_RAW, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ts = ns_to_timespec(
|
||||||
|
compute_time(base_ref, base_cycles, frequency, now_cycles));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace vdso {
|
|||||||
|
|
||||||
int ClockRealtime(struct timespec* ts);
|
int ClockRealtime(struct timespec* ts);
|
||||||
int ClockMonotonic(struct timespec* ts);
|
int ClockMonotonic(struct timespec* ts);
|
||||||
|
int ClockMonotonicRaw(struct timespec* ts);
|
||||||
|
|
||||||
} // namespace vdso
|
} // namespace vdso
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user