对expat库XML_Parse函数调用优化的测试

xpat库文档中说

复制代码
XML_Parse
enum XML_Status XMLCALL
XML_Parse(XML_Parser p,
          const char *s,
          int len,
          int isFinal);
enum XML_Status {
  XML_STATUS_ERROR = 0,
  XML_STATUS_OK = 1
};
Parse some more of the document. The string s is a buffer containing part (or perhaps all) of the document. The number of bytes of s that are part of the document is indicated by len. This means that s doesn't have to be null-terminated. It also means that if len is larger than the number of bytes in the block of memory that s points at, then a memory fault is likely. Negative values for len are rejected since Expat 2.2.1. The isFinal parameter informs the parser that this is the last piece of the document. Frequently, the last piece is empty (i.e. len is zero.)

If a parse error occurred, it returns XML_STATUS_ERROR. Otherwise it returns XML_STATUS_OK value. Note that regardless of the return value, there is no guarantee that all provided input has been parsed; only after the concluding call will all handler callbacks and parsing errors have happened.

Simplified, XML_Parse can be considered a convenience wrapper that is pairing calls to XML_GetBuffer and XML_ParseBuffer (when Expat is built with macro XML_CONTEXT_BYTES defined to a positive value, which is both common and default). XML_Parse is then functionally equivalent to calling XML_GetBuffer, memcpy, and XML_ParseBuffer.

To avoid double copying of the input, direct use of functions XML_GetBuffer and XML_ParseBuffer is advised for most production use, e.g. if you're using read or similar functionality to fill your buffers, fill directly into the buffer from XML_GetBuffer, then parse with XML_ParseBuffer.

最后两段说,这个函数其实是XML_GetBuffer和XML_ParseBuffer两个函数的包装,再在中间插入从用户buffer到parser buffer的复制,如果read函数直接用parser buffer当缓冲区,就可以省略memcpy的操作。

我用先前的xml文件转csv程序做了个测试,

原代码expatfile.c调用XML_Parse

c 复制代码
    char buffer[8192];
    int done;
    do {
        size_t len = fread(buffer, 1, sizeof(buffer), file);
        done = (len < sizeof(buffer));
  
        if (XML_Parse(parser, buffer, len, done) == XML_STATUS_ERROR) {
            break;
        }
    } while (!done);

修改后expatfile2.c调用XML_GetBuffer和XML_ParseBuffer

c 复制代码
    char buffer[8192];
    int done;
    do {void *buff = XML_GetBuffer(parser, 8192);
        size_t len = fread(buff, 1, 8192, file);
        done = (len < 8192);
  
        if (XML_ParseBuffer(parser, len, done) == XML_STATUS_ERROR) {
            break;
        }
    } while (!done);

编译运行

cmd 复制代码
gcc expatfile.c -o expatfile -lexpat -O3

time ./expatfile /par/lineitem/xl/worksheets/sheet1.xml A1:P1000000
CSV已保存到 /par/lineitem/xl/worksheets/sheet1.csv

real	0m18.882s
user	0m18.168s
sys	0m0.324s

gcc expatfile2.c -o expatfile2 -lexpat -O3

time ./expatfile2 /par/lineitem/xl/worksheets/sheet1.xml A1:P1000000
CSV已保存到 /par/lineitem/xl/worksheets/sheet1.csv

real	0m18.909s
user	0m18.116s
sys	0m0.284s

测试证明,两种调用几乎没有差别,也许现在memcpy很快,体现不出来影响了。

相关推荐
学逆向的7 小时前
C 循环结构的执行效率分析
c语言·开发语言·数据结构·网络安全
Navigator_Z10 小时前
LeetCode //C - 1293. Shortest Path in a Grid with Obstacles Elimination
c语言·算法·leetcode
jeo陽11 小时前
04-循环实战:素数、最大公约数、级数求和与枚举法
c语言·开发语言·数据结构
爱读书的小胖13 小时前
LeetCode 88. 合并两个有序数组 C 解题分析
c语言·数据结构·算法
inrichtt14 小时前
第七课时:STM32时钟系统揭秘:从零理解时钟树
c语言·数据结构·stm32·单片机·嵌入式硬件
知识分享小能手14 小时前
C学习教程,从入门到精通,C语言指针 —— 详细知识点总结(10)
c语言·开发语言·学习
金融小师妹14 小时前
多因子时间序列分析:美元与美债收益率变化对黄金价格+1.6%的影响
c语言·人工智能·git·决策树·pyqt
额额额对了15 小时前
Linux 驱动开发:基于 platform 总线 + misc 设备的 DS18B20 单总线温度驱动
linux·c语言·开发语言·驱动开发·嵌入式硬件
奶盐cookie15 小时前
内存区域:栈、全局区和静态区
c语言
头像很酷15 小时前
嵌入式虚拟化-xvisor-跨越边界的读客
c语言·hypervisor·xvisor·嵌入式虚拟化