138 lines
2.5 KiB
Go
138 lines
2.5 KiB
Go
|
// Copyright 2019 The Walk Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
// +build windows
|
||
|
|
||
|
package walk
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"sort"
|
||
|
"sync"
|
||
|
"text/tabwriter"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type stopwatchItem struct {
|
||
|
stopwatchStats
|
||
|
subject string
|
||
|
startedTime time.Time
|
||
|
}
|
||
|
|
||
|
type stopwatchStats struct {
|
||
|
count int64
|
||
|
min time.Duration
|
||
|
max time.Duration
|
||
|
total time.Duration
|
||
|
}
|
||
|
|
||
|
func (sws *stopwatchStats) Average() time.Duration {
|
||
|
if sws.count == 0 {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
return time.Nanosecond * time.Duration(sws.total.Nanoseconds()/sws.count)
|
||
|
}
|
||
|
|
||
|
type stopwatch struct {
|
||
|
mutex sync.Mutex
|
||
|
subject2item map[string]*stopwatchItem
|
||
|
}
|
||
|
|
||
|
func newStopwatch() *stopwatch {
|
||
|
return &stopwatch{
|
||
|
subject2item: make(map[string]*stopwatchItem),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (sw *stopwatch) Start(subject string) time.Time {
|
||
|
sw.mutex.Lock()
|
||
|
defer sw.mutex.Unlock()
|
||
|
|
||
|
item, ok := sw.subject2item[subject]
|
||
|
if !ok {
|
||
|
item = &stopwatchItem{subject: subject}
|
||
|
sw.subject2item[subject] = item
|
||
|
}
|
||
|
|
||
|
item.startedTime = time.Now()
|
||
|
|
||
|
return item.startedTime
|
||
|
}
|
||
|
|
||
|
func (sw *stopwatch) Stop(subject string) time.Duration {
|
||
|
sw.mutex.Lock()
|
||
|
defer sw.mutex.Unlock()
|
||
|
|
||
|
item, ok := sw.subject2item[subject]
|
||
|
if !ok || item.startedTime.IsZero() {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
duration := time.Now().Sub(item.startedTime)
|
||
|
|
||
|
item.count++
|
||
|
if duration < item.min || item.min == 0 {
|
||
|
item.min = duration
|
||
|
}
|
||
|
if duration > item.max {
|
||
|
item.max = duration
|
||
|
}
|
||
|
item.total += duration
|
||
|
item.startedTime = time.Time{}
|
||
|
|
||
|
return duration
|
||
|
}
|
||
|
|
||
|
func (sw *stopwatch) Cancel(subject string) {
|
||
|
sw.mutex.Lock()
|
||
|
defer sw.mutex.Unlock()
|
||
|
|
||
|
item, ok := sw.subject2item[subject]
|
||
|
if !ok {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
item.startedTime = time.Time{}
|
||
|
}
|
||
|
|
||
|
func (sw *stopwatch) Clear() {
|
||
|
sw.mutex.Lock()
|
||
|
defer sw.mutex.Unlock()
|
||
|
|
||
|
for key := range sw.subject2item {
|
||
|
delete(sw.subject2item, key)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (sw *stopwatch) Print() {
|
||
|
sw.mutex.Lock()
|
||
|
|
||
|
items := make([]*stopwatchItem, 0, len(sw.subject2item))
|
||
|
for _, item := range sw.subject2item {
|
||
|
items = append(items, item)
|
||
|
}
|
||
|
|
||
|
sw.mutex.Unlock()
|
||
|
|
||
|
sort.Slice(items, func(i, j int) bool {
|
||
|
return items[i].total > items[j].total
|
||
|
})
|
||
|
|
||
|
var buf bytes.Buffer
|
||
|
|
||
|
writer := tabwriter.NewWriter(&buf, 0, 8, 2, ' ', tabwriter.AlignRight)
|
||
|
|
||
|
fmt.Fprintln(writer, "#\tSubject\tAverage\tTotal\tMin\tMax\t\tCount")
|
||
|
|
||
|
for i, item := range items {
|
||
|
fmt.Fprintf(writer, "%d\t%s\t%s\t%s\t%s\t%s\t\t%d\n", i+1, item.subject, item.Average(), item.total, item.min, item.max, item.count)
|
||
|
}
|
||
|
|
||
|
writer.Flush()
|
||
|
|
||
|
fmt.Print(buf.String())
|
||
|
}
|