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
这玩意
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).