测试DuckDB LuaJit插件通过ffi调用c语言动态库性能

发布时间:2026/10/6 22:41:20

测试DuckDB LuaJit插件通过ffi调用c语言动态库性能 关键步骤有2步。1.用c编译器(gcc/tcc等)编译动态库tcc -shared -fPIC -o libsudoku_c.so sudoku_solve.c2.在DuckDB中把动态库中的函数注册为luajit udfSELECT * FROM luajit_module(mode : compile, sql_name : sudoku_c, source : return function(p) local ffi require(ffi) ffi.cdef[[ int sudoku_solve(const char *p, char *out); ]] local lib ffi.load(/mnt/c/d/libsudoku_c.so) local buf ffi.new(char[82]) local rc lib.sudoku_solve(p, buf) if rc ~ 1 then return NULL end return ffi.string(buf) end );然后用luajit_s等函数调用udf。在Windows中调用不成功。Microsoft Windows [版本 10.0.26200.8655] (c) Microsoft Corporation。保留所有权利。 C:\Users\ltcd\d C:\dduckdb155 DuckDB v1.5.5 (Variegata) Enter .help for usage hints. memory D load luajit; memory D C:\dtcc\tcc -shared -fPIC -o libsudoku_c.so sudoku_solve.c C:\dduckdb155 DuckDB v1.5.5 (Variegata) Enter .help for usage hints. memory D load luajit; memory D SELECT * FROM luajit_module(mode : compile, sql_name : sudoku_c, source : return function(p) local ffi require(ffi) ffi.cdef[[ int sudoku_solve(const char *p, char *out); ]] local lib ffi.load(/d/libsudoku_c.so) local buf ffi.new(char[82]) local rc lib.sudoku_solve(p, buf) if rc ~ 1 then return NULL end return ffi.string(buf) end ); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤ │ true │ compile │ compile │ OK │ │ sudoku_c │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘ memory D SELECT luajit_s(sudoku_c, 000001002000020030004500600007600050080090006100005800001004000070900003400030020); ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ luajit_s(sudoku_c, 000001002000020030004500600007600050080090006100005800001004000070900003400030020) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ NULL │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘在WSL Linux中调用成功。首先用apt install 安装Tcc。C:\dwsl rootDESKTOP-59T6U68:/mnt/c/d# tcc Command tcc not found, but can be installed with: apt install tcc rootDESKTOP-59T6U68:/mnt/c/d# apt install tcc Reading package lists... Done Building dependency tree... Done Reading state information... Done The following NEW packages will be installed: tcc 0 upgraded, 1 newly installed, 0 to remove and 48 not upgraded. Need to get 278 kB of archives. After this operation, 824 kB of additional disk space will be used. Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 tcc amd64 0.9.27git20200814.62c30a4a-1 [278 kB] Fetched 278 kB in 1s (205 kB/s) Selecting previously unselected package tcc. (Reading database ... 84088 files and directories currently installed.) Preparing to unpack .../tcc_0.9.27git20200814.62c30a4a-1_amd64.deb ... Unpacking tcc (0.9.27git20200814.62c30a4a-1) ... Setting up tcc (0.9.27git20200814.62c30a4a-1) ... Processing triggers for install-info (6.8-4build1) ... Processing triggers for man-db (2.10.2-1) ... rootDESKTOP-59T6U68:/mnt/c/d# tcc -shared -fPIC -o libsudoku_c2.so sudoku_solve.c rootDESKTOP-59T6U68:/mnt/c/d# ./duckdb155 DuckDB v1.5.5 (Variegata) Enter .help for usage hints. memory D .timer on memory D load luajit; Run Time (s): real 0.015 user 0.004387 sys 0.000000 memory D SELECT * FROM luajit_module(mode : compile, sql_name : sudoku_c, source : return function(p) local ffi require(ffi) ffi.cdef[[ int sudoku_solve(const char *p, char *out); ]] local lib ffi.load(/mnt/c/d/libsudoku_c2.so) local buf ffi.new(char[82]) local rc lib.sudoku_solve(p, buf) if rc ~ 1 then return NULL end return ffi.string(buf) end ); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤ │ true │ compile │ compile │ OK │ │ sudoku_c │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘ Run Time (s): real 0.008 user 0.002350 sys 0.000048 memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 100); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 978654213645231798213879654796518432521347986384926175437182569159463827862795341 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.950 user 0.900484 sys 0.008561 memory D rootDESKTOP-59T6U68:/mnt/c/d# tcc -shared -fPIC -o libsudoku_c3.so dlxdll.c rootDESKTOP-59T6U68:/mnt/c/d# exit exit memory D SELECT * FROM luajit_module(mode : compile, sql_name : sudoku_c, source : return function(p) local ffi require(ffi) ffi.cdef[[ int sudoku_solve(const char *p, char *out); ]] local lib ffi.load(/mnt/c/d/libsudoku_c3.so) local buf ffi.new(char[82]) local rc lib.sudoku_solve(p, buf) if rc ~ 1 then return NULL end return ffi.string(buf) end ); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤ │ true │ compile │ compile │ OK │ │ sudoku_c │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘ Run Time (s): real 0.019 user 0.019758 sys 0.000000 memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 100); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 978654213645231798213879654796518432521347986384926175437182569159463827862795341 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.075 user 0.031685 sys 0.026326 memory D memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 1000); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 987563214124987653356412987671398542295174836843256179439825761562731498718649325 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.114 user 0.066773 sys 0.012692 memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 10000); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 987652431164739582253481796375824619842916357619375824728163945431597268596248173 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.483 user 0.466168 sys 0.003213分别使用两种算法的数独求解程序跳舞链的速度比MRV启发式—dfs快得多。又尝试mold的作者编写的chibicc编译器。先从源码编译二进制可执行文件。C:\Users\ltwsl rootDESKTOP-59T6U68:/mnt/c/Users/lt# docker start gcc gcc rootDESKTOP-59T6U68:/mnt/c/Users/lt# docker exec -it gcc bash root6ae32a5ffcde:/# cd /par root6ae32a5ffcde:/par# cd chibicc-main root6ae32a5ffcde:/par/chibicc-main# make cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o codegen.o codegen.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o hashmap.o hashmap.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o main.o main.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o parse.o parse.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o preprocess.o preprocess.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o strings.o strings.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o tokenize.o tokenize.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o type.o type.c cc -stdc11 -g -fno-common -Wall -Wno-switch -c -o unicode.o unicode.c cc -stdc11 -g -fno-common -Wall -Wno-switch -o chibicc codegen.o hashmap.o main.o parse.o preprocess.o strings.o tokenize.o type.o unicode.o root6ae32a5ffcde:/par/chibicc-main# cd ..后面的步骤和tcc一样root6ae32a5ffcde:/par# /par/chibicc-main/chibicc -shared -fPIC -o libsudoku_c4.so dlxdll.c ld: warning: /tmp/chibicc-RZBje2: missing .note.GNU-stack section implies executable stack ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker root6ae32a5ffcde:/par# ./duckdb155 DuckDB v1.5.5 (Variegata) Enter .help for usage hints. memory D force install luajit from community; memory D load luajit; memory D SELECT * FROM luajit_module(mode : compile, sql_name : sudoku_c, source : return function(p) local ffi require(ffi) ffi.cdef[[ int sudoku_solve(const char *p, char *out); ]] local lib ffi.load(/par/libsudoku_c4.so) local buf ffi.new(char[82]) local rc lib.sudoku_solve(p, buf) if rc ~ 1 then return NULL end return ffi.string(buf) end ); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤ │ true │ compile │ compile │ OK │ │ sudoku_c │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘ memory D SELECT luajit_s(sudoku_c, 000001002000020030004500600007600050080090006100005800001004000070900003400030020); ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ luajit_s(sudoku_c, 000001002000020030004500600007600050080090006100005800001004000070900003400030020) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 359461782716829534824573619947682351583197246162345897631254978275918463498736125 │ └───────────────────────────────────────────────────────────────────────────────────────────────────────────┘ memory D .timer on memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 100); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 978654213645231798213879654796518432521347986384926175437182569159463827862795341 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.065 user 0.026620 sys 0.029178 memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 1000); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 987563214124987653356412987671398542295174836843256179439825761562731498718649325 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.140 user 0.125244 sys 0.003991 memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 10000); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 987652431164739582253481796375824619842916357619375824728163945431597268596248173 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 1.157 user 2.327257 sys 0.011661chibicc编译出来的动态库比tcc编译的动态库执行速度慢一些使用意义不大。上述2种编译器都没有优化再改用gcc -O3优化编译memory D .system bash root6ae32a5ffcde:/par# gcc -shared -fPIC -o libsudoku_c5.so dlxdll.c -O3 root6ae32a5ffcde:/par# exit exit memory D SELECT * FROM luajit_module(mode : compile, sql_name : sudoku_c, source : return function(p) local ffi require(ffi) ffi.cdef[[ int sudoku_solve(const char *p, char *out); ]] local lib ffi.load(/par/libsudoku_c5.so) local buf ffi.new(char[82]) local rc lib.sudoku_solve(p, buf) if rc ~ 1 then return NULL end return ffi.string(buf) end ); ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐ │ ok │ mode │ phase │ message │ detail │ sql_name │ │ boolean │ varchar │ varchar │ varchar │ varchar │ varchar │ ├─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤ │ true │ compile │ compile │ OK │ │ sudoku_c │ └─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘ Run Time (s): real 0.008 user 0.010392 sys 0.000509 memory D SELECT max(luajit_s(sudoku_c, column0)) from (from read_csv(sudoku17.txt,header0) limit 10000); ┌───────────────────────────────────────────────────────────────────────────────────┐ │ max(luajit_s(sudoku_c, column0)) │ │ varchar │ ├───────────────────────────────────────────────────────────────────────────────────┤ │ 987652431164739582253481796375824619842916357619375824728163945431597268596248173 │ └───────────────────────────────────────────────────────────────────────────────────┘ Run Time (s): real 0.458 user 0.438527 sys 0.001587和tcc的结果没有明显差距。瓶颈好像不在动态库这边。
延伸阅读

更多相关文章

2026/9/23 7:56:35

thor雷神项目Raft进阶:持久化、快照与日志压缩一文搞懂

thor雷神项目Raft进阶:持久化、快照与日志压缩一文搞懂 【免费下载链接】thor 项目地址: https://gitcode.com/gh_mirrors/thor3/thor thor 雷神项目是一个专注于 MIT 6.824 分布式系统课程的中文字幕翻译项目。在这篇文章中,我们将借助该项目整…

2026/10/7 12:16:21

DeepSeek Harness桌面端实战:插件、Skill与工作区配置指南

1. 桌面端来了,为什么这件事比想象中重要 DeepSeek Harness 出官方桌面端这件事,我在圈子里看到消息的第一反应不是"终于有了",而是"早该有了"。过去大半年,身边用 DeepSeek 做 coding 的朋友基本分两派&…

2026/10/7 12:16:21

MCP工具生态治理:从协议落地到生命周期管理

1. 面试官真正想听的不是“MCP是什么”,而是你如何用它解决Agent落地的脏活累活最近三轮Agent开发岗面试下来,我明显感觉到一个变化:面试官不再盯着你背诵MCP协议RFC文档的第3.2节,也不再问“请手写一个Tool Calling状态机”。他们…

2026/10/7 12:16:21

风险驱动重构集成测试框架:SpringBoot+MyBatis实战笔记

如果你所在团队的集成测试还停留在“把所有接口按顺序点一遍、能跑通就算交差”的阶段,这篇内容应该能帮你换一个思路。我最近带着团队把集成测试框架完整重做了一遍,核心就一个词—— 风险驱动 。不再追求接口覆盖率的数字好看,而是把最可…

2026/10/7 12:16:21

基于Spring Boot的美食探店平台毕设全解析:架构、实现与调试指南

如果你正在为毕业设计选方向,又恰好对 Java Web 开发有点基础,那么“基于 Web 的美食探店平台”是一个值得认真考虑的选题。这个题目属于典型的“业务完整、技术栈主流、工作量可控”的毕设类型,既能体现数据库设计能力,又能展示前…

2026/10/7 12:16:21

pstack如何路由任务:poteto-mode的22条触发器逐条注解

pstack如何路由任务:poteto-mode的22条触发器逐条注解 【免费下载链接】pstack-claude Claude Code, Codex, Copilot, Pi, OpenCode, Gemini, and Prime Agent versions of Potetos pstack. Rigorous agent workflows with Cursor primitives translated for other …

2026/10/7 12:11:20

实体关系抽取pipeline实战:BERT+BiLSTM+CRF选型、调优与避坑指南

简介:这份资源面向自然语言处理方向的学习者与研究者,提供一套基于BiLSTMCRF与BERT的实体关系抽取完整pipeline实现,采用分阶段架构:先以BiLSTMCRF完成序列标注式实体识别,再用BERT对实体对进行关系分类,最…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/7 8:18:33

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

ESP32免重刷固件:浏览器直接修改NVS键值实现WiFi配置更新

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

SAP HANA查询结果导出CSV:避开乱码、性能与权限的实用指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:05:03

数字后端Placement阶段Density与Congestion控制实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑