Use condition variable to wake stats collector.

Before the collection goroutine wakes up every 1 second (as configured).
This sleep interval is in case there are no stats to collect we don't
end up in a tight loop.

Instead use a condition variable to signal that a collection is needed.
This prevents us from waking the goroutine needlessly when there is no
one looking for stats.

For now I've kept the sleep just moved it to the end of the loop, which
gives some space between collections.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit e75e6b0e31)
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff 2020-02-08 08:58:42 -08:00
parent 75fa1145da
commit 0901d4ab31
1 changed files with 15 additions and 10 deletions

View File

@ -14,6 +14,7 @@ import (
// Collector manages and provides container resource stats
type Collector struct {
m sync.Mutex
cond *sync.Cond
supervisor supervisor
interval time.Duration
publishers map[*container.Container]*pubsub.Publisher
@ -31,6 +32,7 @@ func NewCollector(supervisor supervisor, interval time.Duration) *Collector {
publishers: make(map[*container.Container]*pubsub.Publisher),
bufReader: bufio.NewReaderSize(nil, 128),
}
s.cond = sync.NewCond(&s.m)
platformNewStatsCollector(s)
@ -46,13 +48,16 @@ type supervisor interface {
// the event loop for collection on the specified interval returning
// a channel for the subscriber to receive on.
func (s *Collector) Collect(c *container.Container) chan interface{} {
s.m.Lock()
defer s.m.Unlock()
s.cond.L.Lock()
defer s.cond.L.Unlock()
publisher, exists := s.publishers[c]
if !exists {
publisher = pubsub.NewPublisher(100*time.Millisecond, 1024)
s.publishers[c] = publisher
}
s.cond.Broadcast()
return publisher.Subscribe()
}
@ -91,23 +96,21 @@ func (s *Collector) Run() {
var pairs []publishersPair
for {
// Put sleep at the start so that it will always be hit,
// preventing a tight loop if no stats are collected.
time.Sleep(s.interval)
s.cond.L.Lock()
for len(s.publishers) == 0 {
s.cond.Wait()
}
// it does not make sense in the first iteration,
// but saves allocations in further iterations
pairs = pairs[:0]
s.m.Lock()
for container, publisher := range s.publishers {
// copy pointers here to release the lock ASAP
pairs = append(pairs, publishersPair{container, publisher})
}
s.m.Unlock()
if len(pairs) == 0 {
continue
}
s.cond.L.Unlock()
onlineCPUs, err := s.getNumberOnlineCPUs()
if err != nil {
@ -149,6 +152,8 @@ func (s *Collector) Run() {
})
}
}
time.Sleep(s.interval)
}
}