javascript/benchmark/index.js (240 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ const Fury = require("@furyjs/fury"); const utils = require("@furyjs/fury/dist/lib/util"); const hps = require('@furyjs/hps').default; const fury = new Fury.default({ hps, refTracking: false, useSliceString: true }); const Benchmark = require("benchmark"); const protobuf = require("protobufjs"); const path = require('path'); const Type = Fury.Type; const assert = require('assert'); const { spawn } = require("child_process"); export const data2TypeInfo = ( data, typeName, ) => { if (data === null || data === undefined) { return null; } if (Array.isArray(data)) { const item = data2TypeInfo(data[0], typeName); if (!item) { throw new Error("empty array can't convert"); } return Type.array(item); } if (data instanceof Date) { return Type.timestamp(); } if (typeof data === "string") { return Type.string(); } if (data instanceof Set) { return Type.set(data2TypeInfo([...data.values()][0], typeName)); } if (data instanceof Map) { return Type.map( data2TypeInfo([...data.keys()][0], typeName), data2TypeInfo([...data.values()][0], typeName), ); } if (typeof data === "boolean") { return Type.bool(); } if (typeof data === "number") { if (data > Number.MAX_SAFE_INTEGER || data < Number.MIN_SAFE_INTEGER) { return Type.int64(); } return Type.int32(); } if (typeof data === "object") { if (isUint8Array(data)) { return Type.binary(); } return Type.struct( { typeName }, Object.fromEntries( Object.entries(data) .map(([key, value]) => { return [key, data2TypeInfo(value, `${typeName}.${key}`)]; }) .filter(([, v]) => Boolean(v)), ), ); } throw new Error(`unkonw data type ${typeof data}`); }; const sample = { id: 123456, name: "John Doe", email: "johndoe@example.com", age: 30, address: { street: "123 Main St", city: "Anytown", state: "CA", zip: "98765", }, phoneNumbers: [ { type: "home", number: "555-1234", }, { type: "work", number: "555-5678", }, ], isMarried: true, hasChildren: false, interests: [ "reading", "hiking", "cooking", "swimming", "painting", "traveling", "photography", "playing music", "watching movies", "learning new things", "spending time with family and friends", ], education: [ { degree: "Bachelor of Science", major: "Computer Science", university: "University of California, Los Angeles", graduationYear: 2012, }, { degree: "Master of Business Administration", major: "Marketing", university: "Stanford University", graduationYear: 2016, }, ], workExperience: [ { company: "Google", position: "Software Engineer", startDate: "2012-06-01", endDate: "2014-08-31", }, { company: "Apple", position: "Product Manager", startDate: "2014-09-01", endDate: "2018-12-31", }, { company: "Amazon", position: "Senior Product Manager", startDate: "2019-01-01", endDate: "2018-12-31", }, ], selfIntroduction: `Hi, my name is John Doe and I am a highly motivated and driven individual with a passion for excellence in all areas of my life. I have a diverse background and have gained valuable experience in various fields such as software engineering, product management, and marketing. I am a graduate of the University of California, Los Angeles where I received my Bachelor of Science degree in Computer Science. After graduation, I joined Google as a software engineer where I worked on developing innovative products that revolutionized the way people interact with technology. With a desire to broaden my skillset, I pursued a Master of Business Administration degree in Marketing from Stanford University. There, I gained a deep understanding of consumer behavior and developed the ability to effectively communicate complex ideas to various stakeholders. After completing my MBA, I joined Apple as a product manager where I led the development of several successful products and played a key role in the company's growth. Currently, I am working as a Senior Product Manager at Amazon, where I am responsible for managing a team of product managers and developing cutting-edge products that meet the needs of our customers. Aside from my professional life, I am an avid reader, hiker, and cook. I enjoy spending time with my family and friends, learning new things, and traveling to new places. I believe that success is a journey, not a destination, and I am committed to continuously improving myself and achieving excellence in all that I do. `, }; const typeinfo = utils.data2TypeInfo(sample, "fury.test.foo"); const { serialize, deserialize, serializeVolatile } = fury.registerSerializer(typeinfo); const furyAb = serialize(sample); const sampleJson = JSON.stringify(sample); function loadProto() { return new Promise((resolve) => { protobuf.load(path.join(__dirname, 'sample.proto'), function (err, root) { if (err) throw err; const AwesomeMessage = root.lookupType("SomeMessage"); resolve({ encode: (payload) => { const message = AwesomeMessage.create(payload); // or use .fromObject if conversion is necessary return AwesomeMessage.encode(message).finish(); }, decode: (buffer) => { const message = AwesomeMessage.decode(buffer); return AwesomeMessage.toObject(message, { longs: String, enums: String, bytes: String, }); }, }); }); }); } async function start() { const { encode: protobufEncode, decode: protobufDecode } = await loadProto(); const protobufBf = protobufEncode(sample); { console.log('sample json size: ', `${(sampleJson.length / 1000).toFixed()}k`); assert(JSON.stringify(protobufDecode(protobufBf)) === sampleJson); assert.deepEqual(deserialize(furyAb), sample); } let result = { fury: { serialize: 0, deserialize: 0, }, protobuf: { serialize: 0, deserialize: 0, }, json: { serialize: 0, deserialize: 0, } } { var suite = new Benchmark.Suite(); suite .add("fury", function () { serializeVolatile(sample).dispose(); }) .add("json", function () { JSON.stringify(sample); }) .add("protobuf", function () { protobufEncode(sample); }) .on("complete", function (e) { e.currentTarget.forEach(({ name, hz }) => { result[name].serialize = Math.ceil(hz / 10000); }); }) .run({ async: false }); } { var suite = new Benchmark.Suite(); suite .add("fury", function () { deserialize(furyAb); }) .add("json", function () { JSON.parse(sampleJson); }) .add("protobuf", function () { protobufDecode(protobufBf); }) .on("complete", function (e) { e.currentTarget.forEach(({ name, hz }) => { result[name].deserialize = Math.ceil(hz / 10000); }); }) .run({ async: false }); } console.table(result); spawn( `python3`, ['draw.py', result.json.serialize, result.json.deserialize, result.protobuf.serialize, result.protobuf.deserialize, result.fury.serialize, result.fury.deserialize], { cwd: __dirname, } ) } start();