Skip to content

Commit

Permalink
Improve hey on Windows (#108)
Browse files Browse the repository at this point in the history
Fixes #107.
  • Loading branch information
egonelbre authored and rakyll committed Apr 27, 2018
1 parent 61cf992 commit f3e8979
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 22 deletions.
1 change: 1 addition & 0 deletions hey.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ func main() {
ProxyAddr: proxyURL,
Output: *output,
}
w.Init()

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
Expand Down
24 changes: 24 additions & 0 deletions requester/now_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed 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.

// +build !windows

package requester

import "time"

var startTime = time.Now()

// now returns time.Duration using stdlib time
func now() time.Duration { return time.Since(startTime) }
47 changes: 47 additions & 0 deletions requester/now_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed 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.

package requester

import (
"syscall"
"time"
"unsafe"
)

// now returns time.Duration using queryPerformanceCounter
func now() time.Duration {
var now int64
syscall.Syscall(queryPerformanceCounterProc.Addr(), 1, uintptr(unsafe.Pointer(&now)), 0, 0)
return time.Duration(now) * time.Second / (time.Duration(qpcFrequency) * time.Nanosecond)
}

// precision timing
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
queryPerformanceFrequencyProc = modkernel32.NewProc("QueryPerformanceFrequency")
queryPerformanceCounterProc = modkernel32.NewProc("QueryPerformanceCounter")

qpcFrequency = queryPerformanceFrequency()
)

// queryPerformanceFrequency returns frequency in ticks per second
func queryPerformanceFrequency() int64 {
var freq int64
r1, _, _ := syscall.Syscall(queryPerformanceFrequencyProc.Addr(), 1, uintptr(unsafe.Pointer(&freq)), 0, 0)
if r1 == 0 {
panic("call failed")
}
return freq
}
2 changes: 1 addition & 1 deletion requester/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
)

const (
barChar = ""
barChar = ""
)

// We report for max 1M results.
Expand Down
50 changes: 29 additions & 21 deletions requester/requester.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,10 @@ type Work struct {
// Writer is where results will be written. If nil, results are written to stdout.
Writer io.Writer

results chan *result
stopCh chan struct{}
start time.Time
initOnce sync.Once
results chan *result
stopCh chan struct{}
start time.Duration

report *report
}
Expand All @@ -101,12 +102,19 @@ func (b *Work) writer() io.Writer {
return b.Writer
}

// Init initializes internal data-structures
func (b *Work) Init() {
b.initOnce.Do(func() {
b.results = make(chan *result, min(b.C*1000, maxResult))
b.stopCh = make(chan struct{}, b.C)
})
}

// Run makes all the requests, prints the summary. It blocks until
// all work is done.
func (b *Work) Run() {
b.results = make(chan *result, min(b.C*1000, maxResult))
b.stopCh = make(chan struct{}, b.C)
b.start = time.Now()
b.Init()
b.start = now()
b.report = newReport(b.writer(), b.results, b.Output, b.N)
// Run the reporter first, it polls the result channel until it is closed.
go func() {
Expand All @@ -125,42 +133,42 @@ func (b *Work) Stop() {

func (b *Work) Finish() {
close(b.results)
total := time.Now().Sub(b.start)
total := now() - b.start
// Wait until the reporter is done.
<-b.report.done
b.report.finalize(total)
}

func (b *Work) makeRequest(c *http.Client) {
s := time.Now()
s := now()
var size int64
var code int
var dnsStart, connStart, resStart, reqStart, delayStart time.Time
var dnsStart, connStart, resStart, reqStart, delayStart time.Duration
var dnsDuration, connDuration, resDuration, reqDuration, delayDuration time.Duration
req := cloneRequest(b.Request, b.RequestBody)
trace := &httptrace.ClientTrace{
DNSStart: func(info httptrace.DNSStartInfo) {
dnsStart = time.Now()
dnsStart = now()
},
DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
dnsDuration = time.Now().Sub(dnsStart)
dnsDuration = now() - dnsStart
},
GetConn: func(h string) {
connStart = time.Now()
connStart = now()
},
GotConn: func(connInfo httptrace.GotConnInfo) {
if !connInfo.Reused {
connDuration = time.Now().Sub(connStart)
connDuration = now() - connStart
}
reqStart = time.Now()
reqStart = now()
},
WroteRequest: func(w httptrace.WroteRequestInfo) {
reqDuration = time.Now().Sub(reqStart)
delayStart = time.Now()
reqDuration = now() - reqStart
delayStart = now()
},
GotFirstResponseByte: func() {
delayDuration = time.Now().Sub(delayStart)
resStart = time.Now()
delayDuration = now() - delayStart
resStart = now()
},
}
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
Expand All @@ -171,9 +179,9 @@ func (b *Work) makeRequest(c *http.Client) {
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}
t := time.Now()
resDuration = t.Sub(resStart)
finish := t.Sub(s)
t := now()
resDuration = t - resStart
finish := t - s
b.results <- &result{
statusCode: code,
duration: finish,
Expand Down

0 comments on commit f3e8979

Please sign in to comment.