< CSDN 逃离计划 > hyperscan 从安装到写出第一个测试demo

hyperscan 作为和intel深度绑定的政策匹配工具,提供了及其强大的正则匹配功能,并提供接口,方便对匹配结果进行二次操作。

我在学习hyperscan时,在各大论坛并没有找到比较完备并且详细讲解,很多只是提到了函数库大概时干什么的,索性将自己了解到的东西,详细的记录下来,也算是自己对hyperscan的一次巩固

hyperscan 是英特尔开源的一款正则匹配工具,与intel芯片深度绑定,intel对其有专门的优化,因此在整体的匹配效率上,相较于其他正则方案,处于一个较为领先的位置。 hyperscan支持pcre 正则规则,现有的主要应用方案大都是基于pcre做的匹配。

样例代码放在了github上,后面会贴出来。

注: 本文演示环境为 ubuntu 22.04

hyperscan下载安装

  1. 下载
    intel在github上开放了源码,通过git即可下载,由于github,在国内访问不友好,在gitee上也有相关开源代码
github
git clone https://github.com/intel/hyperscan.git

gitee
git clone https://gitee.com/tzichengchew/hyperscan.git
  1. 依赖
    hyperscan 使用cmake编译cmake等基础库安装不再赘述, 需要依赖
  2. boost
    Boost Downloads
git clone https://github.com/adrian-thurston/ragel.git
* colm
git clone https://github.com/adrian-thurston/colm.git

其中ragel的安装需要clom支持在官网均能找到下载地址。或者git地址

  1. 安装

安装boost

  bash bootstrap.sh && ./b2 && ./b2 install 

安装ragel
不建议编译安装,坑很多

sudo apt install ragel

编译安装hyperscan
创建一个目录

mkdir hyperscan_comp

执行编译命令

cmake $HYPERSCAN_PATH
make && make install 

需要蛮久的。
遇到一个非常棘手的问题:

undefined reference to `avx2_memset'
undefined reference to `corei7_memset'
…………
https://github.com/intel/hyperscan/issues/292#issuecomment-762635447
亲测有效。

我在另外一台设备上测试发现并没有报错,估计可能是虚拟机cpu配置问题,前面提到了,hyperscan与intel深度绑定。

修改过cmake/build_wrapper.sh脚本后,就可以执行cmake命令了

为防止产生的cmake文件搞混了源文件,这里建议建立一个新的目录,执行cmake

需要注意的是,在使用hyperscan时,动态库要比静态库使用相对方便,修改CMakeCache.txt文件,根据版本不同,所在行数也不同。

BUILD_STATIC_AND_SHARED:BOOL=OFF
->
BUILD_STATIC_AND_SHARED:BOOL=ON

修改过后即可执行make && make install

hyperscan 简单使用

hyperscan整体的使用流程主要分为编译器和运行期

编译期

编译器主要是将编辑好的正则,编译成数据库供后续使用,

主要包括三个函数,分别适用不同的使用场景

  • hs_compile() 将单个规则编译成数据库。
  • hs_compile_multi() 将一组规则编译成数据库。
  • hs_compile_ext_multi() 将一组规则编译成数据库,并支持扩展参数。
    具体细节可以参考《深入浅出 Hyperscan: 高性能正则表达式算法原理与设计》

本例设计使用hs_compile_multi() 应该是最常用的函数,普适性较高

  1. 定义宏,方便后续使用

    enum {
     HYPERSCAN_ID_NONE = 0,
     HYPERSCAN_ID_TEST1,
     HYPERSCAN_ID_TEST2,
     HYPERSCAN_ID_MAX
    };
  2. 定义数据结构

    /**
    * 将数据库中待编译的信息保存到这个数组里面
    */
    typedef struct CompilePatternArray {
     uint32_t ids[20];     /**< id */
     uint32_t flag[20];    /**< 编译参数 */
     const char *exps[20]; /**< 正则 */
    } CompilePatternArray_t;
    /**
    * 编译数据结构
    */
    typedef struct CompilePattern {
     uint32_t ids;
     const char *exps;
    } CompilePattern_t;
  3. 使用数组定义一组正则规则

    /**
    * 编译到数据库中的匹配字段,
    * hyperscan编译阶段有一个特殊字符转义的过程
    */
    static const CompilePattern_t gCompilePattern[] = {
         {HYPERSCAN_ID_NONE,  " "},
         {HYPERSCAN_ID_TEST1, "123.{1,3}abc"},
         {HYPERSCAN_ID_TEST2, "max"}
    };
  4. 编译

    /**
    *
    * @param CompPatt
    * 待编译信息
    * @param count
    * 数据条数
    * @param pDatabase
    * 数据库
    * @return
    * 返回值,暂时没定义
    */
    static int CompilePatterns(CompilePattern_t *CompPatt, uint32_t count, hs_database_t **pDatabase) {
     hs_error_t error;
     hs_compile_error_t *ComError;
     CompilePatternArray_t compilePattern;
     // 一对一存储,转存
     int i;
     for (i = 0; i < count; i++) {
         compilePattern.ids[i] = CompPatt[i].ids;
         compilePattern.exps[i] = CompPatt[i].exps;
         compilePattern.flag[i] = HS_FLAG_CASELESS;   // 忽略大小写
     }
     // 编译
     /**
      * 参数说明
      * 1. 正则
      * 2. 正则匹配标签
      * 3. id
      * 4. 数量
      * 5. 匹配模式
      * 6. platform 需要深入去了解一下,目前置NULL
      * 7. 数据库指针
      * 8. errorInfo
      */
     error = hs_compile_multi(compilePattern.exps, compilePattern.flag, compilePattern.ids, count, HS_MODE_BLOCK, NULL,
                              pDatabase,
                              (hs_compile_error_t **) &ComError);
     if (error != HS_SUCCESS) {
         // 失败的话给出相应的提示信息
         std::cout << "compile failed error code is " << error << std::endl;
     }
     return 0;
    }

    运行期

hypersacn 运行过程中,进行正则匹配会有一个中间状态暂存匹配信息,需要创建一个scratch空间

hs_alloc_scratch(HsDatabase, (hs_scratch_t **) &HsStra);

运行期分为块模式,流模式,向量模式,块模式可以简单的理解为就一次数据输入,输出结果,流模式主要针对网络字节流,但相较于块模式,增加了流开启与关闭的过程,在编译期需要编译的内容也有所区别,本例中主要是块模式样例,流模式,有兴趣可以自行研究。

使用

hs_scan()进行匹配,调用时需要规定回调函数

/** 参数说明
* 1. 数据库
* 2. 待匹配字符串
* 3. 字符串长度
* 4. flag, 未定义,官方说明待用
* 5. scratch
* 6. 回调函数
* 7. 回调函数传参
*/
hs_scan(HsDatabase, tmpString, strlen(tmpString), 0, HsStra, onMatch, tmpString);

回调函数

/**
 * 回调函数
 * @param id
 * 匹配字段的 id
 * @param from
 * 从哪里还是匹配的
 * @param to
 * 匹配到哪里结束(指向尾部)
 * @param flags
 * 根本没用, hyperscan 官方明确说明没有使用的参数。
 * @param ctx
 * 回调参数
 * @return
 * 暂时没用
 */
static int onMatch(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *ctx) {
    char *tmp = (char *) ctx;
    std::cout << "id is " << id << std::endl;
    switch (id) {
        case HYPERSCAN_ID_NONE:
            std::cout << std::endl;
            break;
        case HYPERSCAN_ID_TEST1:
            std::cout << "form:" << tmp + from << std::endl;
            std::cout << "to:" << tmp + to << std::endl;
            std::cout << std::endl;
            break;
        case HYPERSCAN_ID_TEST2:
            std::cout << "form:" << tmp + from << std::endl;
            std::cout << "to:" << tmp + to << std::endl;
            std::cout << std::endl;
            break;
        default:
            std::cout << "can not found any subString" << std::endl;
            break;
    }
    return 0;
}

传入字符串

abc123123123abcmax123123bacbacabc\0

执行效果

< CSDN 逃离计划 > hyperscan 从安装到写出第一个测试demo_第1张图片

后记

hyperscan作为一个高性能正则匹配工具,应用场景很多,王翔先生等用几百页文字详细介绍了hyperscan基本原理,算法过程与高级特性,但真正使用还需要真正去实践才能真正理解,并且用好这个工具

完整代码放在了gitee上,欢迎大家补充,指正。

https://gitee.com/wang-xiaotian-1/MyHyperscanTest.git

你可能感兴趣的:(clinux)