@@ -12,15 +12,29 @@ import (
12
12
"net/http"
13
13
"net/http/httputil"
14
14
"net/url"
15
- "strconv"
16
- "strings"
15
+ "runtime/debug"
17
16
"sync"
18
17
"sync/atomic"
19
18
"time"
20
19
21
20
"github.com/julienschmidt/httprouter"
21
+ "go4.org/strutil"
22
22
)
23
23
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
+
24
38
func main () {
25
39
const (
26
40
defaultPort = "3000"
@@ -32,16 +46,19 @@ func main() {
32
46
// flags
33
47
port := flag .String ("port" , defaultPort , defaultPortUsage )
34
48
redirectURL := flag .String ("url" , defaultTarget , defaultTargetUsage )
35
- cmdEndpoint := flag .String ("endpoint" , "/" , "Custom endpoint to send GCI-specific commands. For example, '/gci'" )
36
49
yGen := flag .Uint64 ("ygen" , 0 , "Young generation size, in bytes." )
37
50
tGen := flag .Uint64 ("tgen" , 0 , "Tenured generation size, in bytes." )
51
+ printGC := flag .Bool ("print_gc" , true , "Whether to print gc information." )
38
52
flag .Parse ()
39
53
40
54
if * yGen == 0 || * tGen == 0 {
41
55
log .Fatalf ("Neither ygen nor tgen can be 0. ygen:%d tgen:%d" , * yGen , * tGen )
42
56
}
43
57
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 )
45
62
c := make (chan struct {}, 1 )
46
63
router := httprouter .New ()
47
64
router .HandlerFunc ("GET" , "/" , func (w http.ResponseWriter , r * http.Request ) {
@@ -55,9 +72,10 @@ func main() {
55
72
const (
56
73
gciHeader = "gci"
57
74
heapCheckHeader = "ch"
58
- genSeparator = "|"
59
75
)
60
76
77
+ var genSeparator = []byte {124 } // character "|"
78
+
61
79
type generation string
62
80
63
81
func (g generation ) string () string {
@@ -73,11 +91,11 @@ type transport struct {
73
91
isAvailable int32
74
92
shed uint64
75
93
target string
76
- cmdEndpoint string
77
94
waiter pendingWaiter
78
95
window sampleWindow
79
96
stGen1 sheddingThreshold
80
97
stGen2 sheddingThreshold
98
+ printGC bool
81
99
}
82
100
83
101
func shedResponse (req * http.Request ) * http.Response {
@@ -94,29 +112,8 @@ func shedResponse(req *http.Request) *http.Response {
94
112
}
95
113
}
96
114
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
-
108
115
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
- }
116
116
if atomic .LoadInt32 (& t .isAvailable ) == 1 {
117
- if request != nil && request .Body != nil {
118
- request .Body .Close ()
119
- }
120
117
atomic .AddUint64 (& t .shed , 1 )
121
118
return shedResponse (request ), nil
122
119
}
@@ -141,7 +138,7 @@ func (t *transport) checkHeap() {
141
138
arrived , finished := t .waiter .waitPending ()
142
139
t .window .update (finished )
143
140
144
- req , err := http .NewRequest ("GET" , fmt . Sprintf ( "%s%s" , t .target , t . cmdEndpoint ) , nil )
141
+ req , err := http .NewRequest ("GET" , t .target , nil )
145
142
if err != nil {
146
143
panic (fmt .Sprintf ("Err trying to build heap check request: %q\n " , err ))
147
144
}
@@ -158,9 +155,9 @@ func (t *transport) checkHeap() {
158
155
panic (fmt .Sprintf ("Could not read check heap response: %q" , err ))
159
156
}
160
157
resp .Body .Close ()
161
- hs := strings .Split (string ( b ) , genSeparator )
158
+ hs := bytes .Split (b , genSeparator )
162
159
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 )
164
161
if err != nil {
165
162
panic (fmt .Sprintf ("Could not convert usedGen2 size to number: %q" , err ))
166
163
}
@@ -169,7 +166,7 @@ func (t *transport) checkHeap() {
169
166
return
170
167
}
171
168
}
172
- usedGen1 , err := strconv . ParseUint (hs [0 ], 10 , 64 )
169
+ usedGen1 , err := strutil . ParseUintBytes (hs [0 ], 10 , 64 )
173
170
if err != nil {
174
171
panic (fmt .Sprintf ("Could not convert usedGen1 size to number: %q" , err ))
175
172
}
@@ -191,7 +188,7 @@ func shouldGC(pending, usedBytes, st uint64) bool {
191
188
}
192
189
193
190
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 )
195
192
if err != nil {
196
193
panic (fmt .Sprintf ("Err trying to build gc request: %q\n " , err ))
197
194
}
@@ -211,7 +208,9 @@ func (t *transport) gc(gen generation) {
211
208
ioutil .ReadAll (resp .Body )
212
209
resp .Body .Close ()
213
210
}
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
+ }
215
214
}
216
215
217
216
////////// PROXY
@@ -224,20 +223,20 @@ func (p *proxy) handle(w http.ResponseWriter, r *http.Request) {
224
223
p .proxy .ServeHTTP (w , r )
225
224
}
226
225
227
- func newProxy (target , cmdEndpoint string , yGen , tGen uint64 ) * proxy {
226
+ func newProxy (target string , yGen , tGen uint64 , printGC bool ) * proxy {
228
227
url , _ := url .Parse (target )
229
228
p := httputil .NewSingleHostReverseProxy (url )
230
- p .Transport = newTransport (target , cmdEndpoint , yGen , tGen )
229
+ p .Transport = newTransport (target , yGen , tGen , printGC )
231
230
return & proxy {target : url , proxy : p }
232
231
}
233
232
234
- func newTransport (target , cmdEndpoint string , yGen , tGen uint64 ) * transport {
233
+ func newTransport (target string , yGen , tGen uint64 , printGC bool ) * transport {
235
234
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 ,
241
240
}
242
241
}
243
242
0 commit comments