Skip to content
Snippets Groups Projects
Unverified Commit d8bd71f6 authored by Levente Pap's avatar Levente Pap
Browse files

Measure finalized/failed conflicts + average rounds of finalization

parent 8e62ab07
No related branches found
No related tags found
No related merge requests found
......@@ -3,10 +3,40 @@ package metrics
import (
"sync/atomic"
"github.com/iotaledger/hive.go/syncutils"
"github.com/iotaledger/goshimmer/packages/vote"
)
var activeConflicts uint64
var finalizedConflictCount uint64
var failedConflictCount uint64
var averageRoundsToFinalize float64
var avLock syncutils.RWMutex
// ActiveConflicts returns the number of currently active conflicts.
func ActiveConflicts() uint64 {
return atomic.LoadUint64(&activeConflicts)
}
// FinalizedConflict returns the number of finalized conflicts since the start of the node.
func FinalizedConflict() uint64 {
return atomic.LoadUint64(&finalizedConflictCount)
}
// FailedConflicts returns the number of failed conflicts since the start of the node.
func FailedConflicts() uint64 {
return atomic.LoadUint64(&failedConflictCount)
}
// AverageRoundsToFinalize returns the average number fo rounds it takes to finalize conflicts since the start of the node.
func AverageRoundsToFinalize() float64 {
avLock.RLock()
defer avLock.RUnlock()
return averageRoundsToFinalize
}
//// logic broken into "process..." functions to be able to write unit tests ////
func processRoundStats(stats vote.RoundStats) {
// get the number of active conflicts
......@@ -14,7 +44,17 @@ func processRoundStats(stats vote.RoundStats) {
atomic.StoreUint64(&activeConflicts, numActive)
}
// ActiveConflicts returns the number of currently active conflicts.
func ActiveConflicts() uint64 {
return atomic.LoadUint64(&activeConflicts)
func processFinalized(ctx vote.Context) {
avLock.Lock()
defer avLock.Unlock()
// calculate sum of all rounds, including the currently finalized
sumRounds := averageRoundsToFinalize*(float64)(atomic.LoadUint64(&finalizedConflictCount)) + (float64)(ctx.Rounds)
// increase finalized counter
atomic.AddUint64(&finalizedConflictCount, 1)
// calculate new average
averageRoundsToFinalize = sumRounds / (float64)(atomic.LoadUint64(&finalizedConflictCount))
}
func processFailed(ctx vote.Context) {
atomic.AddUint64(&failedConflictCount, 1)
}
......@@ -3,11 +3,57 @@ package metrics
import (
"testing"
"github.com/iotaledger/goshimmer/packages/vote"
"github.com/magiconair/properties/assert"
)
func TestActiveConflicts(t *testing.T) {
// initialized to 0
assert.Equal(t, ActiveConflicts(), (uint64)(0))
stats := vote.RoundStats{
ActiveVoteContexts: map[string]*vote.Context{
"test1": &vote.Context{},
"test2": &vote.Context{},
"test3": &vote.Context{},
},
}
processRoundStats(stats)
assert.Equal(t, ActiveConflicts(), (uint64)(3))
}
func TestFailedConflicts(t *testing.T) {
// initialized to 0
assert.Equal(t, FailedConflicts(), (uint64)(0))
// simulate 10 failed conflicts
for i := 0; i < 10; i++ {
processFailed(vote.Context{})
}
assert.Equal(t, FailedConflicts(), (uint64)(10))
// simulate 10 failed conflicts
for i := 0; i < 10; i++ {
processFailed(vote.Context{})
}
assert.Equal(t, FailedConflicts(), (uint64)(20))
}
func TestFinalize(t *testing.T) {
assert.Equal(t, AverageRoundsToFinalize(), 0.0)
assert.Equal(t, FinalizedConflict(), (uint64)(0))
// simulate 5 finalized conflicts with 5 rounds
for i := 0; i < 5; i++ {
processFinalized(vote.Context{
Rounds: 5,
})
}
assert.Equal(t, FinalizedConflict(), (uint64)(5))
// simulate 5 finalized conflicts with 10 rounds
for i := 0; i < 5; i++ {
processFinalized(vote.Context{
Rounds: 10,
})
}
assert.Equal(t, FinalizedConflict(), (uint64)(10))
// => average should be 7.5
assert.Equal(t, AverageRoundsToFinalize(), 7.5)
}
......@@ -53,25 +53,7 @@ func TestReceivedMPSUpdatedEvent(t *testing.T) {
wg.Wait()
}
func TestMPSPerPayloadSingle(t *testing.T) {
// it is empty initially
assert.Equal(t, MPSPerPayload(), map[payload.Type]uint64{})
assert.Equal(t, MessageTotalCount(), (uint64)(0))
// simulate attaching 10 value payloads in 0s < t < 1s
for i := 0; i < 10; i++ {
increasePerPayloadMPSCounter(valuepayload.Type)
}
// test measurement
measureMPSPerPayload()
assert.Equal(t, MPSPerPayload(), map[payload.Type]uint64{valuepayload.Type: 10})
assert.Equal(t, MessageTotalCount(), (uint64)(10))
// test counter reset on measurement
measureMPSPerPayload()
assert.Equal(t, MPSPerPayload(), map[payload.Type]uint64{valuepayload.Type: 0})
assert.Equal(t, MessageTotalCount(), (uint64)(10))
}
func TestMPSPerPayloadMultiple(t *testing.T) {
func TestMPSPerPayload(t *testing.T) {
// it is empty initially
assert.Equal(t, MPSPerPayload(), map[payload.Type]uint64{})
assert.Equal(t, MessageTotalCount(), (uint64)(0))
......
......@@ -53,6 +53,16 @@ func configure(_ *node.Plugin) {
processRoundStats(roundStats)
}))
// a conflict has been finalized
valuetransfers.Voter().Events().Finalized.Attach(events.NewClosure(func(ev *vote.OpinionEvent) {
processFinalized(ev.Ctx)
}))
// consensus failure in conflict resolution
valuetransfers.Voter().Events().Failed.Attach(events.NewClosure(func(ev *vote.OpinionEvent) {
processFailed(ev.Ctx)
}))
//// Events coming from metrics package ////
metrics.Events().FPCInboundBytes.Attach(events.NewClosure(func(amountBytes uint64) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment