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

性能还凑合, 大约用了4 毫秒多, 下一步看看 Google V8 的表现如何

时间: 2024-08-01 10:44:55

JavaScript 引擎性能比较之一SpiderMonkey的相关文章

关于浏览器内核与javascript引擎的一些小知识

浏览器是我们每天几乎都必须使用的软件产品,可是对于自己每天都接触的浏览器,很多同学其实对其一无所知.今天异次元就跟大家说说关于浏览器内核的一些事儿吧,好让你了解多一点稍微内在的东西. 在下面的文章中主要介绍一些常见的浏览器内核和JavaScript引擎,部分内容来自于我在网上找到的资料,还有一些是我自己的理解,不保证完全正确,但是大致应该是没错的.如果有误,请指正…… [本文原作者为武汉小狮子,xxy171070为推荐者,特此声明] 一.浏览器内核 (排版引擎/渲染引擎) 首先解释一下浏览器内核

Javascript常见性能优化

俗话说,时间就是生命,时间就是金钱,时间就是一切,人人都不想把时间白白浪费,一个网站,最重要的就是体验,而网站好不好最直观的感受就是这个网站打开速度快不快,卡不卡. 当打开一个购物网站卡出翔,慢的要死,是不是如同心塞一样的感受,蓝瘦香菇,想买个心爱的宝贝都不能买,心里想这尼玛什么玩意. 那么如何让我们的网站给用户最佳的体验呢?大环境我们不说,什么网络啊,浏览器性能啊,这些我们无法改变,我们能改变的就是我们码农能创造的,那就是代码的性能.代码精简,执行速度快,嵌套层数少等等都是我们可以着手优化注意

JavaScript引擎的工作原理

(转) 1. 什么是JavaScript解析引擎? 简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序.比方说,当你写了 var a = 1 + 1; 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2. 学过编译原理的人都知道,对于静态语言来说(如Java.C++.C),处理上述这些事情的叫编译器(Compiler),相应地对于JavaScript这样的动态语言则叫解释器(Interpre

V8 JavaScript引擎研究(一)简介

V8 JavaScript引擎简介 V8是Google公司的高效JavaScript引擎.它使用C++开发,完全开源,最著名的是使用在Chrome浏览器中作为JavaScript解析引擎. V8实现了ECMAScript-262标准,可以运行在Windows(XP及以上).Mac OS X(10.5及以上)以及使用IA-32.x64或ARM处理器的Linux系统. V8通常使用在浏览器中作为JavaScript的解析引擎,也可以嵌入到任何应用程序中使用. 基于C++的应用程序通过V8可以暴露任何

JavaScript引擎简单总结

顾名思义,JavaScript引擎就是指解析执行JavaScript脚本的虚拟机,一般附带在浏览器中,不同浏览器附带的JS引擎不同,其中Chrome的V8引擎性能十分优越. 一.微软 Chakra:译名查克拉,微软开发的JS引擎,用于IE9的32版本. 二.Mozilla SpiderMonkey:第一款JavaScript引擎,用于Mozilla Firefox 1.0~3.0版本. Rhino:由Mozilla基金会管理,开放源代码,完全以Java编写. TraceMonkey:基于实时编译

我们应该如何去了解JavaScript引擎的工作原理

我们应该如何去了解JavaScript引擎的工作原理 JavaScript探秘:编写可维护的代码的重要性 JavaScript探秘:谨慎使用全局变量 JavaScript探秘:var预解析与副作用 JavaScript探秘:for循环(for Loops) JavaScript探秘:for-in循环(for-in Loops) JavaScript探秘:Prototypes强大过头了 JavaScript探秘:eval()是"魔鬼" JavaScript探秘:用parseInt()进行

JavaScript引擎、虚拟机、运行时环境浅析

一.JavaScript引擎: 所谓JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中,用于解释和执行js脚本. 著名的js引擎: Mozilla:SpiderMonkey引擎,世界第一款JavaScript引擎,有C/C++编写,用于Mozilla Firefox 1.0-3.0版本 Google:V8引擎,由C++/汇编语言编写,用于chrome浏览器 微软:Chakra(查克拉,笑)引擎,用于Internet Explorer 9的32位版本

javascript引擎工作原理

1. 什么是JavaScript解析引擎? 简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序.比方说,当你写了 var a = 1 + 1; 这样一段代码,JavaScript引擎做的事情就是看懂(解析)你这段代码,并且将a的值变为2. 学过编译原理的人都知道,对于静态语言来说(如Java.C++.C),处理上述这些事情的叫编译器(Compiler),相应地对于JavaScript这样的动态语言则叫解释器(Interpreter)

[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285人阅读 评论(1) 收藏 举报  分类: Webkit(34)  JavascriptCore/JIT(3)  版权声明:本文为博主原创文章,未经博主允许不得转载. 看到HorkeyChen写的文章<[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现>