You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2018/11/19 15:29:30 UTC

[GitHub] dneuman64 closed pull request #3002: Add TM GC CPU fraction to stat endpoint

dneuman64 closed pull request #3002: Add TM GC CPU fraction to stat endpoint
URL: https://github.com/apache/trafficcontrol/pull/3002
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/traffic_monitor/datareq/stat.go b/traffic_monitor/datareq/stat.go
index fa5b79716..a0d80cb03 100644
--- a/traffic_monitor/datareq/stat.go
+++ b/traffic_monitor/datareq/stat.go
@@ -39,31 +39,32 @@ type JSONStats struct {
 
 // Stats contains statistics data about this running app. Designed to be returned via an API endpoint.
 type Stats struct {
-	MaxMemoryMB                 uint64 `json:"Max Memory (MB),string"`
-	GitRevision                 string `json:"git-revision"`
-	ErrorCount                  uint64 `json:"Error Count,string"`
-	Uptime                      uint64 `json:"uptime,string"`
-	FreeMemoryMB                uint64 `json:"Free Memory (MB),string"`
-	TotalMemoryMB               uint64 `json:"Total Memory (MB),string"`
-	Version                     string `json:"version"`
-	DeployDir                   string `json:"deploy-dir"`
-	FetchCount                  uint64 `json:"Fetch Count,string"`
-	QueryIntervalDelta          int    `json:"Query Interval Delta,string"`
-	IterationCount              uint64 `json:"Iteration Count,string"`
-	Name                        string `json:"name"`
-	BuildTimestamp              string `json:"buildTimestamp"`
-	QueryIntervalTarget         int    `json:"Query Interval Target,string"`
-	QueryIntervalActual         int    `json:"Query Interval Actual,string"`
-	SlowestCache                string `json:"Slowest Cache"`
-	LastQueryInterval           int    `json:"Last Query Interval,string"`
-	Microthreads                int    `json:"Goroutines"`
-	LastGC                      string `json:"Last Garbage Collection"`
-	MemAllocBytes               uint64 `json:"Memory Bytes Allocated"`
-	MemTotalBytes               uint64 `json:"Total Bytes Allocated"`
-	MemSysBytes                 uint64 `json:"System Bytes Allocated"`
-	OldestPolledPeer            string `json:"Oldest Polled Peer"`
-	OldestPolledPeerMs          int64  `json:"Oldest Polled Peer Time (ms)"`
-	QueryInterval95thPercentile int64  `json:"Query Interval 95th Percentile (ms)"`
+	MaxMemoryMB                 uint64  `json:"Max Memory (MB),string"`
+	GitRevision                 string  `json:"git-revision"`
+	ErrorCount                  uint64  `json:"Error Count,string"`
+	Uptime                      uint64  `json:"uptime,string"`
+	FreeMemoryMB                uint64  `json:"Free Memory (MB),string"`
+	TotalMemoryMB               uint64  `json:"Total Memory (MB),string"`
+	Version                     string  `json:"version"`
+	DeployDir                   string  `json:"deploy-dir"`
+	FetchCount                  uint64  `json:"Fetch Count,string"`
+	QueryIntervalDelta          int     `json:"Query Interval Delta,string"`
+	IterationCount              uint64  `json:"Iteration Count,string"`
+	Name                        string  `json:"name"`
+	BuildTimestamp              string  `json:"buildTimestamp"`
+	QueryIntervalTarget         int     `json:"Query Interval Target,string"`
+	QueryIntervalActual         int     `json:"Query Interval Actual,string"`
+	SlowestCache                string  `json:"Slowest Cache"`
+	LastQueryInterval           int     `json:"Last Query Interval,string"`
+	Microthreads                int     `json:"Goroutines"`
+	LastGC                      string  `json:"Last Garbage Collection"`
+	MemAllocBytes               uint64  `json:"Memory Bytes Allocated"`
+	MemTotalBytes               uint64  `json:"Total Bytes Allocated"`
+	MemSysBytes                 uint64  `json:"System Bytes Allocated"`
+	OldestPolledPeer            string  `json:"Oldest Polled Peer"`
+	OldestPolledPeerMs          int64   `json:"Oldest Polled Peer Time (ms)"`
+	QueryInterval95thPercentile int64   `json:"Query Interval 95th Percentile (ms)"`
+	GCCPUFraction               float64 `json:"gc-cpu-fraction"`
 }
 
 func srvStats(staticAppData config.StaticAppData, healthPollInterval time.Duration, lastHealthDurations threadsafe.DurationMap, fetchCount threadsafe.Uint, healthIteration threadsafe.Uint, errorCount threadsafe.Uint, peerStates peer.CRStatesPeersThreadsafe) ([]byte, error) {
@@ -98,6 +99,7 @@ func getStats(staticAppData config.StaticAppData, pollingInterval time.Duration,
 	s.MemAllocBytes = memStats.Alloc
 	s.MemTotalBytes = memStats.TotalAlloc
 	s.MemSysBytes = memStats.Sys
+	s.GCCPUFraction = memStats.GCCPUFraction
 
 	oldestPolledPeer, oldestPolledPeerTime := oldestPeerPollTime(peerStates.GetQueryTimes(), peerStates.GetPeersOnline())
 	s.OldestPolledPeer = string(oldestPolledPeer)
diff --git a/traffic_monitor/datareq/stat_test.go b/traffic_monitor/datareq/stat_test.go
new file mode 100644
index 000000000..82b6f02fb
--- /dev/null
+++ b/traffic_monitor/datareq/stat_test.go
@@ -0,0 +1,242 @@
+package datareq
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"encoding/json"
+	"errors"
+	"math"
+	"math/rand"
+	"testing"
+	"time"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+	"github.com/apache/trafficcontrol/lib/go-util"
+	"github.com/apache/trafficcontrol/traffic_monitor/config"
+	"github.com/apache/trafficcontrol/traffic_monitor/peer"
+)
+
+func getMockStaticAppData() config.StaticAppData {
+	return config.StaticAppData{
+		StartTime:      time.Now(),
+		GitRevision:    "1234abc",
+		FreeMemoryMB:   99999999,
+		Version:        "0.1",
+		WorkingDir:     "/usr/sbin/",
+		Name:           "traffic_monitor",
+		BuildTimestamp: time.Now().Format(time.RFC3339),
+		Hostname:       "monitor01",
+		UserAgent:      "traffic_monitor/0.1",
+	}
+}
+
+func randStr() string {
+	chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_"
+	num := 100
+	s := ""
+	for i := 0; i < num; i++ {
+		s += string(chars[rand.Intn(len(chars))])
+	}
+	return s
+}
+
+func randBool() bool {
+	return rand.Int()%2 == 0
+}
+
+func getMockLastHealthTimes() map[tc.CacheName]time.Duration {
+	mockTimes := map[tc.CacheName]time.Duration{}
+	numCaches := 10
+	for i := 0; i < numCaches; i++ {
+		mockTimes[tc.CacheName(randStr())] = time.Duration(rand.Int())
+	}
+	return mockTimes
+}
+
+func getMockCRStatesDeliveryService() tc.CRStatesDeliveryService {
+	numCGs := 10
+	disabledLocations := []tc.CacheGroupName{}
+	for i := 0; i < numCGs; i++ {
+		disabledLocations = append(disabledLocations, tc.CacheGroupName(randStr()))
+	}
+
+	return tc.CRStatesDeliveryService{
+		DisabledLocations: disabledLocations,
+		IsAvailable:       randBool(),
+	}
+}
+
+func getMockPeerStates() peer.CRStatesThreadsafe {
+	ps := peer.NewCRStatesThreadsafe()
+
+	numCaches := 10
+	for i := 0; i < numCaches; i++ {
+		ps.SetCache(tc.CacheName(randStr()), tc.IsAvailable{IsAvailable: randBool()})
+	}
+
+	numDSes := 10
+	for i := 0; i < numDSes; i++ {
+		ps.SetDeliveryService(tc.DeliveryServiceName(randStr()), getMockCRStatesDeliveryService())
+	}
+	return ps
+}
+
+func getRandDuration() time.Duration {
+	return time.Duration(rand.Int63())
+}
+
+func getRandResult(name tc.TrafficMonitorName) peer.Result {
+	peerStates := getMockPeerStates()
+	return peer.Result{
+		ID:         name,
+		Available:  randBool(),
+		Errors:     []error{errors.New(randStr())},
+		PeerStates: peerStates.Get(),
+		PollID:     rand.Uint64(),
+		// PollFinished chan<- uint64,
+		Time: time.Now(),
+	}
+}
+
+func getMockCRStatesPeers() peer.CRStatesPeersThreadsafe {
+	ps := peer.NewCRStatesPeersThreadsafe()
+
+	ps.SetTimeout(getRandDuration())
+
+	randPeers := map[tc.TrafficMonitorName]struct{}{}
+	numPeers := 10
+	for i := 0; i < numPeers; i++ {
+		randPeers[tc.TrafficMonitorName(randStr())] = struct{}{}
+	}
+	ps.SetPeers(randPeers)
+
+	for peer, _ := range randPeers {
+		ps.Set(getRandResult(peer))
+	}
+
+	return ps
+}
+
+func TestGetStats(t *testing.T) {
+	appData := getMockStaticAppData()
+	pollingInterval := 5 * time.Second
+	lastHealthTimes := getMockLastHealthTimes()
+	fetchCount := uint64(rand.Int())
+	healthIteration := uint64(rand.Int())
+	errCount := uint64(rand.Int())
+	crStatesPeers := getMockCRStatesPeers()
+
+	statsBts, err := getStats(appData, pollingInterval, lastHealthTimes, fetchCount, healthIteration, errCount, crStatesPeers)
+	if err != nil {
+		t.Fatalf("expected getStats error: nil, actual: %+v\n", err)
+	}
+
+	jsonStats := JSONStats{}
+	if err := json.Unmarshal(statsBts, &jsonStats); err != nil {
+		t.Fatalf("expected getStats bytes: Stats JSON, actual: error decoding: %+v\n", err)
+	}
+	st := jsonStats.Stats
+
+	if st.GitRevision != appData.GitRevision {
+		t.Fatalf("expected getStats GitRevision '%+v', actual: '%+v'\n", appData.GitRevision, st.GitRevision)
+	}
+	if st.ErrorCount != errCount {
+		t.Fatalf("expected getStats ErrorCount '%+v', actual: '%+v'\n", errCount, st.ErrorCount)
+	}
+	if st.Uptime < uint64(time.Since(appData.StartTime)/time.Second) {
+		t.Fatalf("expected getStats Uptime > '%+v', actual: '%+v'\n", appData.StartTime, st.Uptime)
+	}
+	if tooFar := time.Since(appData.StartTime); st.Uptime > uint64(tooFar/time.Second-10) {
+		t.Fatalf("expected getStats Uptime < '%+v', actual: '%+v'\n", tooFar, st.Uptime)
+	}
+	if st.FreeMemoryMB != appData.FreeMemoryMB {
+		t.Fatalf("expected getStats FreeMemoryMB '%+v', actual: '%+v'\n", appData.FreeMemoryMB, st.FreeMemoryMB)
+	}
+	if st.TotalMemoryMB <= 0 {
+		t.Fatalf("expected getStats TotalMemoryMB > 0, actual: '%+v'\n", st.TotalMemoryMB)
+	}
+	if st.Version != appData.Version {
+		t.Fatalf("expected getStats Version '%+v', actual: '%+v'\n", appData.Version, st.Version)
+	}
+	if st.DeployDir != appData.WorkingDir {
+		t.Fatalf("expected getStats DeployDir '%+v', actual: '%+v'\n", appData.WorkingDir, st.DeployDir)
+	}
+	if st.FetchCount != fetchCount {
+		t.Fatalf("expected getStats FetchCount '%+v', actual: '%+v'\n", fetchCount, st.FetchCount)
+	}
+
+	slowestCache, slowestCacheTime := getLongestPoll(lastHealthTimes)
+
+	if st.SlowestCache != string(slowestCache) {
+		t.Fatalf("expected getStats SlowestCache '%+v', actual: '%+v'\n", slowestCache, st.SlowestCache)
+	}
+	if st.Name != appData.Name {
+		t.Fatalf("expected getStats Name '%+v', actual: '%+v'\n", appData.Name, st.Name)
+	}
+	if st.BuildTimestamp != appData.BuildTimestamp {
+		t.Fatalf("expected getStats BuildTimestamp '%+v', actual: '%+v'\n", appData.BuildTimestamp, st.BuildTimestamp)
+	}
+	if st.QueryIntervalTarget != int(pollingInterval/time.Millisecond) {
+		t.Fatalf("expected getStats QueryIntervalTarget '%+v', actual: '%+v'\n", pollingInterval/time.Millisecond, st.QueryIntervalTarget)
+	}
+	if st.QueryIntervalActual != int(slowestCacheTime/time.Millisecond) {
+		t.Fatalf("expected getStats QueryIntervalActual '%+v', actual: '%+v'\n", slowestCacheTime/time.Millisecond, st.QueryIntervalActual)
+	}
+	if st.QueryIntervalDelta != int((slowestCacheTime-pollingInterval)/time.Millisecond) {
+		t.Fatalf("expected getStats QueryIntervalActual '%+v', actual: '%+v'\n", (slowestCacheTime - pollingInterval), st.QueryIntervalDelta)
+	}
+	if st.LastQueryInterval != int(math.Max(float64(slowestCacheTime), float64(pollingInterval))/float64(time.Millisecond)) {
+		t.Fatalf("expected getStats LastQueryInterval expected '%+v', actual: '%+v'\n", int(math.Max(float64(slowestCacheTime), float64(pollingInterval))), st.LastQueryInterval)
+	}
+	if st.Microthreads <= 0 {
+		t.Fatalf("expected getStats Microthreads >0, actual: '%+v'\n", st.Microthreads)
+	}
+	if st.LastGC == "" {
+		t.Fatalf("expected getStats LastGC nonempty, actual: '%+v'\n", st.LastGC)
+	}
+	if st.MemAllocBytes <= 0 {
+		t.Fatalf("expected getStats MemAllocBytes >0, actual: '%+v'\n", st.MemAllocBytes)
+	}
+	if st.MemTotalBytes <= 0 {
+		t.Fatalf("expected getStats MemTotalBytes >0, actual: '%+v'\n", st.MemTotalBytes)
+	}
+	if st.MemSysBytes <= 0 {
+		t.Fatalf("expected getStats MemSysBytes >0, actual: '%+v'\n", st.MemSysBytes)
+	}
+	if st.GCCPUFraction == 0.0 {
+		t.Fatalf("expected getStats GCCPUFraction != 0, actual: '%+v'\n", st.GCCPUFraction)
+	}
+
+	oldestPolledPeer, oldestPolledPeerTime := oldestPeerPollTime(crStatesPeers.GetQueryTimes(), crStatesPeers.GetPeersOnline())
+	if st.OldestPolledPeer != string(oldestPolledPeer) {
+		t.Fatalf("expected getStats OldestPolledPeer '%+v', actual: '%+v'\n", oldestPolledPeer, st.OldestPolledPeer)
+	}
+
+	oldestPolledPeerTimeMS := time.Now().Sub((oldestPolledPeerTime)).Nanoseconds() / util.MSPerNS
+	if st.OldestPolledPeerMs > oldestPolledPeerTimeMS+10 || st.OldestPolledPeerMs < oldestPolledPeerTimeMS-10 {
+		t.Fatalf("expected getStats OldestPolledPeerMs '%+v', actual: '%+v'\n", oldestPolledPeerTimeMS, st.OldestPolledPeerMs)
+	}
+
+	queryInterval95thPercentile := getCacheTimePercentile(lastHealthTimes, 0.95).Nanoseconds() / util.MSPerNS
+
+	if st.QueryInterval95thPercentile != queryInterval95thPercentile {
+		t.Fatalf("expected getStats QueryInterval95thPercentile '%+v', actual: '%+v'\n", queryInterval95thPercentile, st.QueryInterval95thPercentile)
+	}
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services