背景

我们的新项目有个比较复杂的全区全服交易行系统,其中搜索和推荐是高实时性全区服多维度排序的,并且要支持比较复杂的标签交集查询和属性范围查询的自由组合。 当有订单发生变化时,它不仅仅会影响全服状态下搜索和推荐条件的结果变化,也会同时影响商品维度的聚合,交易行层面的数据聚合。

前言

我们项目组前段时间排查和分析压测环境下的某些业务模块大量索引结构的内存问题。通用的工具比如 jemalloc+jeperf 或者 tcmalloc+gperf 的组合过于底层,一方面开启跟踪开销较高,另一方面也是会产生过多噪音数据影响判断。所以我针对我们的智能指针(包含 std::shared_ptr 和我最近写了个非线程安全的版本的 strong_rc_ptr , 这个后面有空再分享)和STL容器实现了allocator来帮助动态的手动插桩来分析问题。 最终的效果是可以通过一键替换类型申明的Allocator来插入动态控制和插桩统计的能力,这里分享一下手夯标准STL allocator的一些实现细节,方便其他小伙伴如果需要做类似的实现来参考。

背景

这篇分享拖更了好久了。问题起源于去年我们项目组接入 opentelemetry-cpp 的时候,在进程优雅退出的时候偶现超时,虽然可以直接kill进程没啥影响但是退出不“优雅”的话总归会破坏发布流程,增加人工介入的成本。这里记录一下问题可能其他的组件有类似的用法也会有相似的问题。

前言

很久很久以前,浮点数的性能和跨平台跨硬件架构一致性是无法获得保证的,所以我们一般在需要强一致性和高性能的游戏服务器中会禁用浮点数,转而使用自己实现的定点数。 这么多年过去了,前段时间想看看现代化硬件下是否仍然有性能问题和是否能够保证一致性,做了些简单的测试,这里记录一下。

C++20 开始支持 Module 了。在以前C++为了解决循环依赖问题,经常会把类或者函数声明写前面,实现写后面。然后中间的代码就可以实现内部模块的内聚而互相引用。比如:

class foo;

void bar(foo*);

class foo {
public:
    foo(){
        bar(this);
    }
};

那么在 Module 里怎么处理这种需求呢?其实我之前一直只是知道有这么个东西,并没有深入研究过。前段时间看到公司论坛里有同学问,就现学了并且试了一下,以下是一些记录。

前言

最近GCC 10.1.0 发布,三大编译器(MSVC、GCC、Clang)都已经支持了C++20协程,之前给 libcopp 接入 C++20协程 的计划也就提上了日程。C++20协程 在创建、切换开销和内存分配上和传统有栈协程相比有着无可比拟的优势。但是C++20全面普及还有相当长一段时间,所以我们设计的重要目标之一就是能够让以后的迁移更容易且更平滑地进行,本文则是记录了 libcopp 接入 C++20协程 时地一些性能上和平滑接入上的思考和成果。

前段时间有同事联系我想看看可能推广我之前写的协程库 libcopp,虽然 libcopp 已经用到过好几个项目上,这几年也断断续续地写了一些实现细节的文章,但是也但确实需要系统、概览性地介绍下 libcopp ,所以就有了这篇文章。

Github: https://github.com/owent/libcopp Document: https://libcopp.atframe.work/

libcopp 的由来

协程的概念并不是什么非常新颖的东西,最早有做 libcopp 的想法的时候,是听了微信分享的 libco 。但是我们游戏业务里大部分的实现都还是走的事务和Task/Step的模型,特别是C++上异步调用非常不直观。而这种协程的方法可以比较容易地把接口设计得很简洁,而且后续的功能集成上也很容易不破坏原有的API约定,还有微信这么大的业务背书,我们就想在游戏业务里也使用这种方案。我们先是预研了一些类似的方案,但是都不是特别满意。

前言

之前写了 《协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比》《C++20 Coroutine》 ,但是一直没写 C++20 Coroutine 的测试报告。

现在的草案版本比我当时写 《C++20 Coroutine》 的时候有了一点点更新,cppreference 上有文档了(https://en.cppreference.com/w/cpp/language/coroutines) 。里面列举的标准文档是P0912R5,这个文档目前还没完工,详情可以看他的来源N4775。不过内容上暂时还没有太大的变化,今天我就照着之前的方式来benchmark一波 C++20 Coroutine 吧。

压力测试机环境

为了方便比较,我更新了一下之前在 《协程框架(libcopp)v2优化、自适应栈池和同类库的Benchmark对比》 里的测试项目的版本。Windows环境仅仅是为了测试MSVC下的性能,因为GCC还不支持所以Linux下是使用Clang编译的。

前言

最近的新闻里 C++20 已经确认的内容里已经有了协程组件,之前都是粗略看过这个协程草案。最近抽时间更加系统性的看了下接入和实现细节。

我的测试代码都是在MSVC下开启 /await 选项后测试的,在我本地的Linux clang环境中,可以通过 $LLVM_CLANG_PREFIX/bin/clang++ -std=c++2a -O0 -g -ggdb -stdlib=libc++ -fcoroutines-ts -lc++ -lc++abi -Wl,-rpath=$LLVM_CLANG_PREFIX/lib/ test.cpp 编译和运行。

前段时间看到说Lua 5.4用了一种新的通用随机数算法,替换掉本来内部使用的CRT的随机数引擎。我看了一下大致的实现,CPU和空间复杂度任然保持了一个较低的水平,并且循环节和说是随机性都还不错。我们游戏项目中原本对大量随机数场景的随机数算法使用的是基于线性同余的TAUS88,但是使用过程中发现这个算法分布上还是有一些不是很理想,所以就想把这个新的科研成果也用进我们项目中试试看效果。

前言

最近看Rust相关东西的时候看到一篇关于压缩可执行文件的文章。压缩可执行文件对嵌入式开发特别有用,但是延伸一下用来减少我们游戏行业里预编译的工具二进制包大小和Android/iOS的库也是蛮有用的。

原文见这里: https://jamesmunns.com/blog/tinyrocket/

基本流程

  1. Release编译,移除调试符号文件,开启最小化size优化(-Oz)
  2. 使用LLVM的全量LTO
  3. 使用xargo重新编译标准库(std)和核心库(core)(这个C/C++不容易模仿,而且编译选项十分难搞)
  4. 移除jemalloc(服务器程序还是留着比较好,内置的malloc实现一般碎片比较厉害。虽然C/C++默认也不是jemalloc,很多项目为了新能还是会用它)
  5. 移除panic的详情信息(这个仅适用于Rust
  6. strip(由GNU的binutils提供),参考命令: strip [二进制]
  7. UPX进一步压缩加壳

尝试改造优化

然后尝试使用上面的流程改造我们的 gmtools-cli 。原先我是直接开LTO+Release编译的,编出的文件大小为4.4MB(4520728字节)。

开始之前

很多语言的log模块都有一个功能,就是在打log的时候能够追溯调用栈,有的时候对查bug能有点帮助。之前我也想过给我们的log模块加上C++的backtrace的功能,迟迟一直没有做主要是两个原因:一是C++的backtrace在各个平台和编译器上都不太一样,比较冗杂;二是C/C++在编译优化之后,调用行之类的信息和甚至一些函数可能就被优化没了。所以能提供的信息就相当有限。前两天刚好有朋友问有没有提供这个,所以就花了点时间整理了下适配方案。