mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
Use codegen for json marshalling: 20% faster, 12% less bytes allocated, 85% less allocations
This commit is contained in:
@@ -18,7 +18,7 @@ func getPort() int {
|
||||
return int(atomic.AddUint32(&nextPort, 1))
|
||||
}
|
||||
|
||||
func tmpDir(t *testing.T) string {
|
||||
func tmpDir(t testing.TB) string {
|
||||
dir, err := ioutil.TempDir("", "nomad")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
@@ -26,7 +26,7 @@ func tmpDir(t *testing.T) string {
|
||||
return dir
|
||||
}
|
||||
|
||||
func makeAgent(t *testing.T, cb func(*Config)) (string, *Agent) {
|
||||
func makeAgent(t testing.TB, cb func(*Config)) (string, *Agent) {
|
||||
dir := tmpDir(t)
|
||||
conf := DevConfig()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,6 +27,13 @@ const (
|
||||
scadaHTTPAddr = "SCADA"
|
||||
)
|
||||
|
||||
var (
|
||||
// jsonHandle and jsonHandlePretty are the codec handles to JSON encode
|
||||
// structs. The pretty handle will add indents for easier human consumption.
|
||||
jsonHandle = &codec.JsonHandle{}
|
||||
jsonHandlePretty = &codec.JsonHandle{Indent: 4}
|
||||
)
|
||||
|
||||
// HTTPServer is used to wrap an Agent and expose it over an HTTP interface
|
||||
type HTTPServer struct {
|
||||
agent *Agent
|
||||
@@ -183,20 +192,22 @@ func (s *HTTPServer) wrap(handler func(resp http.ResponseWriter, req *http.Reque
|
||||
|
||||
// Write out the JSON object
|
||||
if obj != nil {
|
||||
var buf []byte
|
||||
var buf bytes.Buffer
|
||||
if prettyPrint {
|
||||
buf, err = json.MarshalIndent(obj, "", " ")
|
||||
enc := codec.NewEncoder(&buf, jsonHandlePretty)
|
||||
err = enc.Encode(obj)
|
||||
if err == nil {
|
||||
buf = append(buf, "\n"...)
|
||||
buf.Write([]byte("\n"))
|
||||
}
|
||||
} else {
|
||||
buf, err = json.Marshal(obj)
|
||||
enc := codec.NewEncoder(&buf, jsonHandle)
|
||||
err = enc.Encode(obj)
|
||||
}
|
||||
if err != nil {
|
||||
goto HAS_ERR
|
||||
}
|
||||
resp.Header().Set("Content-Type", "application/json")
|
||||
resp.Write(buf)
|
||||
resp.Write(buf.Bytes())
|
||||
}
|
||||
}
|
||||
return f
|
||||
|
||||
@@ -13,12 +13,13 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/nomad/nomad/mock"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/testutil"
|
||||
)
|
||||
|
||||
type TestServer struct {
|
||||
T *testing.T
|
||||
T testing.TB
|
||||
Dir string
|
||||
Agent *Agent
|
||||
Server *HTTPServer
|
||||
@@ -30,9 +31,25 @@ func (s *TestServer) Cleanup() {
|
||||
os.RemoveAll(s.Dir)
|
||||
}
|
||||
|
||||
func makeHTTPServer(t *testing.T, cb func(c *Config)) *TestServer {
|
||||
// makeHTTPServerNoLogs returns a test server with full logging.
|
||||
func makeHTTPServer(t testing.TB, cb func(c *Config)) *TestServer {
|
||||
return makeHTTPServerWithWriter(t, nil, cb)
|
||||
}
|
||||
|
||||
// makeHTTPServerNoLogs returns a test server which only prints agent logs and
|
||||
// no http server logs
|
||||
func makeHTTPServerNoLogs(t testing.TB, cb func(c *Config)) *TestServer {
|
||||
return makeHTTPServerWithWriter(t, ioutil.Discard, cb)
|
||||
}
|
||||
|
||||
// makeHTTPServerWithWriter returns a test server whose logs will be written to
|
||||
// the passed writer. If the writer is nil, the logs are written to stderr.
|
||||
func makeHTTPServerWithWriter(t testing.TB, w io.Writer, cb func(c *Config)) *TestServer {
|
||||
dir, agent := makeAgent(t, cb)
|
||||
srv, err := NewHTTPServer(agent, agent.config, agent.logOutput)
|
||||
if w == nil {
|
||||
w = agent.logOutput
|
||||
}
|
||||
srv, err := NewHTTPServer(agent, agent.config, w)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
@@ -45,6 +62,37 @@ func makeHTTPServer(t *testing.T, cb func(c *Config)) *TestServer {
|
||||
return s
|
||||
}
|
||||
|
||||
func BenchmarkHTTPRequests(b *testing.B) {
|
||||
s := makeHTTPServerNoLogs(b, func(c *Config) {
|
||||
c.Client.Enabled = false
|
||||
})
|
||||
defer s.Cleanup()
|
||||
|
||||
job := mock.Job()
|
||||
var allocs []*structs.Allocation
|
||||
count := 1000
|
||||
for i := 0; i < count; i++ {
|
||||
alloc := mock.Alloc()
|
||||
alloc.Job = job
|
||||
alloc.JobID = job.ID
|
||||
alloc.Name = fmt.Sprintf("my-job.web[%d]", i)
|
||||
allocs = append(allocs, alloc)
|
||||
}
|
||||
|
||||
handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
return allocs[:count], nil
|
||||
}
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
resp := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/v1/kv/key", nil)
|
||||
s.Server.wrap(handler)(resp, req)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetIndex(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
setIndex(resp, 1000)
|
||||
|
||||
Reference in New Issue
Block a user