C++ 中文周刊 2024-02-09 第148期

周刊项目地址

公众号

qq群 点击进入

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

欢迎投稿,推荐或自荐文章/软件/资源等

提交 issue 或评论区留言

本期文章由 黄亮Anthony HNY 不语 赞助

祝大家新年快乐


资讯

boost 新增 charconv

把from_chars搬到c++11,我建议放弃c++11 ,2024了bro 文档

标准委员会动态/ide/编译器信息放在这里

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-01-31 第239期

What’s New in vcpkg January 2024

另外有个重写loki的活动哈,有点幽默,感兴趣可以点击直达

(重写loki不是已经做了吗,folly啊)

brpc发布1.8版本 release note

文章

使用 hugetlb 提升性能

redis 为啥不用?避免影响rdb生成?

另外这有个 hugetop命令

代码这里 https://gitlab.com/procps-ng/procps

C++异常的误用以及改进

群友翻译,非常干货,值得看看

不过异常设计的还是太傻呗了

[RFC] Upstreaming ClangIR https://discourse.llvm.org/t/rfc-upstreaming-clangir/76587/19

之前聊到的MLIR 在c/c++上的落地 CIR准备合入到LLVM

感觉clang明显更激进一些,而gcc还是一群老登

Option Soup: the subtle pitfalls of combining compiler flags https://hacks.mozilla.org/2024/01/option-soup-the-subtle-pitfalls-of-combining-compiler-flags/

傻逼locale问题,虽然你是静态连接libstdcxx-static,但是locale并不static

errno and libc https://dxuuu.xyz/errno.html

errno是内核设置还是libc设置?当然是libc

怎么验证? 简单来说就是同一个系统调用,调用syscall/通过汇编调用,观察errno变化


static int use_wrapper(int cmd, union bpf_attr *attr, unsigned int size) {
    long ret;
    errno = 0;
    ret = syscall(__NR_bpf, cmd, attr, size);
    if (ret < 0)
        printf("wrapped syscall failed, ret=%d, errno=%d\n", ret, errno);
    else
        printf("wrapped syscall succeeded\n");
}

asm

static int use_raw(int cmd, union bpf_attr *attr, unsigned int size) {
    long ret;
    errno = 0;
    __asm__(
        "movq %1, %%rax\n"        /* syscall number */
        "movq %2, %%rdi\n"        /* arg1 */
        "movq %3, %%rsi\n"        /* arg2 */
        "movq %4, %%rdx\n"        /* arg3 */
        "syscall\n"
        "movq %%rax, %0\n"

        /* retval */
        : "=r"(ret)

        /* input operands */
        : "r"((long)__NR_bpf), "r"((long)cmd), "r"((long)attr), "r"((long)size)

        /* clobbers */
        : "rax", "rdi", "rsi", "rdx"
       );

    /* Check return value */
    if (ret < 0)
        printf("raw syscall failed, ret=%d, errno=%d\n", ret, errno);
    else
        printf("raw syscall succeeded\n");
}

gcc 7.3 bug一例 class template argument deduction fails in new-expression


template <typename T1, typename T2>
struct Bar {
    Bar(T1, T2) { }
};

int main() {
    auto x = Bar(1, 2);
    auto y = new Bar(3, 4);
    auto z = new Bar{3, 4};
}

低版本的gcc (现在低版本gcc指的是7/8了)用大括号绕过即可,为什么列这个呢,因为我遇到了

Unexpected Ways Memory Subsystem Interacts with Branch Prediction

https://github.com/ibogosavljevic/johnysswlab/blob/master/2023-12-branches-memory/binary_search.cpp#L53

int binary_search(int* array, int number_of_elements, int key) {
    int low = 0, high = number_of_elements-1, mid;
    while(low <= high) {
        mid = (low + high)/2;

        if (st == search_type::REGULAR) {
            if(array[mid] < key)
                low = mid + 1; 
            else if(array[mid] == key)
                return mid;
            else
                high = mid-1;
        }

        if (st == search_type::CONDITIONAL_MOVE) {
            int middle = array[mid];
            if (middle == key) {
                    return mid;
                }

            int new_low = mid + 1;
            int new_high = mid - 1;
            __asm__ (
                "cmp %[array_middle], %[key];"
                "cmovae %[new_low], %[low];"
                "cmovb %[new_high], %[high];"
                : [low] "+&r"(low), [high] "+&r"(high)
                : [new_low] "g"(new_low), [new_high] "g"(new_high), [array_middle] "g"(middle), [key] "g"(key)
                : "cc"
            );
        }

        if (st == search_type::ARITHMETIC) {
            int middle = array[mid];
            if (middle == key) {
                return mid;
            }

            int new_low = mid + 1;
            int new_high = mid - 1;
            int condition = array[mid] < key;
            int condition_true_mask = -condition;
            int condition_false_mask = -(1 - condition);

            low += condition_true_mask & (new_low - low);
            high += condition_false_mask & (new_high - high); 

        }
    }
    return -1;
}
Array Size (in elements) Original Conditional Moves Arithmetics
4 K Runtime: 0.22 sInstr: 434 M CPI: 1.96Mem. Data Volume: 0.45 GB Runtime: 0.14 sInstr: 785 MCPI: 0.728Mem. Data Volume: 0.25 GB Runtime: 0.19 sInstr: 1.102 MCPI: 0.69Mem. Data Volume: 0.32 GB
16 K Runtime: 0.26 sInstr: 511 MCPI: 2.01Mem. Data Volume: 0.49 GB Runtime: 0.19 sInstr: 928 MCPI: 0.77Mem. Data Volume: 0.39 GB Runtime: 0.24 sInstr: 1.308 MCPI: 0.72Mem. Data Volume: 0.46 GB
64 K Runtime: 0.32 sInstr: 584 MCPI: 2.143Mem. Data Volume: 0.48 GB Runtime: 0.24 sInstr: 1.064 MCPI: 0.90Mem. Data Volume: 0.25 GB Runtime: 0.31Instr: 1.504CPI: 0.82Mem. Data Volume: 0.26 GB
256 K Runtime: 0.43 sInstr: 646 MCPI: 2.59Mem. Data Volume: 0.36 GB Runtime: 0.39 sInstr: 1.199 MCPI: 1.28Mem. Data Volume: 0.32 GB Runtime: 0.47 sInstr: 1.698 MCPI: 1.09Mem. Data Volume: 0.36 GB
1 M Runtime: 0.56 sInstr: 727 MCPI: 3.05Mem. Data Volume: 0.67 GB Runtime: 0.59 sInstr: 1.333 MCPI: 1.72Mem. Data Volume: 0.59 GB Runtime: 0.70 sInstr: 1.891 MCPI: 1.42Mem. Data Volume: 0.68 GB
4 M Runtime: 1.127 sInstr: 798 MCPI: 4.65Mem. Data Volume: 9.94 GB Runtime: 1.48 sInstr: 1.467 MCPI: 3.1Mem. Data Volume: 3.75 GB Runtime: 1.59 sInstr: 2.084 MCPI: 2.45Mem. Data Volume: 3.9 GB
16 M Runtime: 1.65 sInstr: 870 MCPI: 6.26Mem. Data Volume: 18.48 GB Runtime: 2.75 sInstr: 1.601CPI: 4.16Mem. Data Volume: 6.95 GB Runtime: 2.90 sInstr: 2.277 MCPI: 3.18Mem. Data Volume: 7.05 GB

课外阅读

快排代码

static int partition(std::vector<float>& vector, int low, int high) {
    float pivot = vector[high];
    int i = (low - 1);
    for (int j = low; j < high; j++) {
        if (vector[j] <= pivot) {
            i++;
            std::swap(vector[i], vector[j]);
        }
    }
    i = i + 1;
    std::swap(vector[i], vector[high]);
    return i;
}
    static int partition(std::vector<float>& vector, int low, int high) {
        float* vector_i = &vector[low];
        float* vector_j = &vector[low];
        float* vector_end = &vector[high];

        __m128 pivot = _mm_load_ss(&vector[0] + high);
        while(true) {
            if (vector_j >= vector_end) break;
            __m128 vec_i = _mm_load_ss(vector_i);
            __m128 vec_j = _mm_load_ss(vector_j);

            __m128 compare = _mm_cmplt_ss(vec_j, pivot); // if (vec_j < pivot)
            __m128 new_vec_i = _mm_blendv_ps(vec_i, vec_j, compare);
            __m128 new_vec_j = _mm_blendv_ps(vec_j, vec_i, compare);

            int increment = _mm_extract_epi32(_mm_castps_si128(compare), 0) & 0x1;

            _mm_store_ss(vector_i, new_vec_i);
            _mm_store_ss(vector_j, new_vec_j);

            vector_i += increment;

            vector_j++;
        }

        std::swap(*vector_i, *vector_end);
        return (vector_i - &vector[0]);
    }


代码在这里 https://github.com/ibogosavljevic/johnysswlab/blob/master/2022-01-sort/

感觉值得展开讲讲。我找作者要了授权,后面还会继续介绍这个。本地也复现一下

constexpr number parsing

有句讲句 from_chars接口有点难用

auto res = std::from_chars(str.data() + start, str.data() + str.size(), result);    
if (res.ec == std::errc{}) {...}

可以用结构化绑定,更好看一点

c++26可以直接这么用

auto res = std::from_chars(str.data() + start, str.data() + str.size(), result);    
if (res) { ... }

converting string_view to time point

std::chrono::sys_seconds convertToTimePoint(std::string_view fmtstring)
{
    std::chrono::sys_seconds syssec;
    std::istringstream in{std::string{raw_data}};//raw_data is a string_view
    in >> std::chrono::parse(fmtstring, syssec);
    return syssec;
}

没有std::chrono::parse?

std::chrono::sys_seconds convertToTimePoint(std::string_view fmtstring)
{
    std::chrono::sys_seconds syssec;
    std::istringstream in{std::string{raw_data}};//raw_data is a string_view
    std::tm tm = {};
    in >> std::get_time(&tm, fmtstring.data());
    std::time_t time = std::mktime(&tm);
    if(in.good())
      syssec =  std::chrono::time_point_cast< std::chrono::sys_seconds::duration>(std::chrono::system_clock::from_time_t(time));
    else throw std::runtime_error(std::string("Could not convert ") + raw_data + " to a date time value with format string " + fmtstring);
    return syssec;
}

怎么测试编译器 Testing the MSVC Compiler Backend

有点意思

视频

最近的cppcon有几个不错的都非常硬,我准备单独发,不放在这个环节了,这里预告一下

一个是 taro https://www.bilibili.com/video/BV1BC4y1R7iL/?p=34 这个点子虽然有意思,但是代码完成度一般,感觉不如taskflow

这个可以结合taskflow一起讲一讲。

一个是代码重构

How to Build Your First C++ Automated Refactoring Tool - Kristen Shaker - CppCon 2023

介绍利用clangtidy原地该代码的,自动改,还算有点意思 女演讲人长得有点像三表哥说实话

一个是讲代码分析

Object Introspection: A C++ Memory Profiler - Jonathan Haslam & Aditya Sarwade - CppCon 2023

都是有意思的工作

开源项目介绍

互动环节

最近微信群里来了几个做静态检查产品的老哥,突然感觉到国内做对表coverity产品的都没什么声音,这里也和大家一起互动讨论下

都用过哪些静态检查产品?clang-tidy?gconv?coverity?cpplint/cppcheck 感觉基本没啥用,除了修订格式

sonar?

国产的用过吗? analyze 这个听说过吗?

欢迎大家讨论


上一期

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账