home | OO Richards Bench

OOVM Smalltalk #13

Register values v1 v2 are held in Task classes, which implement scheduler function fn as a method.

Smalltalk language OOVM Smalltalk version Resilient Technology Preview. Tiny bytecode interpreter VM for embedded devices.

Bench = Object () class (

  "Category: schedule"

  main: aCount = (
    | s wkq count ticks filename stream |
    layout := 50.
    count := aCount.
    ticks := (Time measure: [
      s := Scheduler showTrace: false.
      s addIdleTask: idle priority: 0 queue: nil for: count.
    
      wkq := Packet link: nil id: worker kind: Packet::work.    
      wkq := Packet link: wkq id: worker kind: Packet::work.
      s addWorkerTask: worker priority: 1000 queue: wkq.
    
      wkq := Packet link: nil id: deviceA kind: Packet::device.
      wkq := Packet link: wkq id: deviceA kind: Packet::device.
      wkq := Packet link: wkq id: deviceA kind: Packet::device.
      s addHandlerTask: handlerA priority: 2000 queue: wkq.            
        
      wkq := Packet link: nil id: deviceB kind: Packet::device.
      wkq := Packet link: wkq id: deviceB kind: Packet::device.
      wkq := Packet link: wkq id: deviceB kind: Packet::device.
      s addHandlerTask: handlerB priority: 3000 queue: wkq.
    
      s addDeviceTask: deviceA priority: 4000 queue: nil.
      s addDeviceTask: deviceB priority: 5000 queue: nil.  
    
      s schedule.          
      
    ]) milliseconds.
    
    stream := Hosted::File open: 'J:\benchmarks\build\testrun-times.xml' mode: 'a'.
    stream 
    putAll: '<ExternalStat>';
    putAll: '<size>'; putAll: count printString; putAll: '</size>';
    putAll: '<ticks>';  putAll: ticks printString; 
    putAll: '</ticks>';
    putAll: '<ticksPerSecond>'; putAll: 1000 printString; 
    putAll: '</ticksPerSecond>';
    putAll: '</ExternalStat>';
    close.    
    
    Debug::console show: 'QueueCount = '; show: s queueCount printString; cr.
    Debug::console show: 'HoldCount = '; show: s holdCount printString.  
    )
    
  trace: aString = (
    layout <= 0
      ifTrue: [
        Debug::console cr.
        layout := 50.
        ].
    layout := layout - 1.
    Debug::console show: aString.
  )     
  
) statics (
  layout = variable
  maxTasks = 6
  
  idle = 1
  worker = 2
  handlerA = 3  
  handlerB = 4
  deviceA = 5
  deviceB = 6
)



DeviceTask = Object ( 
  | scheduler v1 v2 |

  "Category: functions"
  
  run: aPacket = (
    | pkt |
    aPacket isNil
      ifTrue: [
        v1 isNil
          ifTrue: [
            ^scheduler suspendCurrent]
          ifFalse: [
            pkt := v1.
            v1 := nil.
            ^scheduler queue: pkt.
            ]
        ]
      ifFalse: [
        v1 := aPacket.
        "scheduler traceOn 
          ifTrue: [
            Bench trace: (StringStream new 
              put: aPacket a1 asCharacter) asString]."
        ^scheduler holdCurrent.
        ]  
    )
        
  
  "Category: schedule"
  
  for: aScheduler = (
      scheduler := aScheduler.
      )  

) class (
  "Category: schedule"  
  
  for: aScheduler = (
    ^super new
      for: aScheduler
    )
)



HandlerTask = Object ( 
  | scheduler v1 v2 |
  
  "Category: functions"
  
  run: aPacket = (
    | workPacket devicePacket count |
    aPacket isNotNil
      ifTrue: [
        aPacket kind == Packet::work
          ifTrue: [v1 := aPacket addTo: v1]
          ifFalse: [v2 := aPacket addTo: v2].
        ].
    v1 isNotNil
      ifTrue: [
        workPacket := v1.
        count := workPacket a1.
        count > 4
          ifTrue: [
            v1 := v1 link.
            ^scheduler queue: workPacket.
            ]
          ifFalse: [
            v2 isNotNil
              ifTrue: [
                devicePacket := v2.
                v2 := devicePacket link.
                devicePacket a1: (workPacket a2 at: count).
                workPacket a1: count + 1.
                ^scheduler queue: devicePacket.
                ]                             
            ]
        ].      
        ^scheduler suspendCurrent          
    )
  
  
  "Category: schedule"
  
  for: aScheduler = (
      scheduler := aScheduler.
      )


) class (
  "Category: schedule"  
  
  for: aScheduler = (
    ^super new
      for: aScheduler
    )
)



IdleTask = Object ( 
  | scheduler v1 v2 |  

  "Category: functions"
  
  run: aPacket = (
    v2 := v2 - 1.
    v2 == 0 
      ifTrue: [^scheduler holdCurrent]
      ifFalse: [
        (v1 & 1) == 0
          ifTrue: [
            v1 := v1 >> 1.
            ^scheduler release: Bench::deviceA.
            ]
          ifFalse: [
            v1 := (v1 >> 1) ~ 16rD008.
            ^scheduler release: Bench::deviceB.
            ].
        ]  
    )
    
  
  "Category: schedule"
  
  for: aScheduler with: aValue1 with: aValue2 = (
      scheduler := aScheduler.
      v1 := aValue1.
      v2 := aValue2.
      )    

) class (
  "Category: schedule"  
  
  for: aScheduler with: aValue1 with: aValue2 = (
    ^super new
      for: aScheduler with: aValue1 with: aValue2
    )
)



WorkerTask = Object ( 
  | scheduler v1 v2 |
  
  "Category: functions"
  
  run: aPacket = (
    aPacket isNil
      ifTrue: [^scheduler suspendCurrent]
      ifFalse: [
        v1 := v1 == Bench::handlerA 
          ifTrue: [Bench::handlerB] ifFalse: [Bench::handlerA].
        aPacket id: v1; a1: 1.
        1 to: aPacket a2 size do: [:i| 
          v2 := v2 + 1.
          v2 > 26 ifTrue: [v2 := 1].
          aPacket a2 at: i put: $A asInteger + v2 - 1.
          ].
        ^scheduler queue: aPacket
        ]  
    )
    
    
  "Category: schedule"
  
  for: aScheduler with: aValue1 with: aValue2 = (
      scheduler := aScheduler.
      v1 := aValue1.
      v2 := aValue2.
      )  

    
) class (
  "Category: schedule"  
  
  for: aScheduler with: aValue1 with: aValue2 = (
    ^super new
      for: aScheduler with: aValue1 with: aValue2
    )
)



Scheduler = Object (
  | table list currentTcb currentId v1 v2 queueCount holdCount traceOn |
  
  "Category: accessing"    
  
  holdCount = (^holdCount)    
  queueCount = (^queueCount)  
  traceOn = (^traceOn)


  "Category: initialize"       
  
  addDeviceTask: anId priority: aPriority queue: aQueue = (
      self createTcb: anId priority: aPriority 
        queue: aQueue task: (DeviceTask for: self)
      )
        
  addHandlerTask: anId priority: aPriority queue: aQueue = (
    self createTcb: anId priority: aPriority 
      queue: aQueue task: (HandlerTask for: self)        
    ) 
  
  addIdleTask: anId priority: aPriority queue: aQueue for: aCount = (
    self createRunningTcb: anId priority: aPriority 
      queue: aQueue task: (IdleTask for: self with: 1 with: aCount)    
    )
  
  addWorkerTask: anId priority: aPriority queue: aQueue = (
    self createTcb: anId priority: aPriority 
      queue: aQueue task: (WorkerTask for: self with: Bench::handlerA with: 0)  
    )
    
    
  createRunningTcb: anId priority: aPriority queue: aQueue task: aTask = (
    self createTcb: anId priority: aPriority queue: aQueue task: aTask.
      currentTcb setRunning.
    )   
    
  createTcb: anId priority: aPriority queue: aQueue task: aTask = (
      currentTcb := Tcb link: list id: anId priority: aPriority 
        queue: aQueue task: aTask.
    list := currentTcb.
    table at: anId put: currentTcb.
    )
    
  initialize = (
    table := Array new: Bench::maxTasks.
    list := nil.
    queueCount := 0.
    holdCount := 0.
    traceOn := false.    
   )
      
  showTrace: aBoolean = (
      traceOn := aBoolean
    )

  "Category: schedule"    
  
  holdCurrent = (
      holdCount := holdCount + 1.
      currentTcb hold.
      ^currentTcb link  
    )    
    
  queue: aPacket = (
    | task |
    task := table at: aPacket id.
    task isNil 
      ifTrue: [^task].
    queueCount := queueCount + 1.
    aPacket link: nil.
    aPacket id: currentId.
    ^task checkPriority: currentTcb add: aPacket
    )
    
  release: anId = (
    | task |
    task := table at: anId.
    task isNil 
      ifTrue: [^task].
    task releaseHold.
    ^task priority > currentTcb priority
      ifTrue: [task]
      ifFalse: [currentTcb]
    )
    
  schedule = (
    currentTcb := list.
    [currentTcb isNotNil] 
      whileTrue: [
        currentTcb isHeldOrSuspended
          ifTrue: [
            currentTcb := currentTcb link]
          ifFalse: [
            currentId := currentTcb id.
            "traceOn 
              ifTrue: [Bench trace: currentId printString]."
            currentTcb := currentTcb run.
            ].
        ].  
    )  

  suspendCurrent = (^currentTcb suspend)


) class (

  "Category: initialize"  
  
  showTrace: aBoolean = (
    ^super new
      initialize;
      showTrace: aBoolean  
    )
)



Tcb = Object (
  | link id pri wkq state task |
  
  "Category: accessing"    
  
  id = (^id)  
  priority = (^pri)  
  link = (^link)  


  "Category: initialize"
            
  link: aLink id: anId priority: aPriority queue: aQueue task: aTask = (
    link := aLink.
    id := anId.
    pri := aPriority.
    wkq :=  aQueue.
    task := aTask.
    state := wkq isNil
      ifTrue: [2r10] ifFalse: [2r11]
    )
    
    
  "Category: schedule"  
    
  checkPriority: aTcb add: aPacket = (
    wkq isNil
      ifTrue:[
        wkq := aPacket.
        state := state | 2r1. 
        pri > aTcb priority
          ifTrue: [^self]
        ]
      ifFalse: 
        [wkq := aPacket addTo: wkq].
    ^aTcb
    )  
    
  run = (
      | packet |
      state == 2r11 "SuspendedRunnable"      
         ifTrue: [
            packet := wkq.
            wkq := packet link.
            wkq isNil
               ifTrue: [state := 2r0] "Running"            
               ifFalse: [state := 2r1]. "Runnable"  
            ]
         ifFalse: [packet := nil].
    ^task run: packet
    )    
    
		
   "Category: state"   
   
   setRunning = (state := 2r0)   
   
   isHeldOrSuspended = (^(state & 2r100) ~== 0  or: [state == 2r10])         
      
   suspend = (state := state | 2r10)      
      
   hold = (state := state | 2r100)      
   
   releaseHold = (state := state & -2r101)      
       
   isSuspended = (^(state & 2r10) ~== 0)                             

) class (

  "Category: initialize"  
    
  link: aLink id: anId priority: aPriority queue: aQueue task: aTask = (
    ^super new
        link: aLink id: anId priority: aPriority queue: aQueue task: aTask
    )  
)



Packet = Object (
  | link id kind a1 a2 |
  
  "Category: accessing"    
  
  a1 = (^a1)  
  a1: aValue = (a1 := aValue)  
  a2 = (^a2)  
  id = (^id)  
  id: anId = (id := anId)  
  kind = (^kind)  
  link = (^link)  
  link: aPacket = (link := aPacket)  
  
  "Category: initialize"  
  
  link: aLink id: anId kind: aKind = (
    link := aLink.
    id := anId.
    kind := aKind.
    a1 := 1.
    a2 := ByteArray new: 4 with: 0
    )  
  
  "Category: schedule"  
  
  addTo: aQueue = (
    | next peek |
    link := nil.
    aQueue isNil
      ifTrue: [^self].
    next := aQueue.
    [(peek := next link) isNotNil]
      whileTrue: [next := peek].
    next link: self.
    ^aQueue  
    )  
  

) class (

  "Category: initialize"
  
  link: aLink id: anId kind: aKind = (
    ^super new
      link: aLink id: anId kind: aKind
  )

) statics (
  device = 0  
  work = 1    
)

Valid XHTML 1.0!