k8s.io/perf-tests/clusterloader2@v0.0.0-20240304094227-64bdb12da87e/pkg/measurement/common/timer.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package common 18 19 import ( 20 "fmt" 21 "sync" 22 "time" 23 24 "k8s.io/klog/v2" 25 "k8s.io/perf-tests/clusterloader2/pkg/measurement" 26 measurementutil "k8s.io/perf-tests/clusterloader2/pkg/measurement/util" 27 "k8s.io/perf-tests/clusterloader2/pkg/util" 28 ) 29 30 const ( 31 timerMeasurementName = "Timer" 32 ) 33 34 func init() { 35 if err := measurement.Register(timerMeasurementName, createTimerMeasurment); err != nil { 36 klog.Fatalf("Cannot register %s: %v", timerMeasurementName, err) 37 } 38 } 39 40 func createTimerMeasurment() measurement.Measurement { 41 return &timer{ 42 startTimes: make(map[string]time.Time), 43 durations: make(map[string]time.Duration), 44 } 45 } 46 47 type timer struct { 48 lock sync.Mutex 49 startTimes map[string]time.Time 50 durations map[string]time.Duration 51 } 52 53 // Execute supports two actions. start - which start timer. stop - which stops timer 54 // and collects time duration between start and stop. 55 // Both start and stop actions require label parameter to be provided. 56 // Gather action logs a measurement for all collected phases durations. 57 func (t *timer) Execute(config *measurement.Config) ([]measurement.Summary, error) { 58 action, err := util.GetString(config.Params, "action") 59 if err != nil { 60 return nil, err 61 } 62 63 t.lock.Lock() 64 defer t.lock.Unlock() 65 switch action { 66 case "start": 67 label, err := util.GetString(config.Params, "label") 68 if err != nil { 69 return nil, err 70 } 71 t.startTimes[label] = time.Now() 72 case "stop": 73 label, err := util.GetString(config.Params, "label") 74 if err != nil { 75 return nil, err 76 } 77 startTime, ok := t.startTimes[label] 78 if !ok { 79 return nil, fmt.Errorf("uninitialized timer %s", label) 80 } 81 duration := time.Since(startTime) 82 klog.V(0).Infof("%s: %s - %v", t, label, duration) 83 t.durations[label] = duration 84 delete(t.startTimes, label) 85 case "gather": 86 result := measurementutil.PerfData{ 87 Version: "v1", 88 DataItems: []measurementutil.DataItem{{ 89 Unit: "s", 90 Labels: map[string]string{"test": "phases"}, 91 Data: make(map[string]float64)}}} 92 93 for label, duration := range t.durations { 94 result.DataItems[0].Data[label] = duration.Seconds() 95 } 96 content, err := util.PrettyPrintJSON(result) 97 if err != nil { 98 return nil, err 99 } 100 summary := measurement.CreateSummary(timerMeasurementName, "json", content) 101 return []measurement.Summary{summary}, nil 102 default: 103 return nil, fmt.Errorf("unknown action %s", action) 104 } 105 return nil, nil 106 } 107 108 // Dispose cleans up after the measurement. 109 func (t *timer) Dispose() {} 110 111 // String returns string representation of this measurement. 112 func (*timer) String() string { 113 return timerMeasurementName 114 }