C++ 中文周刊 第95期

2023-02-06 15:45:34 浏览数 (1)

C 中文周刊 第95期

周刊项目地址

公众号

弄了个qq频道,手机qq点击进入

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

请提交 issue

新年第一周


文章

  • 编程求一个正整数有几位,最快的方法是什么?

__builtin_clzll.作者还讲了一些优化的东西,涨涨见识

  • C at the end of 2022

总结了2022年来c 的各种进展,很全面了

  • Did you know that C 23 permitts static constexpr variables in constexpr functions?

直接看代码

代码语言:javascript复制
constexpr auto foo() {
  static constexpr auto value = 42; // error in C  20, okay in C  23
  return value;
}

乍看没啥用

给个例子

代码语言:javascript复制
template<char... Cs>
[[nodiscard]] constexpr auto to_string_view(){
    static constexpr char p[sizeof...(Cs)] = {Cs...};
    return std::string_view(p, sizeof...(Cs));
}

我发现这个特性和例子差距有点像你已经学会1 1=2了来证明黎曼猜想吧那种感觉

  • Did you know DRY (Don’t Repeat Yourself) comparisons pattern?

实现条件判断版本的none of any of

代码语言:javascript复制
auto none_of(auto pred, auto... ts) {
    const auto a = std::array{ts...};
    return std::none_of(std::cbegin(a), std::cend(a), pred);
}

auto before(int a, int b, int c) {
    if (a != 2 and b != 2 and c != 2) {
      return 42;
    }
    return 0;
}

auto after(int a, int b, int c) {
    if (none_of([](auto x) { return x == 2; }, a, b, c)) {
      return 42;
    }
    return 0;
}

anyof怎么实现?

代码语言:javascript复制
#include <utility>
#include <tuple>
#include <concepts>

template<class ... Args>
struct Comp {
    template<class T>
    auto operator==(T && other) {
        return std::apply(
            [&other](auto &&... data) {
                return (((std::equality_comparable_with<decltype(data), T>) && data == other) || ...);
            },
            this -> data
        );
    }
    std::tuple<Args...> data {};
};

template<class ...Args>
auto any_of(Args && ... args)  {
    return Comp<Args...> {
        std::make_tuple(std::forward<Args>(args)...)
    };
    
}

和上面差距有点大

  • Adding Design-by-Contract [[invariant]] conditions to C , via a GCC plugin

实现了一个gcc插件支持[[invariant]]特性,代码在这里https://github.com/GavinRay97/gcc-invariant-plugin

博客记录了开发插件的方法和过程,挺有意思的

  • Debugging binaries invoked from scripts with GDB

gdb调试和shell交互,复杂

  • Cpp2 and cppfront: Year-end mini-update

介绍他的折腾

  • Parallelizing C using Execution Policies

就是std::execution::par/std::execution::par_unseq这玩意

代码语言:javascript复制
std::vector<size_t> indices(num_pixels);
 // initialize indices with 0, 1, ..
std::iota(indices.begin(), indices.end(), 0); // needs <numeric>

std::transform( // needs <algorithm>
    std::execution::par, // <-- needs <execution>
    indices.begin(), indices.end(), pixels.begin(), 
    [](size_t index){
        return expensive_calculation(index);
    }
);
  • 5 techniques for writing memory safe C

老生常谈讲智能指针那套东西

  • Determining if a template specialization exists

检查有没有std::hash特化

代码语言:javascript复制
struct HasStdHash {
private:
  template <class T, class Dummy = decltype(std::hash<T>{})>
  static constexpr bool exists(int) {
    return true;
  }

  template <class T>
  static constexpr bool exists(char) {
    return false;
  }

public:
  template <class T>
  static constexpr bool check() {
    return exists<T>(42);
  }
};

std::cout << "Does std::string have std::hash? " << HasStdHash::check<std::string>();

能不能更泛化一点?

代码语言:javascript复制
template <template <class... InnerArgs> class Tmpl>
struct IsSpecialized {
private:
  template <class... Args,
          class dummy = decltype(Tmpl<Args...>{}.~Tmpl<Args...>())>
  static constexpr bool exists(int) {
    return true;
  }

  template <class... Args>
  static constexpr bool exists(char) {
    return false;
  }

public:
  template <class... Args>
  static constexpr bool check() {
    return exists<Args...>(42);
  }
};

但这个代码对于这种场景是无效的

代码语言:javascript复制
template<class T> struct SomeStruct;
bool test1 = IsSpecialized<SomeStruct>::check<std::string>();

template<> struct SomeStruct<std::string> {};
bool test2 = IsSpecialized<SomeStruct>::check<std::string>();

后面又讨论了一通ADL检测,我已经看不懂了

  • Pro TBB阅读笔记(一

随便看看

  • How to Optimize a CUDA Matmul Kernel for cuBLAS-like Performance: a Worklog

cuda代码调优记录。看不懂

  • Emulating an emulator inside itself. Meet Blink

模拟器里玩模拟器,看不懂

  • MSVC: The Devourer of Const

msvc一个bug

代码语言:javascript复制
#include <iostream>
#include <string>

template <typename T>
T galactus_the_devourer_of_const(const T& v) {
    return false ? std::move(T{}) : std::move(v);
}

int main() {
    const std::string food = "asdf";
    std::cout << "before: " << food << 'n';
    galactus_the_devourer_of_const(food);
    std::cout << "after:  " << food << 'n';
    return 0;
}

// before: asdf
// after:  

莫名其妙的被move了。解决办法,/permissive-,默认是/permissive

  • brpc之bthread
  • 自底向上brpc(一):resource_pool

感兴趣可以看看

  • Tracking Shared Pointer Leaks

介绍这个库 https://github.com/iboB/xmem

可以分析智能指针引用,用法就不贴了。和hook malloc那种类似。不过要做很多很多适配代码

  • Using perfect (and imperfect) forwarding to simplify C wrapper classes

看代码

代码语言:javascript复制
namespace winrt::Contoso::implementation {
    struct ItemCollection : ItemCollectionT<ItemCollection>{
        template<typename...Args> auto First(Args&&... args) {
            return m_items.First(args...);
        }

        template<typename...Args> auto GetAt(Args&&... args) {
            return m_items.GetAt(args...);
        }

        template<typename...Args> auto Size(Args&&... args) {
            return m_items.Size(args...);
        }

        template<typename...Args> auto IndexOf(Args&&... args) {
            return m_items.IndexOf(args...);
        }

        template<typename...Args> auto GetMany(Args&&... args) {
            return m_items.GetMany(args...);
        }
        // And our bonus method
        hstring ToJson();
    private:
        Windows::Foundation::Collections::IVector<Contoso::Item> m_items;
    };
}

视频

  • Trading at light speed: designing low latency systems in C - David Gross - Meeting C 2022

optvier做高频交易的,这个talk还是很有东西的

一些性能优化点

小对象尽可能紧凑,利用好cpu cache

能用vector用vector,甚至boost::stable_vector,unordered_map开销非常恐怖 workding set size有分析工具wss https://github.com/brendangregg/wss

seqlock怎么做更快?

作者实现了个基于奇偶版本号的lock,单生产者多消费者,T很小,这种写法没啥竞争,很值

代码语言:javascript复制
template<typename T>
class SeqLock {
  T mData;
  std::atomic<uint32_t> mVersion;
};

template<typename T>
void SeqLock<T>::Store(const T& value) {
  mVersion =1;
  std::memcpy(&mData, value, sizeof(T));
  mVersion =1;
}

template<typename T>
bool SeqLock<T>::Load(T& value) {
  const auto version = mVersion.load();
  if (version & 1 != 0) {
      return false;
  }
  std::memcpy(&value, mData, sizeof(T));
  return version == mVersion;
}

更快的SPMC?

考虑消费队列 SPSC

代码语言:javascript复制
struct SPSCQueue {
  alignas(64) std::atomic<uint64_t> mWriteIndex;
  alignas(64) std::atomic<uint64_t> mReadIndex;
  alignas(64) uint8_t mData[0];
};

就是一个循环buffer

SPMC那就不用维护mReadIndex,同时尽可能的让竞争更小

代码语言:javascript复制
struct SPMCQueueV1 {
  alignas(64) std::atomic<uint64_t> mIndex;
  alignas(64) std::atomic<uint64_t> mPendingIndex;
  alignas(64) uint8_t mData[0];
};
代码语言:javascript复制
template <typename C>
void SPMCQueueV1::Push(MessageSize size, C WriteCallback) {
    mPendingIndex  = size;
    std::memcpy(mCurrent, size, sizeof(MessageSize));
    WriteCallback(mCurrent    sizeof(MessageSize));
    mIndex  = size;
}

template <typename C>
void SPMCQueueV1::Pop(C ReadCallback) {
    if (mPendingIndex == mIndex) return;
    MessageSize size;
    std::memcpy(&size, mCurrent   sizeof(MessageSize), sizeof(MessageSize));
    uint8_t buffer[size];
    std::memcpy(buffer, mCurrent   sizeof(MessageSize), size);
    ReadCallback(buffer, mSize);
}

性能不行

考虑seqlock的思路,使用版本号来替换index,降低index频繁修改的开销,均摊到每个槽的版本号上,性能直接起飞

每个槽都有mBlockCounter和mVersion,mVersion判定变化,mBlockCounter控制消费

代码语言:javascript复制
struct Block {
  alignas(64) std::atomic<uint64_t> mVersion;
  alignas(64) std::atomic<uint64_t> mSize;
  alignas(64) uint8_t mData[0];
};
struct Header {
  alignas(64) std::atomic<uint64_t> mBlockCounter;
  alignas(64) Block mData[0];
};

template <typename C>
void SPMCQueueV2::Push(MessageSize size, C WriteCallback) {
    mVersion =1
    WriteCallback(&mCurrentBlock->mData[0]);
    mVersion =1
    mBlockCounter =1
}

系统调优,降了很多cpu cache利用,还有CPU隔离/用户态网络,NUMA绑定 大页等等

采集参数信息,保持观察

这随便说了一嘴,重要还是上面seqlock这套思路,将了大半个小时

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

新项目介绍/版本更新

  • bitset2: bitset improved 给标准库的bitset做了很多调优和加强

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持!

本文永久链接

代码语言:txt复制
     This site is open source. [Improve this page](https://github.com/wanghenshui/cppweeklynews/edit/dev/posts/095.md).

0 人点赞