JavaScript 引擎性能比较之一SpiderMonkey[通俗易懂]

JavaScript 是最常用的前端语言, 在后端也渐渐有所应用, 比如 NodeJS, 在C++应用中嵌入JavaScript 到底性能如何?

就拿最流行的 Mozilla SpiderMonkey 和 Google V8 做一个比较测试, 先以 SpiderMonkey 为例, 来执行一个一万个字串的数据排序和反转

1. 下载

https://people.mozilla.org/~sstangl/mozjs-31.2.0.rc0.tar.bz2 bunzip2 mozjs-31.2.0.rc0.tar.bz2 tar xvf mozjs-31.2.0.rc0.tar 2. 构建 https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Build_Documentation 2.1 下载 autoconf2.13 http://ftp.gnu.org/gnu/autoconf/autoconf-2.13.tar.gz tar xvfz autoconf-2.13.tar.gz ./configure –prefix=/usr –program-suffix=-2.13 make acdatadir=/usr/share/autoconf-2.13 make acdatadir=/usr/share/autoconf-2.13 install 2.2 编译步骤 cd js/src autoconf-2.13 # This name should end with “_OPT.OBJ” to make the version control system ignore it. mkdir build_OPT.OBJ cd build_OPT.OBJ ../configure # Use “mozmake” on Windows make make install ———— ../../dist/bin/nsinstall -t js-config /usr/local/bin ../../dist/bin/nsinstall -t libjs_static.a /usr/local/lib mv -f /usr/local/lib/libjs_static.a /usr/local/lib/libmozjs-31.a ../../dist/bin/nsinstall -t libmozjs-31.dylib /usr/local/lib /Applications/Xcode.app/Contents/Developer/usr/bin/make -C shell install ../../../dist/bin/nsinstall -t js /usr/local/bin ———— 2.3 编译验证 # ./dist/bin/js js> print(“hello world”); hello world js> quit(); 3. 参考资料 * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_User_Guide * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/How_to_embed_the_JavaScript_engine 4. 测试程序

#include "jsapi.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#define TRACE_MINARGS 2
#define TIME_FMT_LEN 50
using namespace JS;
// The class of the global object.
static JSClass globalClass = { "global", JSCLASS_GLOBAL_FLAGS, JS_PropertyStub,
JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr, nullptr,
nullptr, nullptr, JS_GlobalObjectTraceHook };
long long current_timestamp(char arrTimeStr[TIME_FMT_LEN]) {
struct timeval tv;
struct tm* ptm;
char time_string[40];
gettimeofday(&tv, NULL); // get current time
if (arrTimeStr) {
ptm = localtime(&tv.tv_sec);
/* Format the date and time, down to a single second.  */
strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%s", ptm);
/* Compute milliseconds from microseconds.  */
//snprintf(char * restrict str, size_t size, const char * restrict format,
snprintf(arrTimeStr, TIME_FMT_LEN, "%s.%06d", time_string, tv.tv_usec);
}
long long total_us = tv.tv_sec * 1000000LL + tv.tv_usec ; // caculate milliseconds
// printf("milliseconds: %lld\n", milliseconds);
return total_us;
}
// [SpiderMonkey 24] Use JSBool instead of bool.
static bool debug_trace(jscontext *cx, unsigned argc, jsval *vp) {
JS::CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() > 0) {
char szTimeStr[TIME_FMT_LEN] = { '\0' };
current_timestamp(szTimeStr);
Jsstring *str = args[0].toString();
printf("[%s] %s\n", szTimeStr, JS_EncodeString(cx, str));
}
return true;
}
//typedef void (* JSErrorReporter)(jscontext *cx, const char *message, JSErrorReport *report);
// The error reporter callback.
void report_error(jscontext *cx, const char *message, JSErrorReport *report) {
fprintf(stderr, "%s:%u:%s\n",
report->filename ? report->filename : "[no filename]",
(unsigned int) report->lineno, message);
}
int load_file_malloc(const char* szFile, char*& pBuffer,
long* pBufSize = NULL) {
FILE * pFile = NULL;
long lSize = 0;
size_t result = 0;
pFile = fopen(szFile, "r");
if (pFile == NULL) {
fputs("File open error", stderr);
return 1;
}
// obtain file size:
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
// allocate memory to contain the whole file:
pBuffer = (char*) malloc(sizeof(char) * lSize);
if (pBuffer == NULL) {
fputs("Memory allocate error", stderr);
fclose(pFile);
return 2;
}
// copy the file into the buffer:
result = fread(pBuffer, 1, lSize, pFile);
if (result != lSize) {
fputs("Reading file error", stderr);
fclose(pFile);
return 3;
}
if (pBufSize)
*pBufSize = lSize;
fclose(pFile);
return 0;
}
int test(jscontext *cx, Rootedobject* pGlobal, const char* pScript) {
//Rootedobject global = *pGlobal;
JS::RootedValue rval(cx);
JSAutoCompartment ac(cx, *pGlobal);
JS_InitStandardClasses(cx, *pGlobal);
const char *filename = "noname";
int lineno = 1;
bool ok = JS_DefineFunction(cx, *pGlobal, "debug_trace", debug_trace,
TRACE_MINARGS, 0);
if (!ok)
return 1;
ok = JS_EvaluateScript(cx, *pGlobal, pScript, strlen(pScript), filename,
lineno, &rval);
if (!ok)
return 2;
//Jsstring *str = rval.toString();
//printf("%s\n", JS_EncodeString(cx, str));
return 0;
}
int run(jscontext *cx, const char* pScript) {
// Enter a request before running anything in the context.
JSAutoRequest ar(cx);
// Create the global object and a new compartment.
Rootedobject global(cx);
global = JS_NewGlobalObject(cx, &globalClass, nullptr,
JS::DontFireOnNewGlobalHook);
if (!global)
return 1;
// Enter the new global object's compartment.
JSAutoCompartment ac(cx, global);
// Populate the global object with the standard globals, like Object and
// Array.
if (!JS_InitStandardClasses(cx, global))
return 1;
// Your application code here. This may include JSAPI calls to create your
// own custom JS objects and run scripts.
long long begin_time = current_timestamp(NULL);
test(cx, &global, pScript);
long long end_time = current_timestamp(NULL);
printf("calling costs %lld microseconds\n", end_time - begin_time);
return 0;
}
int main(int argc, const char *argv[]) {
// Initialize the JS engine.
if (!JS_Init())
return 1;
// Create a JS runtime.
JSRuntime *rt = JS_NewRuntime(8L * 1024L * 1024L, JS_USE_HELPER_THREADS);
if (!rt)
return 1;
// Create a context.
jscontext *cx = JS_NewContext(rt, 8192);
if (!cx)
return 1;
//JS_SetErrorReporter(jscontext *cx, JSErrorReporter er);
JS_SetErrorReporter(cx, report_error);
int status = 0;
if (argc > 1) {
char* buffer = NULL;
int ret = load_file_malloc(argv[1], buffer);
if (ret != 0) {
return ret;
}
status = run(cx, buffer);
// free
if (buffer)
free(buffer);
} else {
const char *script = "'hello'+'world, it is '+new Date()";
status = run(cx, script);
}
// Shut everything down.
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
return status;
}

测试JavaScript 脚本

function random_str()
{
var text = "";
var possible = "ABCDEFGHIJKLMnopQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 8; i++ )
text += possible.charat(Math.floor(Math.random() * possible.length));
return text;
}
var array = new Array();
for ( var i = 0; i < 10000; i++) 
{
array[array.length] = random_str();
}
debug_trace("begin sort and reverse array which length=" + array.length );
array.sort();
array.reverse();
debug_trace("done, first element=" + array[0]+ ", " + "last element=" + array[array.length-1] );

测试结果

$ ./test/SpiderMonkeyTest ./test/arraysort.js

[2015-05-07 21:07:29.762895] begin sort and reverse array which length=10000 [2015-05-07 21:07:29.766270] done, first element=zzjG0Pnh, last element=0000LZbe

calling costs 52492 microseconds

性能还可以, 总执行时间花费52 毫秒, JS数组排序反转大约用了4 毫秒多, 下一步看看 Google V8 的表现如何

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/184323.html原文链接:https://javaforall.cn

相关文章

应用场景 C端用户提交工单、工单创建完成之后、会发布一条工...
线程类,设置有一个公共资源 package cn.org.chris.concurre...
Java中的数字(带有0前缀和字符串)
在Java 9中使用JLink的目的是什么?
Java Stream API Filter(过滤器)
在Java中找到正数和负数数组元素的数量