• 【小优化】golang中取两个字符串的公共前缀的长度


    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


    在VM的merge部分的代码中发现这样一个函数:

    func commonPrefixLen(a, b []byte) int {
        i := 0
        if len(a) > len(b) {
            for i < len(b) && a[i] == b[i] {
                i++
            }
        } else {
            for i < len(a) && a[i] == b[i] {
                i++
            }
        }
        return i
    }
    

    在merge整个sstable的时候,需要算出所有字符串的公共前缀,然后存储的时候就不再存储公共前缀的部分,这样就实现了进一步的数据压缩。
    这个函数调用得非常频繁,于是想尝试用SIMD来优化。
    后来试了一下,简单的写法就能提升1.6倍,优化的代码如下:

    // macbook pro 2019, Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
    // 15.70 ns/op
    func commonPrefixLenOneByOne(a, b []byte) int {
        i := 0
        if len(a) > len(b) {
            for i < len(b) && a[i] == b[i] {
                i++
            }
        } else {
            for i < len(a) && a[i] == b[i] {
                i++
            }
        }
        return i
    }
    
    // from this issue: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2254
    // macbook pro 2019, Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
    // 9.785 ns/op when memory aligned, 1.6 times faster
    // 9.833 ns/op when memory not aligned
    func commonPrefixLen(a, b []byte) int {
        if len(a) > len(b) {
            a, b = b, a
        }
        if len(a) < 8 {
            return commonPrefixLenOneByOne(a, b)
        }
        const size = 8
        compareTimes := len(a) / size
        addrA := uintptr(unsafe.Pointer(&a[0]))
        addrB := uintptr(unsafe.Pointer(&b[0]))
        for i := 0; i < compareTimes; i++ {
            v1 := (*uint64)(unsafe.Pointer(addrA))
            v2 := (*uint64)(unsafe.Pointer(addrB))
            if *v1 != *v2 {
                return i*size + commonPrefixLenOneByOne(a[i*size:], b[i*size:])
            }
            addrA += size
            addrB += size
        }
        return compareTimes*size + commonPrefixLenOneByOne(a[compareTimes*size:], b[compareTimes*size:])
    }
    

    思路就是用unsafe指针把连续的8个byte转换为uint64的指针,这样就可以一条指令比较8个字节。

    这个优化已经提了一个PR到VM的仓库:https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2913

  • 相关阅读:
    从ReentrantLock的实现看AQS的原理及应用
    Java 守护线程
    js静态文件编辑器显示操作,但网页显示中文乱码 解决方案
    springmvc 4.3版本集成 Caffeine缓存系统
    chrome浏览器如何设置黑色背景
    电脑型号19 1200 固态SSD
    电脑型号18 1200 固态SSD
    geohash st_distance st_distance_sphere 关系
    Git自动输入账户名密码。明文及SSH私钥2种方式
    一步快速获取 iOS 设备的 UDID
  • 原文地址:https://www.cnblogs.com/ahfuzhang/p/16524396.html
Copyright © 2020-2023  润新知