pivotal / skenario

A simulator toolkit for Knative
Apache License 2.0
30 stars 10 forks source link

Run simulation in-memory #64

Closed josephburnett closed 4 years ago

josephburnett commented 4 years ago

Currently stock movements are written to an Sqlite database. And simulation results are returned from queries on the database. This is nice and flexible, but requires a lot of IO. And disk storage.

To make the simulation run much faster, we should store all the relevant data in memory. We don't necessarily need to store every single stock movement either, if we know what metrics we want to collect up front. (If the simulation is deterministic end-to-end then we can always rerun to get more detailed metrics).

josephburnett commented 4 years ago

From 4.5 seconds to 200 millseconds!

2020/06/08 15:11:10 "POST http://localhost:3000/run HTTP/1.1" from [::1]:43940 - 200 834337B in 237.825889ms
2020/06/08 15:11:18 "POST http://localhost:3000/run HTTP/1.1" from [::1]:43940 - 200 834113B in 4.533779147s
juliababkina commented 4 years ago

I think we could make it even faster if we get rid of an database completely. Our response to client should include TallyLine, ResponseTimes, RequestsPerSecond. Here is a suggested solution how to calculate them.

TallyLine:

type TallyLine struct {
  OccursAt    int64 
  StockName   string
  KindStocked string 
  Tally       int64  
}

There is a completed movements list - completed. Sort completed by occursAt field Create a map: Key -> StockName Value -> Tally (the number of entities in stock)

For completed {
    If KindStocked in (request, desired, replica){
    Update map -> map.put(StockName, +/- 1)
    Add to result new TallyLine
}
}

ResponseTimes:

type ResponseTime struct {
  ArrivedAt    int64 
  CompletedAt  int64 
  ResponseTime int64 
}

Create a map reqToMovements: Key -> requestEntity Value -> list(movements) Create a result map result

arriveAt
completedAt
For req : reqToMovements.keySet() {
    For mov : reqToMovements.get(req){
arriveAt = min(arriveAt, mov.occusAt)
        completedAt = max(completedAt, mov.occusAt)
}
result.put(req, ResponseTime{arriveAt, completedAt , completedAt-arriveAt})
}

RequestsPerSecond:

type RPS struct {
  Second   int64 
  Requests int64
}

Create a map timeToCount : Key -> occursAt Value -> numberOfRequest

For mov : completed{
    If mov.kind == “arrive_at_routing” {
    timeToCount.put(mov.occursAt, +1)
}
}