{"action":"created","issue":{"url":"https://api.github.com/repos/pquerna/ffjson/issues/136","labels_url":"https://api.github.com/repos/pquerna/ffjson/issues/136/labels{/name}","comments_url":"https://api.github.com/repos/pquerna/ffjson/issues/136/comments","events_url":"https://api.github.com/repos/pquerna/ffjson/issues/136/events","html_url":"https://github.com/pquerna/ffjson/issues/136","id":71337449,"number":136,"title":"Slower than encoding/json at all levels of GOMAXPROCS (8 cores, i7 macbook pro 16gb ram)","user":{"login":"momer","id":1387974,"avatar_url":"https://avatars.githubusercontent.com/u/1387974?v=3","gravatar_id":"","url":"https://api.github.com/users/momer","html_url":"https://github.com/momer","followers_url":"https://api.github.com/users/momer/followers","following_url":"https://api.github.com/users/momer/following{/other_user}","gists_url":"https://api.github.com/users/momer/gists{/gist_id}","starred_url":"https://api.github.com/users/momer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/momer/subscriptions","organizations_url":"https://api.github.com/users/momer/orgs","repos_url":"https://api.github.com/users/momer/repos","events_url":"https://api.github.com/users/momer/events{/privacy}","received_events_url":"https://api.github.com/users/momer/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-04-27T16:33:02Z","updated_at":"2015-04-27T21:29:22Z","closed_at":null,"body":"All, my results of running benchmarks against `ffjson` and `encoding/json` show that `ffjson` does not meet the claims of being 2-3x faster than `encoding/json`; and, in-fact, is much slower.\r\n\r\nShould the documentation be revised, or did I do something 'wrong'?\r\n\r\nResults (GOMAXPROCS 1): \r\n\r\n    MyComp:gotestffjson mo.omer$ ffjson ./main.go\r\n    ./main_ffjson.go\r\n    MyComp:gotestffjson mo.omer$ ./main\r\n    2015/04/27 11:34:35 GOMAXPROCS:  1\r\n    2015/04/27 11:34:41 encoding/json Marshal Function:   1000000         1297 ns/op\r\n    2015/04/27 11:34:41 encoding/json Encoder Function:   1000000         1121 ns/op\r\n    2015/04/27 11:34:41 ffjson Marshal Function:   1000000        1385 ns/op\r\n    2015/04/27 11:34:41 ffjson Encoder Function:   1000000        1888 ns/op\r\n\r\n\r\nResults (GOMAXPROCS: 8):\r\n\r\n    MyComp:gotestffjson mo.omer$ ./main\r\n    2015/04/27 11:30:18 GOMAXPROCS:  8\r\n    2015/04/27 11:30:24 encoding/json Marshal Function:   1000000         1024 ns/op\r\n    2015/04/27 11:30:24 encoding/json Encoder Function:   2000000          973 ns/op\r\n    2015/04/27 11:30:24 ffjson Marshal Function:   1000000        1093 ns/op\r\n    2015/04/27 11:30:24 ffjson Encoder Function:   1000000        1488 ns/op\r\n\r\nmain.go:\r\n\r\n    package main\r\n    \r\n    import (\r\n    \t\"encoding/json\"\r\n    \t\"github.com/pquerna/ffjson/ffjson\"\r\n    \t\"io\"\r\n    \t\"log\"\r\n    \t\"net/http/httptest\"\r\n    \t\"runtime\"\r\n    \t\"testing\"\r\n    )\r\n    \r\n    const helloWorldString = \"Hello, World!\"\r\n    \r\n    type Message struct {\r\n    \tMessage string `json:\"message\"`\r\n    }\r\n    \r\n    func Encode(item interface{}, out io.Writer) {\r\n    \t// Encode\r\n    \tbuf, err := ffjson.Marshal(&item)\r\n    \tif err != nil {\r\n    \t\tlog.Fatalf(\"Error: %+v\\n\", err)\r\n    \t}\r\n    \r\n    \t// Write the buffer\r\n    \t_, _ = out.Write(buf)\r\n    \r\n    \t// We are now no longer need the buffer so we pool it.\r\n    \tffjson.Pool(buf)\r\n    }\r\n    \r\n    func encoderFunction(b *testing.B) {\r\n    \tfor i := 0; i < b.N; i++ {\r\n    \t\tw := httptest.NewRecorder()\r\n    \t\t_ = json.NewEncoder(w).Encode(&Message{helloWorldString})\r\n    \t}\r\n    }\r\n    \r\n    func ffencoderFunction(b *testing.B) {\r\n    \tfor i := 0; i < b.N; i++ {\r\n    \t\tw := httptest.NewRecorder()\r\n    \t\tEncode(&Message{helloWorldString}, w)\r\n    \t}\r\n    }\r\n    \r\n    func marshalFunction(b *testing.B) {\r\n    \tfor i := 0; i < b.N; i++ {\r\n    \t\tw := httptest.NewRecorder()\r\n    \t\ta, _ := json.Marshal(&Message{helloWorldString})\r\n    \t\tw.Write(a)\r\n    \t}\r\n    }\r\n    \r\n    func ffmarshalFunction(b *testing.B) {\r\n    \tfor i := 0; i < b.N; i++ {\r\n    \t\tw := httptest.NewRecorder()\r\n    \t\ta, _ := ffjson.Marshal(&Message{helloWorldString})\r\n    \t\tw.Write(a)\r\n    \t}\r\n    }\r\n    \r\n    func main() {\r\n\r\n        // numProcs := runtime.NumCPU()\r\n        numProcs := 1\r\n        runtime.GOMAXPROCS(numProcs)\r\n        log.Println(\"GOMAXPROCS: \", numProcs)\r\n    \r\n    \tffmf := testing.Benchmark(ffmarshalFunction)\r\n    \tffef := testing.Benchmark(ffencoderFunction)\r\n    \tmf := testing.Benchmark(marshalFunction)\r\n    \tef := testing.Benchmark(encoderFunction)\r\n    \r\n    \tlog.Println(\"encoding/json Marshal Function: \", mf)\r\n    \tlog.Println(\"encoding/json Encoder Function: \", ef)\r\n    \r\n    \tlog.Println(\"ffjson Marshal Function: \", ffmf)\r\n    \tlog.Println(\"ffjson Encoder Function: \", ffef)\r\n    } \r\n\r\nmain_ffjson.go:\r\n\r\n    // DO NOT EDIT!\r\n    // Code generated by ffjson <https://github.com/pquerna/ffjson>\r\n    // source: ./main.go\r\n    // DO NOT EDIT!\r\n    \r\n    package main\r\n    \r\n    import (\r\n    \t\"bytes\"\r\n    \t\"fmt\"\r\n    \tfflib \"github.com/pquerna/ffjson/fflib/v1\"\r\n    )\r\n    \r\n    func (mj *Message) MarshalJSON() ([]byte, error) {\r\n    \tvar buf fflib.Buffer\r\n    \terr := mj.MarshalJSONBuf(&buf)\r\n    \tif err != nil {\r\n    \t\treturn nil, err\r\n    \t}\r\n    \treturn buf.Bytes(), nil\r\n    }\r\n    func (mj *Message) MarshalJSONBuf(buf fflib.EncodingBuffer) error {\r\n    \tvar err error\r\n    \tvar obj []byte\r\n    \t_ = obj\r\n    \t_ = err\r\n    \tbuf.WriteString(`{\"message\":`)\r\n    \tfflib.WriteJsonString(buf, string(mj.Message))\r\n    \tbuf.WriteByte('}')\r\n    \treturn nil\r\n    }\r\n    \r\n    const (\r\n    \tffj_t_Messagebase = iota\r\n    \tffj_t_Messageno_such_key\r\n    \r\n    \tffj_t_Message_Message\r\n    )\r\n    \r\n    var ffj_key_Message_Message = []byte(\"message\")\r\n    \r\n    func (uj *Message) UnmarshalJSON(input []byte) error {\r\n    \tfs := fflib.NewFFLexer(input)\r\n    \treturn uj.UnmarshalJSONFFLexer(fs, fflib.FFParse_map_start)\r\n    }\r\n    \r\n    func (uj *Message) UnmarshalJSONFFLexer(fs *fflib.FFLexer, state fflib.FFParseState) error {\r\n    \tvar err error = nil\r\n    \tcurrentKey := ffj_t_Messagebase\r\n    \t_ = currentKey\r\n    \ttok := fflib.FFTok_init\r\n    \twantedTok := fflib.FFTok_init\r\n    \r\n    mainparse:\r\n    \tfor {\r\n    \t\ttok = fs.Scan()\r\n    \t\t//\tprintln(fmt.Sprintf(\"debug: tok: %v  state: %v\", tok, state))\r\n    \t\tif tok == fflib.FFTok_error {\r\n    \t\t\tgoto tokerror\r\n    \t\t}\r\n    \r\n    \t\tswitch state {\r\n    \r\n    \t\tcase fflib.FFParse_map_start:\r\n    \t\t\tif tok != fflib.FFTok_left_bracket {\r\n    \t\t\t\twantedTok = fflib.FFTok_left_bracket\r\n    \t\t\t\tgoto wrongtokenerror\r\n    \t\t\t}\r\n    \t\t\tstate = fflib.FFParse_want_key\r\n    \t\t\tcontinue\r\n    \r\n    \t\tcase fflib.FFParse_after_value:\r\n    \t\t\tif tok == fflib.FFTok_comma {\r\n    \t\t\t\tstate = fflib.FFParse_want_key\r\n    \t\t\t} else if tok == fflib.FFTok_right_bracket {\r\n    \t\t\t\tgoto done\r\n    \t\t\t} else {\r\n    \t\t\t\twantedTok = fflib.FFTok_comma\r\n    \t\t\t\tgoto wrongtokenerror\r\n    \t\t\t}\r\n    \r\n    \t\tcase fflib.FFParse_want_key:\r\n    \t\t\t// json {} ended. goto exit. woo.\r\n    \t\t\tif tok == fflib.FFTok_right_bracket {\r\n    \t\t\t\tgoto done\r\n    \t\t\t}\r\n    \t\t\tif tok != fflib.FFTok_string {\r\n    \t\t\t\twantedTok = fflib.FFTok_string\r\n    \t\t\t\tgoto wrongtokenerror\r\n    \t\t\t}\r\n    \r\n    \t\t\tkn := fs.Output.Bytes()\r\n    \t\t\tif len(kn) <= 0 {\r\n    \t\t\t\t// \"\" case. hrm.\r\n    \t\t\t\tcurrentKey = ffj_t_Messageno_such_key\r\n    \t\t\t\tstate = fflib.FFParse_want_colon\r\n    \t\t\t\tgoto mainparse\r\n    \t\t\t} else {\r\n    \t\t\t\tswitch kn[0] {\r\n    \r\n    \t\t\t\tcase 'm':\r\n    \r\n    \t\t\t\t\tif bytes.Equal(ffj_key_Message_Message, kn) {\r\n    \t\t\t\t\t\tcurrentKey = ffj_t_Message_Message\r\n    \t\t\t\t\t\tstate = fflib.FFParse_want_colon\r\n    \t\t\t\t\t\tgoto mainparse\r\n    \t\t\t\t\t}\r\n    \r\n    \t\t\t\t}\r\n    \r\n    \t\t\t\tif fflib.EqualFoldRight(ffj_key_Message_Message, kn) {\r\n    \t\t\t\t\tcurrentKey = ffj_t_Message_Message\r\n    \t\t\t\t\tstate = fflib.FFParse_want_colon\r\n    \t\t\t\t\tgoto mainparse\r\n    \t\t\t\t}\r\n    \r\n    \t\t\t\tcurrentKey = ffj_t_Messageno_such_key\r\n    \t\t\t\tstate = fflib.FFParse_want_colon\r\n    \t\t\t\tgoto mainparse\r\n    \t\t\t}\r\n    \r\n    \t\tcase fflib.FFParse_want_colon:\r\n    \t\t\tif tok != fflib.FFTok_colon {\r\n    \t\t\t\twantedTok = fflib.FFTok_colon\r\n    \t\t\t\tgoto wrongtokenerror\r\n    \t\t\t}\r\n    \t\t\tstate = fflib.FFParse_want_value\r\n    \t\t\tcontinue\r\n    \t\tcase fflib.FFParse_want_value:\r\n    \r\n    \t\t\tif tok == fflib.FFTok_left_brace || tok == fflib.FFTok_left_bracket || tok == fflib.FFTok_integer || tok == fflib.FFTok_double || tok == fflib.FFTok_string || tok == fflib.FFTok_bool || tok == fflib.FFTok_null {\r\n    \t\t\t\tswitch currentKey {\r\n    \r\n    \t\t\t\tcase ffj_t_Message_Message:\r\n    \t\t\t\t\tgoto handle_Message\r\n    \r\n    \t\t\t\tcase ffj_t_Messageno_such_key:\r\n    \t\t\t\t\terr = fs.SkipField(tok)\r\n    \t\t\t\t\tif err != nil {\r\n    \t\t\t\t\t\treturn fs.WrapErr(err)\r\n    \t\t\t\t\t}\r\n    \t\t\t\t\tstate = fflib.FFParse_after_value\r\n    \t\t\t\t\tgoto mainparse\r\n    \t\t\t\t}\r\n    \t\t\t} else {\r\n    \t\t\t\tgoto wantedvalue\r\n    \t\t\t}\r\n    \t\t}\r\n    \t}\r\n    \r\n    handle_Message:\r\n    \r\n    \t/* handler: uj.Message type=string kind=string */\r\n    \r\n    \t{\r\n    \r\n    \t\t{\r\n    \t\t\tif tok != fflib.FFTok_string && tok != fflib.FFTok_null {\r\n    \t\t\t\treturn fs.WrapErr(fmt.Errorf(\"cannot unmarshal %s into Go value for string\", tok))\r\n    \t\t\t}\r\n    \t\t}\r\n    \r\n    \t\tif tok == fflib.FFTok_null {\r\n    \r\n    \t\t} else {\r\n    \r\n    \t\t\tuj.Message = string(fs.Output.String())\r\n    \r\n    \t\t}\r\n    \t}\r\n    \r\n    \tstate = fflib.FFParse_after_value\r\n    \tgoto mainparse\r\n    \r\n    wantedvalue:\r\n    \treturn fs.WrapErr(fmt.Errorf(\"wanted value token, but got token: %v\", tok))\r\n    wrongtokenerror:\r\n    \treturn fs.WrapErr(fmt.Errorf(\"ffjson: wanted token: %v, but got token: %v output=%s\", wantedTok, tok, fs.Output.String()))\r\n    tokerror:\r\n    \tif fs.BigError != nil {\r\n    \t\treturn fs.WrapErr(fs.BigError)\r\n    \t}\r\n    \terr = fs.Error.ToError()\r\n    \tif err != nil {\r\n    \t\treturn fs.WrapErr(err)\r\n    \t}\r\n    \tpanic(\"ffjson-generated: unreachable, please report bug.\")\r\n    done:\r\n    \treturn nil\r\n    }"},"comment":{"url":"https://api.github.com/repos/pquerna/ffjson/issues/comments/96827387","html_url":"https://github.com/pquerna/ffjson/issues/136#issuecomment-96827387","issue_url":"https://api.github.com/repos/pquerna/ffjson/issues/136","id":96827387,"user":{"login":"momer","id":1387974,"avatar_url":"https://avatars.githubusercontent.com/u/1387974?v=3","gravatar_id":"","url":"https://api.github.com/users/momer","html_url":"https://github.com/momer","followers_url":"https://api.github.com/users/momer/followers","following_url":"https://api.github.com/users/momer/following{/other_user}","gists_url":"https://api.github.com/users/momer/gists{/gist_id}","starred_url":"https://api.github.com/users/momer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/momer/subscriptions","organizations_url":"https://api.github.com/users/momer/orgs","repos_url":"https://api.github.com/users/momer/repos","events_url":"https://api.github.com/users/momer/events{/privacy}","received_events_url":"https://api.github.com/users/momer/received_events","type":"User","site_admin":false},"created_at":"2015-04-27T21:29:22Z","updated_at":"2015-04-27T21:29:22Z","body":"The ffjson code was generated before the build, of course. Good catch on the usage of the ffjson methods in the encoding/json benchmarks, though!\r\n\r\nI didn't test the ffjson Encoder, but rather the README Encode func, but it seems that the Encoder func you used closed the performance gap from ~50% slower to ~25% slower.\r\n\r\nMarshalFast seems like the way to go, as it's around 38% faster on your machine.\r\n\r\nFfjson is a really interesting and fun project; however, the claims are \"2-3x\" faster, which are false. Additionally, the tuned encoder methods are still 25% slower. \r\n\r\nThoughts on either addressing the performance or documentation?"}}