json 性能比较

Json benchmark环境配置

使用nativejson-benchmark作性能测试benchmark。 按照nativejson-benchmark中[Build and Run]一节编译环境,注意对于苹果m1电脑,需要在nativejson-benchmark/build/premake5.lua中修改:

1
buildoptions "-mcpu=apple-m1 -Wall -Wextra"

如果用xcode自带clang编译器编译失败,可以安装llvm:

1
2
3
4
5
6
7
brew install llvm
open ~/.bash_profile
// 添加一下命令 到bash_profile
// export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
// export LDFLAGS="-L/opt/homebrew/opt/llvm/lib"
// export CPPFLAGS="-I/opt/homebrew/opt/llvm/include"
source ~/.bash_profile

新增新的json测试单元,以yaml-cpp为例子

  1. Git clone yaml-cpp 到nativejson-benchmark/thirdparty/yaml-cpp并按照官方教程编译静态库。
  2. 在nativejson-benchmark/src/tests新增yamlcpptest.cpp:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "../test.h"
#include "yaml-cpp/yaml.h"

using namespace YAML;

static void GenStat(Stat& stat, const Node &v)
{
    switch (v.Type())
    {
        case NodeType::Null:
        {
            stat.nullCount++;
            break;
        }
        case NodeType::Scalar:
        {
            std::string scalar = v.Scalar();
            if(scalar == "true")
            {
                stat.trueCount++;
                stat.stringLength += scalar.size();
            }
            else if(scalar == "false")
            {
                stat.falseCount++;
                stat.stringLength += scalar.size();
            }
            else if (scalar == "null")
            {
                stat.nullCount++;
                stat.stringLength += scalar.size();
            }
            double tDouble = 0.0;
            if (convert<double>::decode(v, tDouble))
            {
                stat.numberCount++;
            }
            else
                stat.stringCount++;
            break;
        }
        case NodeType::Sequence:
        {
            uint32_t size = 0;
            for(const auto& i : v)
            {
                size++;
                GenStat(stat, i);
            }
            stat.arrayCount++;
            stat.elementCount += size;
            break;
        }
        case NodeType::Map:
        {
            uint32_t size = 0;
            for (auto it = v.begin(); it != v.end(); ++it)
            {
                size++;
                std::string key = it->first.as<std::string>();
                Node value = it->second;
                GenStat(stat, value);
                stat.stringLength += key.size();
            }
            stat.objectCount++;
            stat.memberCount += size;
            stat.stringCount += size;
            break;
        }
        default:
            break;
    }
}

class YamlCppParseResult : public ParseResultBase {
public:
    YamlCppParseResult() {}
    ~YamlCppParseResult() {}
    Node node;
};

class YamlCppStringResult : public StringResultBase {
public:
    virtual const char* c_str() const { return str.c_str(); }
    std::string str;
};

class YamlCppTest : public TestBase {
public:
#if TEST_INFO
    virtual const char* GetName() const { return "YamlCpp (C++11)"; }
    virtual const char* GetFilename() const { return __FILE__; }
#endif

#if TEST_PARSE
virtual ParseResultBase* Parse(const char* json, size_t length) const {
        (void)length;
    YamlCppParseResult *pr = new YamlCppParseResult;
    try {
            pr->node = Load(json);
        }
        catch (...) {
            delete pr;
            return 0;
        }
        return pr;
}
#endif

#if TEST_STRINGIFY
virtual StringResultBase* Stringify(const ParseResultBase* parseResult) const {
    const YamlCppParseResult* pr = static_cast<const YamlCppParseResult*>(parseResult);
    YamlCppStringResult* sr = new YamlCppStringResult;
    // this implement is not right, just for Stringify test
    sr->str = pr->node.Scalar();
    return sr;
  }
#endif

#if TEST_PRETTIFY
virtual StringResultBase* Prettify(const ParseResultBase* parseResult) const {
    const YamlCppParseResult* pr = static_cast<const YamlCppParseResult*>(parseResult);
    YamlCppStringResult* sr = new YamlCppStringResult;
    // this implement is not right, just for Stringify test
    sr->str = pr->node.Scalar();
    return sr;
  }
#endif

#if TEST_STATISTICS
virtual bool Statistics(const ParseResultBase* parseResult, Stat* stat) const {
    const YamlCppParseResult* pr = static_cast<const YamlCppParseResult*>(parseResult);
    memset(stat, 0, sizeof(Stat));
    GenStat(*stat, pr->node);
    return true;
}
#endif

#if TEST_CONFORMANCE
    virtual bool ParseDouble(const char* json, double* d) const {
        Node node;
        node = Load(json);
        if(!node.IsNull() && node.IsSequence() && node.size() == 1 && node[0].IsScalar())
        {
            double tDouble = 0.0;
            if (convert<double>::decode(node[0], tDouble))
            {
                *d = tDouble;
                return true;
            }
        }
        return false;
    }

    // virtual bool ParseString(const char* json, std::string& s) const {
    //     Node node;
    //     node = Load(json);
    //     if (!node.IsNull() && node.IsScalar()) {
    //         std::string str = node.Scalar();
    //         s = str;
    //         return true;
    //     }
    //     return false;
    // }
#endif
};

REGISTER_TEST(YamlCppTest);
  1. 在nativejson-benchmark/build/premake5.lua中新增yaml-cpp到头文件和库文件
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
function setTargetObjDir(outDir)
	targetdir(outDir)
	objdir(string.lower("../intermediate/%{cfg.shortname}/" .. _ACTION))
	targetsuffix(string.lower("_%{cfg.shortname}_" .. _ACTION))
end

function copyfiles(dstDir, srcWildcard)
	os.mkdir(dstDir)
	local matches = os.matchfiles(srcWildcard)
	for _, f in ipairs(matches) do
		local filename = string.match(f, ".-([^\\/]-%.?[^%.\\/]*)$")
		os.copyfile(f, dstDir .. "/" .. filename)
	end
end

function gmake_common()
    buildoptions "-mcpu=apple-m1 -Wall -Wextra"
    -- buildoptions "-march=x86_64 -Wall -Wextra"
    if (os.findlib("boost_system")) then
        defines { "HAS_BOOST=1" }
        links { "boost_system" }
    end

    -- On some boost distributions, the naming contains -mt suffixes
    if (os.findlib("boost_thread")) then
        links  { "boost_thread" }
    elseif (os.findlib("boost_thread-mt")) then
        links  { "boost_thread-mt" }
    end

    if (os.findlib("boost_locale")) then
        links  { "boost_locale" }
    elseif (os.findlib("boost_locale-mt")) then
        links  { "boost_locale-mt" }
    end

    -- For clock_gettime in jvar
    if (os.findlib("rt")) then
        links  { "rt" }
    end

    if (os.findlib("PocoJSON")) then
        defines { "HAS_POCO=1" }
        links { "PocoFoundation", "PocoJSON" }
    end

    if (os.findlib("folly")) then
        defines { "HAS_FOLLY=1" }
        links { "folly" }
    end

    if (os.findlib("v8")) then
        defines { "HAS_V8=1" }
        links { "v8_base", "v8_libbase", "v8_libplatform", "v8_nosnapshot" }
    end

    if (os.findlib("libcpprest")) then
        defines { "HAS_CPPREST=1" }
        links { "cpprest"}
    end

    configuration "macosx"
        if (os.isdir("/usr/local/opt/qt5/include")) then
            defines { "HAS_QT=1" }
            links { "QtCore.framework" }
            includedirs { "/usr/local/opt/qt5/include" }
            linkoptions { "-F /usr/local/opt/qt5/lib" }
        end

        -- Temp fix for OSX brew + V8 include path issue
        if (os.isdir("/usr/local/opt/v8/")) then
            includedirs { "/usr/local/opt/v8/" }
        end
end

solution "benchmark"
	configurations { "release" }
	platforms { "x32", "x64" }

	location ("./" .. (_ACTION or ""))
	language "C++"
	flags { "ExtraWarnings" }
	defines { "__STDC_FORMAT_MACROS=1" }

	configuration "release"
		defines { "NDEBUG" }
		optimize "Full"

	configuration "vs*"
		defines { "_CRT_SECURE_NO_WARNINGS" }

	configuration "gmake"
		gmake_common()

	project "jsonclibs"
		kind "StaticLib"

        includedirs {
            "../thirdparty/",
            "../thirdparty/include/",
            "../thirdparty/ujson4c/3rdparty/",
            "../thirdparty/pjson/inc/",
  			"../thirdparty/udp-json-parser/",
            "../thirdparty/facil.io/lib/facil/core/types",
            "../thirdparty/facil.io/lib/facil/core/types/fiobj",
        }

		files {
			"../src/**.c",
		}

		setTargetObjDir("../bin")

		copyfiles("../thirdparty/include/yajl", "../thirdparty/yajl/src/api/*.h" )

	project "nativejson"
		kind "ConsoleApp"

        includedirs {
            "../thirdparty/",
            "../thirdparty/fastjson/include/",
            "../thirdparty/jsonbox/include/",
            "../thirdparty/jsoncpp/include/",
            "../thirdparty/rapidjson/include/",
            "../thirdparty/yaml-cpp/include/",
            "../thirdparty/udp-json-parser/",
            "../thirdparty/include/",
            "../thirdparty/json-voorhees/include",
            "../thirdparty/json-voorhees/src",
            "../thirdparty/jsoncons/src",
            "../thirdparty/ArduinoJson/include",
            "../thirdparty/include/jeayeson/include/dummy",
  			"../thirdparty/jvar/include",
            "../thirdparty/pjson/inc",
            "../thirdparty/facil.io/lib/facil/core/types",
            "../thirdparty/facil.io/lib/facil/core/types/fiobj",
            "../thirdparty/simdjson/singleheader",
            "../thirdparty/boost/libs/json/include",
            "../thirdparty/boost/libs/config/include",
            "../thirdparty/boost/libs/assert/include",
            "../thirdparty/boost/libs/exception/include",
            "../thirdparty/boost/libs/throw_exception/include",
            "../thirdparty/boost/libs/core/include",
            "../thirdparty/boost/libs/container/include",
            "../thirdparty/boost/libs/move/include",
            "../thirdparty/boost/libs/static_assert/include",
            "../thirdparty/boost/libs/intrusive/include",
            "../thirdparty/boost/libs/system/include",
            "../thirdparty/boost/libs/mp11/include",
            "../thirdparty/boost/libs/align/include",
        }

        linkoptions { "../../thirdparty/yaml-cpp/build/libyaml-cpp.a" }

		files {
			"../src/*.h",
			"../src/*.cpp",
			"../src/tests/*.cpp"
		}

		libdirs { "../bin",
                "../thirdparty/simdjson",
                }

		setTargetObjDir("../bin")

		-- linkLib("jsonclibs")
		links "jsonclibs"

		configuration "gmake"
			buildoptions "-std=c++14"

solution "jsonstat"
    configurations { "release" }
    platforms { "x32", "x64" }
    location ("./" .. (_ACTION or ""))
    language "C++"
    flags { "ExtraWarnings" }

    defines {
    	"USE_MEMORYSTAT=0",
    	"TEST_PARSE=1",
    	"TEST_STRINGIFY=0",
    	"TEST_PRETTIFY=0",
    	"TEST_TEST_STATISTICS=1",
    	"TEST_SAXROUNDTRIP=0",
    	"TEST_SAXSTATISTICS=0",
    	"TEST_SAXSTATISTICSUTF16=0",
    	"TEST_CONFORMANCE=0",
    	"TEST_INFO=0"
	}

    includedirs {
        "../thirdparty/",
        "../thirdparty/fastjson/include/",
        "../thirdparty/jsonbox/include/",
        "../thirdparty/jsoncpp/include/",
        "../thirdparty/rapidjson/include/",
        "../thirdparty/yaml-cpp/include/",
        "../thirdparty/udp-json-parser/",
        "../thirdparty/include/",
        "../thirdparty/json-voorhees/include",
        "../thirdparty/json-voorhees/src",
        "../thirdparty/jsoncons/src",
        "../thirdparty/ArduinoJson/include",
        "../thirdparty/include/jeayeson/include/dummy",
        "../thirdparty/jvar/include",
        "../thirdparty/pjson/inc",
        "../thirdparty/facil.io/lib/facil/core/types",
        "../thirdparty/facil.io/lib/facil/core/types/fiobj",
        "../thirdparty/simdjson/singleheader",
        "../thirdparty/boost/libs/json/include",
        "../thirdparty/boost/libs/config/include",
        "../thirdparty/boost/libs/assert/include",
        "../thirdparty/boost/libs/exception/include",
        "../thirdparty/boost/libs/throw_exception/include",
        "../thirdparty/boost/libs/core/include",
        "../thirdparty/boost/libs/container/include",
        "../thirdparty/boost/libs/move/include",
        "../thirdparty/boost/libs/static_assert/include",
        "../thirdparty/boost/libs/intrusive/include",
        "../thirdparty/boost/libs/system/include",
        "../thirdparty/boost/libs/mp11/include",
        "../thirdparty/boost/libs/align/include",
    }

    configuration "release"
        defines { "NDEBUG" }
        optimize "Full"

    configuration "vs*"
        defines { "_CRT_SECURE_NO_WARNINGS" }

	configuration "gmake"
        gmake_common()

	project "jsonclibs2"
		kind "StaticLib"

        includedirs {
            "../thirdparty/",
            "../thirdparty/include/",
            "../thirdparty/ujson4c/3rdparty/",
  			"../thirdparty/udp-json-parser/",
            "../thirdparty/facil.io/lib/facil/core/types",
            "../thirdparty/facil.io/lib/facil/core/types/fiobj",
        }

		files {
			"../src/**.c",
		}

        setTargetObjDir("../bin/jsonstat")

		copyfiles("../thirdparty/include/yajl", "../thirdparty/yajl/src/api/*.h", "../thirdparty/simdjson/src/simdjson.cpp")

    local testfiles = os.matchfiles("../src/tests/*.cpp")
    for _, testfile in ipairs(testfiles) do
        project("jsonstat_" .. path.getbasename(testfile))
            kind "ConsoleApp"
            files {
            	"../src/jsonstat/jsonstatmain.cpp",
            	"../src/memorystat.cpp",
            	testfile
			}
			libdirs { "../bin/jsonstat" }
			links "jsonclibs2"
            setTargetObjDir("../bin/jsonstat")

            linkoptions { "../../thirdparty/yaml-cpp/build/libyaml-cpp.a" }

			configuration "gmake"
				buildoptions "-std=c++14"
    end

json数据对比

捕获.PNG 捕获1.PNG 捕获2.PNG 捕获3.PNG 捕获4.PNG 捕获5.PNG

updatedupdated2023-03-042023-03-04