前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ 中文周刊 第95期

C++ 中文周刊 第95期

作者头像
王很水
发布2023-02-06 15:45:34
4260
发布2023-02-06 15:45:34
举报

C++ 中文周刊 第95期

周刊项目地址

公众号

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

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

提交 issue

新年第一周


文章

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

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

直接看代码

代码语言: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了来证明黎曼猜想吧那种感觉

实现条件判断版本的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)...)
    };
    
}

和上面差距有点大

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

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

gdb调试和shell交互,复杂

介绍他的折腾

就是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);
    }
);

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

检查有没有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检测,我已经看不懂了

随便看看

cuda代码调优记录。看不懂

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

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

感兴趣可以看看

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

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

看代码

代码语言: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;
    };
}

视频

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前来对线

新项目介绍/版本更新


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

本文永久链接

代码语言:txt
复制
     This site is open source. [Improve this page](https://github.com/wanghenshui/cppweeklynews/edit/dev/posts/095.md).
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C++ 中文周刊 第95期
    • 文章
      • 视频
        • 开源项目需要人手
          • 新项目介绍/版本更新
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档