Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Fedorov committed Jul 11, 2022
1 parent e3425c6 commit 195787f
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 1 deletion.
27 changes: 27 additions & 0 deletions pkg/common/time/standard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright Contributors to the Mir project
//
// SPDX-License-Identifier: Apache-2.0

package time

import "time"

var StandardImpl = standardImpl{}

type standardImpl struct{}

func (standardImpl) Now() time.Time { return time.Now() }

func (standardImpl) AfterFunc(d time.Duration, f func()) *Timer {
return &Timer{time.AfterFunc(d, f), nil}
}

func (standardImpl) NewTimer(d time.Duration) *Timer {
t := time.NewTimer(d)
return &Timer{t, t.C}
}

func (standardImpl) NewTicker(d time.Duration) *Ticker {
t := time.NewTicker(d)
return &Ticker{t, t.C}
}
52 changes: 52 additions & 0 deletions pkg/common/time/time.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright Contributors to the Mir project
//
// SPDX-License-Identifier: Apache-2.0

package time

import "time"

type Time = time.Time
type Duration = time.Duration

var impl Impl = StandardImpl

func SetImpl(i Impl) { impl = i }

type Impl interface {
Now() Time
AfterFunc(d Duration, f func()) *Timer
NewTimer(d Duration) *Timer
NewTicker(d Duration) *Ticker
}

type TimerImpl interface {
Reset(d Duration) bool
Stop() bool
}

type Timer struct {
TimerImpl
C <-chan Time
}

type TickerImpl interface {
Reset(d Duration)
Stop()
}

type Ticker struct {
TickerImpl
C <-chan Time
}

func Now() Time { return impl.Now() }
func AfterFunc(d Duration, f func()) *Timer { return impl.AfterFunc(d, f) }
func NewTimer(d Duration) *Timer { return impl.NewTimer(d) }
func NewTicker(d Duration) *Ticker { return impl.NewTicker(d) }

func After(d Duration) <-chan Time { return impl.NewTimer(d).C }
func Sleep(d Duration) { <-impl.NewTimer(d).C }
func Tick(d Duration) <-chan Time { return impl.NewTicker(d).C }
func Since(t Time) Duration { return impl.Now().Sub(t) }
func Until(t Time) Duration { return t.Sub(impl.Now()) }
159 changes: 159 additions & 0 deletions pkg/testsim/testsim.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Copyright Contributors to the Mir project
//
// SPDX-License-Identifier: Apache-2.0

package testsim

import (
"container/heap"
"math"
"math/rand"
"time"
)

type Simulation struct {
Rand *rand.Rand

// nextPID PID
// processes map[PID]*Process

now int64
eq eventQueue
}

func NewSimulation(rndSeed int64) *Simulation {
return &Simulation{
Rand: rand.New(rand.NewSource(rndSeed)),
// nextPID: 1,
// processes: map[PID]*Process{},
now: 0,
eq: []*event{},
}
}

// Spawn creates a new active process.
func (s *Simulation) Spawn() *Process {
p := &Process{
Simulation: s,
// id: s.nextPID,
}
// s.processes[p.id] = p
// s.nextPID++

return p
}

func (s *Simulation) AfterFunc(d time.Duration, f func()) {
heap.Push(&s.eq, &event{s.timeAfter(d), f})
}

func (s *Simulation) RandDuration(min, max time.Duration) time.Duration {
return min + time.Duration(s.Rand.Int63n(int64(max-min+1)))
}

func (s *Simulation) RandExpDuration(min, mean time.Duration) time.Duration {
max := float64(2 << 53) // maximum exactly representable positive integer
scale := float64(mean - min)
for {
randExp := s.Rand.ExpFloat64() // random exponentially distributed value
d := math.FMA(scale, randExp, float64(min)) // scale * randExp + min
if d <= max {
return time.Duration(d)
}
}
}

func (s *Simulation) Run() {
for s.eq.Len() > 0 {
s.doStep()
}
}

func (s *Simulation) RunFor(d time.Duration) {
t := s.timeAfter(d)
for s.eq.Len() > 0 && s.eq[0].t <= t {
s.doStep()
}
}

func (s *Simulation) Step() (ok bool) {
if s.eq.Len() > 0 {
s.doStep()
ok = true
}
return
}

func (s *Simulation) timeAfter(d time.Duration) int64 {
t := s.now + int64(d)
if t < 0 {
panic("Time overflow")
}
return t
}

func (s *Simulation) doStep() {
e := heap.Pop(&s.eq).(*event)
s.now = e.t
e.f()
}

type event struct {
t int64
f func()
}

type eventQueue []*event

func (eq eventQueue) Len() int { return len(eq) }
func (eq eventQueue) Less(i, j int) bool { return eq[i].t < eq[j].t }
func (eq eventQueue) Swap(i, j int) { eq[i], eq[j] = eq[j], eq[i] }
func (eq *eventQueue) Push(e any) { *eq = append(*eq, e.(*event)) }
func (eq *eventQueue) Pop() (e any) {
n := len(*eq)
e = (*eq)[n-1]
*eq, (*eq)[n-1] = (*eq)[:n-1], nil
return
}

// type PID int

type Process struct {
*Simulation

// id PID
}

// ID returns the process' identifier.
// func (p *Process) ID() PID { return p.id }

// Fork creates a new active process.
func (p *Process) Fork() *Process { return p.Spawn() }

// // Yield enables another waiting process to run.
// func (p *Process) Yield() { p.Delay(0) }

// Delay suspends the execution and returns after d amount of
// simulated time. It returns false in case the process was killed
// while waiting.
func (p *Process) Delay(d time.Duration) (ok bool) { return }

// Exit terminates the process normally.
func (p *Process) Exit() {}

// Kill immediately resumes and terminates the process.
func (p *Process) Kill() {}

type Chan struct {
}

// Send enqueues the value v to the channel and resumes a process
// waiting in Recv operation on the channel.
func (c *Chan) Send(v any) {}

// Recv attempts to dequeue a value from the channel. If the channel
// is empty then it suspends the execution until a new value is
// enqueued to the channel or the process gets killed. It returns the
// dequeued value and true, otherwise it returns nil and false in case
// the process was killed while waiting.
func (c *Chan) Recv() (v any, ok bool) { return }
3 changes: 2 additions & 1 deletion pkg/timer/timer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package timer
import (
"context"
"fmt"

"github.com/filecoin-project/mir/pkg/common/time"
"github.com/filecoin-project/mir/pkg/events"
"github.com/filecoin-project/mir/pkg/pb/eventpb"
t "github.com/filecoin-project/mir/pkg/types"
"time"
)

// The Timer module abstracts the passage of real time.
Expand Down

0 comments on commit 195787f

Please sign in to comment.