Skip to content

Commit 5a7287b

Browse files
committed
Performance improvement and flag cleanups. Improved a lot testing, including a benchmark.
1 parent 31b3c2a commit 5a7287b

File tree

5 files changed

+118
-82
lines changed

5 files changed

+118
-82
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ results.bin
1010
vendor
1111
gci-proxy_darwin_amd64
1212
gci-proxy_linux_amd64
13-
gci-proxy_windows_amd64.exe
13+
gci-proxy_windows_amd64.exe
14+
bench*
15+
*.test
16+
*.out

Gopkg.lock

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,19 @@ GCI has two main parts: i) the GCI-Proxy -- a multiplatform, runtime-agnostic HT
1212
## Running GCI Proxy
1313

1414
```bash
15-
./gci-proxy --port 3000 --url http://localhost:8080 --ygen=67108864 --tgen=6710886 --endpoint="/gci"
15+
./gci-proxy --port 3000 --url http://localhost:8080 --ygen=67108864 --tgen=6710886
1616
```
1717

1818
Where the flags:
1919

2020
* --ygen: size in bytes of the young generation, e.g. 67108864 (64MB)
2121
* --tgen: size in bytes of the tenured generation, e.g. 67108864 (64MB)
2222
* --port: port which the gci-proxy will listen, e.g. 3000
23-
* --url: URL of the server being proxied, e.g. --url http://localhost:8080
24-
* --endpoint: (optional) custom HTTP endpoint to send GCI-specific commands, e.g. --endpoint=/__gci
23+
* --url: complete endpoint to send GCI-specific commands, e.g. --url http://localhost:8080/__gci
2524

25+
The URL of the server being proxies is either extracted from the request or indicated by the
26+
environment variables `HTTP_PROXY`, `HTTPS_PROXY` (or the lowercase versions
27+
thereof). `HTTPS_PROXY` takes precedence over `HTTP_PROXY` for https requests.
2628

2729
## GCI Proxy Protocol
2830

main.go

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,29 @@ import (
1212
"net/http"
1313
"net/http/httputil"
1414
"net/url"
15-
"strconv"
16-
"strings"
15+
"runtime/debug"
1716
"sync"
1817
"sync/atomic"
1918
"time"
2019

2120
"github.com/julienschmidt/httprouter"
21+
"go4.org/strutil"
2222
)
2323

24+
var transportClient = &http.Transport{
25+
Proxy: http.ProxyFromEnvironment,
26+
DisableCompression: true,
27+
Dial: (&net.Dialer{
28+
Timeout: 5 * time.Second,
29+
}).Dial,
30+
TLSHandshakeTimeout: 5 * time.Second,
31+
}
32+
33+
var client = &http.Client{
34+
Timeout: time.Second * 5,
35+
Transport: transportClient,
36+
}
37+
2438
func main() {
2539
const (
2640
defaultPort = "3000"
@@ -32,16 +46,19 @@ func main() {
3246
// flags
3347
port := flag.String("port", defaultPort, defaultPortUsage)
3448
redirectURL := flag.String("url", defaultTarget, defaultTargetUsage)
35-
cmdEndpoint := flag.String("endpoint", "/", "Custom endpoint to send GCI-specific commands. For example, '/gci'")
3649
yGen := flag.Uint64("ygen", 0, "Young generation size, in bytes.")
3750
tGen := flag.Uint64("tgen", 0, "Tenured generation size, in bytes.")
51+
printGC := flag.Bool("print_gc", true, "Whether to print gc information.")
3852
flag.Parse()
3953

4054
if *yGen == 0 || *tGen == 0 {
4155
log.Fatalf("Neither ygen nor tgen can be 0. ygen:%d tgen:%d", *yGen, *tGen)
4256
}
4357

44-
proxy := newProxy(*redirectURL, *cmdEndpoint, *yGen, *tGen)
58+
// Configuring Garbage Collector activity. Please take a look at the benchmark comment before changing this value.
59+
debug.SetGCPercent(400)
60+
61+
proxy := newProxy(*redirectURL, *yGen, *tGen, *printGC)
4562
c := make(chan struct{}, 1)
4663
router := httprouter.New()
4764
router.HandlerFunc("GET", "/", func(w http.ResponseWriter, r *http.Request) {
@@ -55,9 +72,10 @@ func main() {
5572
const (
5673
gciHeader = "gci"
5774
heapCheckHeader = "ch"
58-
genSeparator = "|"
5975
)
6076

77+
var genSeparator = []byte{124} // character "|"
78+
6179
type generation string
6280

6381
func (g generation) string() string {
@@ -73,11 +91,11 @@ type transport struct {
7391
isAvailable int32
7492
shed uint64
7593
target string
76-
cmdEndpoint string
7794
waiter pendingWaiter
7895
window sampleWindow
7996
stGen1 sheddingThreshold
8097
stGen2 sheddingThreshold
98+
printGC bool
8199
}
82100

83101
func shedResponse(req *http.Request) *http.Response {
@@ -94,29 +112,8 @@ func shedResponse(req *http.Request) *http.Response {
94112
}
95113
}
96114

97-
var transportClient = &http.Transport{
98-
Dial: (&net.Dialer{
99-
Timeout: 5 * time.Second,
100-
}).Dial,
101-
TLSHandshakeTimeout: 5 * time.Second,
102-
}
103-
var client = &http.Client{
104-
Timeout: time.Second * 5,
105-
Transport: transportClient,
106-
}
107-
108115
func (t *transport) RoundTrip(request *http.Request) (*http.Response, error) {
109-
if request.Body != nil {
110-
buf, err := ioutil.ReadAll(request.Body)
111-
if err != nil {
112-
panic(err)
113-
}
114-
request.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
115-
}
116116
if atomic.LoadInt32(&t.isAvailable) == 1 {
117-
if request != nil && request.Body != nil {
118-
request.Body.Close()
119-
}
120117
atomic.AddUint64(&t.shed, 1)
121118
return shedResponse(request), nil
122119
}
@@ -141,7 +138,7 @@ func (t *transport) checkHeap() {
141138
arrived, finished := t.waiter.waitPending()
142139
t.window.update(finished)
143140

144-
req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", t.target, t.cmdEndpoint), nil)
141+
req, err := http.NewRequest("GET", t.target, nil)
145142
if err != nil {
146143
panic(fmt.Sprintf("Err trying to build heap check request: %q\n", err))
147144
}
@@ -158,9 +155,9 @@ func (t *transport) checkHeap() {
158155
panic(fmt.Sprintf("Could not read check heap response: %q", err))
159156
}
160157
resp.Body.Close()
161-
hs := strings.Split(string(b), genSeparator)
158+
hs := bytes.Split(b, genSeparator)
162159
if len(hs) > 1 { // If there is more than one generation, lets check the tenured and run the full gc if needed.
163-
usedGen2, err := strconv.ParseUint(hs[1], 10, 64)
160+
usedGen2, err := strutil.ParseUintBytes(hs[1], 10, 64)
164161
if err != nil {
165162
panic(fmt.Sprintf("Could not convert usedGen2 size to number: %q", err))
166163
}
@@ -169,7 +166,7 @@ func (t *transport) checkHeap() {
169166
return
170167
}
171168
}
172-
usedGen1, err := strconv.ParseUint(hs[0], 10, 64)
169+
usedGen1, err := strutil.ParseUintBytes(hs[0], 10, 64)
173170
if err != nil {
174171
panic(fmt.Sprintf("Could not convert usedGen1 size to number: %q", err))
175172
}
@@ -191,7 +188,7 @@ func shouldGC(pending, usedBytes, st uint64) bool {
191188
}
192189

193190
func (t *transport) gc(gen generation) {
194-
req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", t.target, t.cmdEndpoint), nil)
191+
req, err := http.NewRequest("GET", t.target, nil)
195192
if err != nil {
196193
panic(fmt.Sprintf("Err trying to build gc request: %q\n", err))
197194
}
@@ -211,7 +208,9 @@ func (t *transport) gc(gen generation) {
211208
ioutil.ReadAll(resp.Body)
212209
resp.Body.Close()
213210
}
214-
fmt.Printf("%d,%s,%v\n", start.Unix(), gen.string(), end.Sub(start).Nanoseconds()/1e6)
211+
if t.printGC {
212+
fmt.Printf("%d,%s,%v\n", start.Unix(), gen.string(), end.Sub(start).Nanoseconds()/1e6)
213+
}
215214
}
216215

217216
////////// PROXY
@@ -224,20 +223,20 @@ func (p *proxy) handle(w http.ResponseWriter, r *http.Request) {
224223
p.proxy.ServeHTTP(w, r)
225224
}
226225

227-
func newProxy(target, cmdEndpoint string, yGen, tGen uint64) *proxy {
226+
func newProxy(target string, yGen, tGen uint64, printGC bool) *proxy {
228227
url, _ := url.Parse(target)
229228
p := httputil.NewSingleHostReverseProxy(url)
230-
p.Transport = newTransport(target, cmdEndpoint, yGen, tGen)
229+
p.Transport = newTransport(target, yGen, tGen, printGC)
231230
return &proxy{target: url, proxy: p}
232231
}
233232

234-
func newTransport(target, cmdEndpoint string, yGen, tGen uint64) *transport {
233+
func newTransport(target string, yGen, tGen uint64, printGC bool) *transport {
235234
return &transport{
236-
target: target,
237-
cmdEndpoint: cmdEndpoint,
238-
window: newSampleWindow(),
239-
stGen1: newSheddingThreshold(time.Now().UnixNano(), yGen),
240-
stGen2: newSheddingThreshold(time.Now().UnixNano(), tGen),
235+
target: target,
236+
window: newSampleWindow(),
237+
stGen1: newSheddingThreshold(time.Now().UnixNano(), yGen),
238+
stGen2: newSheddingThreshold(time.Now().UnixNano(), tGen),
239+
printGC: printGC,
241240
}
242241
}
243242

0 commit comments

Comments
 (0)