`
chaoslawful
  • 浏览: 198436 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

通过lua-tcc内联c提升关键代码效率

阅读更多

tcc 是一个很有趣的小型 C 编译器,其最大的特点是可以实现即时编译 C 代码,无需产生中间文件即可生成 native code,且将内部功能全部作为库函数暴露出来,可以很方便地嵌入到自己的应用中。

 

目前有一些现成的 lua 模块可以将 tcc 引入到 lua 里,用其即时生成 C-function 供 lua 使用。其中 lua-tcc 是最简单的一个,但代码年代较久,需要进行 patch 才可同最新的 tcc-0.9.25 一同工作,patch 后的代码参见这里

 

下面是一个例子,对比了 lua 原生的 json 解析器 json4lua 和通过 tcc 内联的 c json 解析器 yajl 的效率(需预先安装 json4lualua-tcc 以及 yajl ):

local json = require("json")
local tcc = require("lua_tcc")
yajl = tcc.compile([=[
	#include <lua.h>
	#include <lualib.h>
	#include <lauxlib.h>
	#include <yajl/yajl_parse.h>
	#include <stdlib.h>
	#include <errno.h>

	/* FIXME: maximum container nesting level hardcoded to 512 */
	#define MAX_NEST_LEVEL 512

	typedef struct {
		lua_State *L;
		int curr_level;
		enum {not_in_container, in_map, in_array} env[MAX_NEST_LEVEL];
		int start_of_container[MAX_NEST_LEVEL];
	} parse_ctx_t;

	int parse_null(void *ctx)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		lua_pushnil(c->L);
		switch(c->env[c->curr_level]) {
			case in_map:
				/* nothing to do, push prev pair until the next pair key appears or map is end */
				break;
			case in_array:
				lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
				break;
			default:
				break;
		}
		return 1;
	}

	int parse_boolean(void *ctx, int bool_val)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		lua_pushboolean(c->L, bool_val);
		switch(c->env[c->curr_level]) {
			case in_map:
				/* nothing to do, push prev pair until the next pair key appears or map is end */
				break;
			case in_array:
				lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
				break;
			default:
				break;
		}
		return 1;
	}

	int parse_integer(void *ctx, long int_val)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		lua_pushinteger(c->L, (lua_Integer)int_val);
		switch(c->env[c->curr_level]) {
			case in_map:
				/* nothing to do, push prev pair until the next pair key appears or map is end */
				break;
			case in_array:
				lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
				break;
			default:
				break;
		}
		return 1;
	}

	int parse_double(void *ctx, double dbl_val)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		lua_pushnumber(c->L, (lua_Number)dbl_val);
		switch(c->env[c->curr_level]) {
			case in_map:
				/* nothing to do, push prev pair until the next pair key appears or map is end */
				break;
			case in_array:
				lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
				break;
			default:
				break;
		}
		return 1;
	}

	int parse_string(void *ctx, const unsigned char *str_val, unsigned int str_len)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		lua_pushlstring(c->L, (const char*)str_val, str_len);
		switch(c->env[c->curr_level]) {
			case in_map:
				/* nothing to do, push prev pair until the next pair key appears or map is end */
				break;
			case in_array:
				lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
				break;
			default:
				break;
		}
		return 1;
	}

	int parse_start_map(void *ctx)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		switch(c->env[c->curr_level]) {
			case in_map:
			case in_array:
			default:
				lua_newtable(c->L);
				c->curr_level++;
				c->env[c->curr_level] = in_map;
				c->start_of_container[c->curr_level] = 1;
				break;
		}
		return 1;
	}

	int parse_map_key(void *ctx, const unsigned char *key, unsigned int len)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		
		switch(c->env[c->curr_level]) {
			case in_map:
				/* store prev pair */
				if(c->start_of_container[c->curr_level]) {
					c->start_of_container[c->curr_level] = 0;
				} else {
					lua_rawset(c->L, -3);
				}

				/* push new pair's key */
				lua_pushlstring(c->L, (const char*)key, len);

				break;
			case in_array:
			default:
				return 0;
		}
		return 1;
	}

	int parse_end_map(void *ctx)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		
		switch(c->env[c->curr_level]) {
			case in_map:
				/* store prev pair */
				lua_rawset(c->L, -3);

				c->curr_level--;
				switch(c->env[c->curr_level]) {
					case in_array:
						lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
						break;
					case in_map:
					default:
						break;
				}
				break;
			case in_array:
			default:
				return 0;
		}
		return 1;
	}

	int parse_start_array(void *ctx)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		
		switch(c->env[c->curr_level]) {
			case in_map:
			case in_array:
			default:
				lua_newtable(c->L);
				c->curr_level++;
				c->env[c->curr_level] = in_array;
				c->start_of_container[c->curr_level] = 1;
				break;
		}
		return 1;
	}
	
	int parse_end_array(void *ctx)
	{
		parse_ctx_t *c = (parse_ctx_t*)ctx;
		
		switch(c->env[c->curr_level]) {
			case in_array:
				c->curr_level--;
				switch(c->env[c->curr_level]) {
					case in_array:
						lua_rawseti(c->L, -2, lua_objlen(c->L, -2)+1);
						break;
					case in_map:
					default:
						break;
				}
				break;
			case in_map:
			default:
				return 0;
		}
		return 1;
	}

	int parse_json(lua_State *L)
	{
		static yajl_parser_config _config = {
			allowComments: 1,
			checkUTF8: 1
		};
		static yajl_callbacks _callbacks = {
			yajl_null: parse_null,
			yajl_boolean: parse_boolean,
			yajl_integer: parse_integer,
			yajl_double: parse_double,
			yajl_number: NULL,
			yajl_string: parse_string,
			yajl_start_map: parse_start_map,
			yajl_map_key: parse_map_key,
			yajl_end_map: parse_end_map,
			yajl_start_array: parse_start_array,
			yajl_end_array: parse_end_array
		};

		parse_ctx_t ctx;
		size_t json_len;
		const unsigned char *json_str = (const unsigned char*)luaL_checklstring(L, -1, &json_len);
		yajl_handle yajl;
		yajl_status status;

		ctx.L = L;
		ctx.curr_level = 0;
		ctx.env[0] = not_in_container;
		ctx.start_of_container[0] = 0;

		yajl = yajl_alloc(&_callbacks, &_config, NULL, &ctx);

		status = yajl_parse(yajl, json_str, json_len);
		if(status == yajl_status_ok) {
			status = yajl_parse_complete(yajl);
		}

		if(status != yajl_status_ok) {
			unsigned char* err_msg = yajl_get_error(yajl, 1, json_str, json_len);
			lua_pushfstring(L, "parsing error: %s", err_msg);
			yajl_free_error(yajl, err_msg);

			return lua_error(L);
		}

		yajl_free(yajl);
		return 1;
	}
]=],
	{"parse_json"},
	{"yajl"}
)

local ntimes = 300000
local st, ed
local str = '{"a":1234,"b":2.34,"c":true,"d":"hello","e":[1,2,{"a":{"b":{"c":"d"}}}]}'

st = os.time()
for i=1,ntimes do
	local arr = yajl.parse_json(str)
end
ed = os.time()
print("yajl elapsed = ", (ed-st))

st = os.time()
for i=1,ntimes do
	local arr = json.decode(str)
end
ed = os.time()
print("json4lua elapsed = ", (ed-st))

 在我的 colinux 虚拟环境下用标准 lua 运行该程序时结果如下:

$ lua yajl.lua
yajl elapsed = 4
json4lua elapsed = 134

 相比之下通过 tcc 内联的 yajl 解析器解析相同的 json 串时比 json4lua 快了 33.5 倍!而换用 luajit-2.0 运行该程序时结果如下:

$ luajit yajl.lua
yajl elapsed =  2
json4lua elapsed = 52

 json4lua 表现好了不少,但 yajl 的解析速度仍是 json4lua 的 26 倍。由此可见,在恰当的地方通过 tcc 内联 c 代码替代 lua 处理数据可以收到相当好的性能提升效果,且由于模块代码以源代码形式分发,对于没有外部依赖库的代码不会存在传统 Lua-C 模块那样的跨平台二进制接口兼容性问题。

 

0
0
分享到:
评论
2 楼 zzz654321 2012-09-26  
intel E5300 2.6G

json4lua version 0.9.50
luajit 2.0 beta10

windows 2003 sp1



json4lua elapsed =      9
1 楼 outrace 2010-09-29  
有没有lua table到json转换的库啊?

相关推荐

    lua-nginx-module-0.10.13

    LuaJIT是Lua的一个高性能Just-In-Time编译器,能显著提升lua-nginx-module的运行效率。 5.3 Coroutines(协程) Lua支持轻量级的协程,可以在不引入多线程复杂性的前提下实现并发。 总结,Lua-Nginx-Module ...

    EmmyLua-AttachDebugger 可用

    总的来说,EmmyLua-AttachDebugger是Unity lua开发者的得力助手,它使得lua脚本调试变得方便快捷,提升了开发效率。如果你正在使用lua开发Unity游戏,那么掌握如何利用这个工具将大大提高你的工作效能。记得在使用...

    lua-nginx-module-master.zip

    这个"lua-nginx-module-master.zip"压缩包包含了该模块的源代码,是安装和自定义Nginx与Lua集成的关键组件。 在深入讲解之前,先来了解一下Nginx。Nginx是一款高性能的HTTP和反向代理服务器,以其轻量级、高并发...

    lua-devel-5.3.4-12.el8.aarch64

    1. **头文件**:例如 `lua.h`、`luac.h` 等,这些头文件定义了 Lua API,供 C/C++ 程序调用 Lua 的函数和结构体,以便在 C 代码中与 Lua 脚本进行交互。 2. **库文件**:`liblua.a` 或 `liblua.so` 是静态和动态...

    lua-nginx-module-0.10.9rc7

    - **定时任务**:通过`ngx.timer.at`创建定时任务,实现在特定时间执行Lua代码的功能。 - **错误处理**:使用`ngx.errlog`记录错误日志,方便调试和排查问题。 总之,Lua-Nginx-Module 0.10.9rc7是Nginx服务器的一...

    lua-cjson-2.1.0

    **lua-cjson-2.1.0:Lua与JSON交互的核心工具** `lua-cjson`是Lua编程语言中一个高效且功能丰富的JSON(JavaScript Object Notation)解析和序列化...通过熟练掌握`lua-cjson`,可以有效提高开发效率,提升项目质量。

    EmmyLua-AttachDebugger-1.0.0.4.zip

    EmmyLua是一款专门为Lua语言开发的强大的调试工具,它允许开发者在IntelliJ IDEA这样的集成开发环境中进行断点调试,极大地提高...通过正确安装和配置这个插件,你可以充分利用其特性,提升你的Lua编程体验和工作效率。

    所有版本LUA源码

    所有版本LUA源码 lua-5.3.5 lua-5.3.4 lua-5.3.3 lua-5.3.2 lua-5.3.1 lua-5.3.0 lua-5.2.4 lua-5.2.3 lua-5.2.2 lua-5.2.1 lua-5.2.0 lua-5.1.5 lua-5.1.4 lua-5.1.3 lua-5.1.2 lua-5.1.1 lua-5.1 lua-5.0.3 lua-...

    lua-5.1.5安装包

    这里的"lua-5.1.5安装包"指的是Lua编程语言的5.1.5版本的源代码包。这个版本在2009年发布,是Lua 5.1系列的一个稳定版本。 Lua-5.1.5.tar.gz是一个压缩文件,通常在Linux或Unix-like系统中使用,其扩展名.tar.gz...

    vscode-coco2dx-lua-api.7z

    为了提升开发效率,Visual Studio Code(VSCode)作为一款强大的源代码编辑器,提供了各种插件和扩展支持,使得Cocos2d-x Lua项目的开发更为便捷。"vscode-coco2dx-lua-api.7z"就是这样一个专为VSCode定制的辅助工具...

    lua-nginx-module-0.10.20.tar.gz

    利用Lua进行日志格式化和分析,提升运维效率。 总的来说,lua-nginx-module-0.10.20是Nginx服务器中一个强大的工具,它将Lua的灵活性和Nginx的高性能相结合,为Web开发带来新的可能。无论是简单的配置增强还是复杂...

    lua-resty-template

    而lua-resty-template和大多数模板引擎是类似的,大体内容有: 模板位置:从哪里查找模板; 变量输出/转义:变量值输出; 代码片段:执行代码片段,完成如if/else、for等复杂逻辑,调用对象函数/方法; 注释:解释...

    EmmyLua-Unity

    EmmyLua-Unity 是一个专为Unity游戏引擎开发者设计的工具,它是由国内开发者创建的,目的是提升在Unity中编写Lua脚本的效率和便捷性。这个插件主要与IntelliJ IDEA集成,IntelliJ IDEA是一款强大的Java开发集成环境...

    lua-cURL访问http/https

    Lua-cURL是一个用于在Lua环境中实现HTTP和HTTPS访问的库,它是基于著名的C语言库cURL构建的。这个库提供了全面的功能,使得Lua脚本能够方便地与Web服务进行交互,比如发送GET、POST请求,处理cookies,上传文件,...

    lua-5.4.2_Win64_bin.zip

    同时,luac.exe则用于将hello.lua预编译为hello.luac,这样在后续运行时可以提高执行效率: ```shell luac -o hello.luac hello.lua lua hello.luac ``` 总的来说,"lua-5.4.2_Win64_bin.zip" 提供了一套完整的64...

    云风-lua源码欣赏-lua-5.21

    这部分内容对于理解Lua的执行效率和如何优化代码至关重要。此外,还涉及到了内嵌库的实现,这些库是Lua功能的重要组成部分,如数学运算、表操作等。 在内存管理章节,作者详细讲解了Lua如何进行内存分配和释放,...

    lua-pb解析

    3. **解析和序列化**: Lua代码可以通过这些生成的模块创建protobuf消息对象,设置字段值,然后序列化成二进制数据。反之,也可以从接收到的二进制数据反序列化成Lua对象。 4. **兼容性**: lua-pb库通常会努力保持与...

    lua-5.3.3.tar.gz安装包

    编译过程中,会生成可执行的lua和luac二进制文件,lua是解释器,luac是编译器,可以将Lua脚本编译为字节码。 3. **安装**:通常,我们使用`make install`命令将编译好的Lua程序安装到系统默认的位置,如/usr/local/...

    lua-resty-redis-connector-master

    《lua-resty-redis-connector:Lua在OpenResty中的Redis连接器详解》 在现代Web服务开发中,Lua作为一种轻量级脚本语言,因其高效、简洁的特性被广泛应用于服务器端。OpenResty是基于Nginx的高性能Web平台,它集成...

Global site tag (gtag.js) - Google Analytics