皮皮网

【ebbi公式源码】【泡泡屏源码】【板块名称源码】libstdc 源码

2024-11-23 12:56:35 来源:less-loader 源码

1.C++ string 源码实现对比
2.lldb 小记和std::string的数据结构图源码阅读
3.什么时候以struct替代class?
4.图文鲲鹏916-ARM64架构源码gcc编译完整记录
5.如何使用oprofile对软件做profiling
6.Linux环境源码安装GCC/CMAKE

libstdc 源码

C++ string 源码实现对比

       标题:C++ string 源码实现对比

       作为游戏客户端开发工程师,作者lucasfan分享了他对不同版本C++ string源码的深入分析,以帮助开发者解决std::string在现网中可能引发的Crash问题。本文将对比libstdc++、腾讯内部的Android和iOS SDK使用的string实现,以及tpstl string,ebbi公式源码涉及内存结构、构造函数和析构方法等关键部分。

       1. libstdc++ string

       Android SDK普遍采用的libstdc++ string以写时拷贝(COW)特性为主,但可能导致性能问题。其内存结构包含指向堆上数据的指针和一个包含长度信息的_Rep对象。构造函数如char*构造器负责内存申请和字符串拷贝,拷贝构造通过_M_grab处理共享与深度拷贝,拷贝赋值操作涉及assign方法。

       2. libc++ string (iOS SDK)

       相比之下,iOS使用了短字符串优化(SSO),内存结构分为长字符串和短字符串模式,通过位标志判断。char*构造器和拷贝构造根据字符串类型执行不同初始化方法,右值拷贝利用转移语义节省内存。

       3. tpstl string (腾讯自研)

       tpstl string简化了STL,使用内存池管理内存,其构造和赋值操作均在内存池上进行,有助于解决跨库问题。

       结论

       理解这些string源码实现有助于开发者定位和解决实际问题。泡泡屏源码作者将继续分享更多案例和调试策略,有兴趣的开发者可加入官方QQ交流群:,获取更多技术分享。

lldb 小记和std::string的数据结构图源码阅读

       在深入理解LLVM和GCC的std::string实现差异时,我们首先从lldb着手,探索其内部工作机制。昨天尝试编译llvm后,今天我们就来研究std::string在lldb中的表现,它与g++的std::string实现有何不同。

       从一个简单的测试程序开始,我们对比了用g++和clang++编译的代码。在g++版本中,字符串s使用了短字符串优化(SSO)的存储方式,"hi"存储在_M_local_buf中。SSO旨在节省内存,通过为短字符串预留固定大小的结构,如长度、容量和指向字符串数组的指针,共字节。

       对于长字符串,例如scow,存储方式不同。尽管_M_local_buf中没有"this is a sunny day",但通过M p找到的板块名称源码实际字符串地址显示出长字符串的存储策略。这表明在长字符串时,std::string会采用常规的存储方式,即一个指针指向字符串数组。

       接下来,我们需要弄清楚如何判断何时使用SSO。在代码中,我们猜测可能通过某些标志位来区分,但实际观察到的operator[]函数表明,M p始终指向字符串数组,不论字符串长度。这就意味着,无论短长,读取指定位置的字符都遵循相同的逻辑。

       在libstdc++(g++)和libc++(llvm)的实现上,我们发现两者在数据结构上存在差异。例如,libstdc++的std::string使用字节的union,而libc++则为字节。区分长短字符串的方式在libc++中通过检查容量字段的比特位实现,这依赖于机器的字节序。

       附录中,我分享了自己编译LLVM的体验和使用clang++编译程序的CMakeLists.txt设置,供有兴趣的读者参考。

什么时候以struct替代class?traefik源码解析

       考虑使用struct而非class时,重点在于结构体的C++风格及其特性。与C语言中的结构体不同,C++中的结构体支持模板和大量继承(尽管不使用虚函数)。这些特性在C语言中不存在,因此在C++中使用结构体显得更为自然。

       例如,ut库,一个小巧的C++单元测试库,其源码仅多行,几乎全部使用了结构体。这种选择体现了C++中结构体的灵活性和简洁性。

       以libstdc++为例,即gcc开源项目中的C++标准库,其ranges实现源码同样采用了大量结构体。这些结构体设计简洁,成员变量数量不多,一般只有一两个至三个,且成员变量的私有化并不普遍。因此,在这种情况下,使用类定义反而显得多余。

       综上所述,在C++中,当结构体的驱动sys源码成员变量数量不多,且成员变量的私有化不是主要需求时,使用结构体而非类更为合适。结构体的简洁性、模板支持以及与大量继承的结合,使其成为解决特定问题时的优良选择。

图文鲲鹏-ARM架构源码gcc编译完整记录

       以下是关于ARM架构源码gcc编译的详细步骤记录:

       首先,确保已经准备就绪,如果cmake未安装,需要进行安装。检查cmake版本以确认其是否满足需求。

       安装必要的依赖包,如isl、gmp、mpc、mpfr等,检查它们是否已成功安装。

       针对gcc版本过低的问题,需下载并更新到7.3版本。下载并解压gcc7.3的安装包。

       在gcc-7.3.0目录下,确认已下载和安装了所有依赖包。

       利用多核CPU的优势,通过“-j”参数加速编译过程。原先是按照官方文档使用make -j,但速度缓慢,后来调整为make -j以提升效率。

       依次执行编译目录创建、gcc编译、安装以及确认“libstdc++.so”软连接在正确的目录(/usr/lib)。

       编译完成后,通过查看gcc版本来确认安装是否成功。

       以上就是完整的gcc编译安装流程。如果您觉得这些信息对您有所帮助,欢迎分享和关注我们的更新。更多技术内容敬请期待,感谢您的支持!

如何使用oprofile对软件做profiling

       ã€€ã€€å…³äºŽXilinx Zynq-带来的新的系统设计思路,以及Profiling的对象libjpeg,前文已经描述过了,再此不再赘述。

       ã€€ã€€ä¸€. Oprofile简介

       ã€€ã€€Profiling是对不同性能特征的数据的形式化总结或分析,它通常以图形和表的形式出现。它提供为特定的处理器事件收集的采样百分数或数 量,比如cache miss rate、TLB miss rate等等。一般来说,主要目的是为了找出软件中的性能瓶颈,然后有针对性的优化以提升软件的整体性能。

       ã€€ã€€Oprofile 是用于 Linux 的若干种评测和性能监控工具中的一种。它可以工作在不同的体系结构上,包括ARM, PowerPC, MIPS, IA, IA 和 AMD Athlon等等。它的开销很小,从Linux 2.6 版起,它被包含进了Linux内核中。

       ã€€ã€€Oprofile可以收集有关处理器事件的信息,帮助用户识别诸如循环的展开、cache的使用率低、低效的类型转换和冗余操作、错误预测转移 等问题。Oprofile是一种细粒度的工具,可以为指令集或者为函数、系统调用或中断处理例程收集采样。Oprofile 通过取样来工作。使用收集到的评测数据,用户可以很容易地找出性能问题。

       ã€€ã€€é€šè¿‡ç›‘察CPU的hardware events,oprofile可以在运行状态下对整个Linux系统进行profiling。Profiling的对象可以是Linux kernel (包括modules和interrupt handlers), shared libraries或者应用程序。

       ã€€ã€€ä»Ž0.9.8版本开始,oprofile支持Perf_events profiling mode模式。应用程序operf被用来控制profiling过程;而在legacy mode下,是通过opcontrol脚本和oprofiled daemon来完成的。Operf不再象legacy mode那样需要OProfile kernel driver,它直接和Linux Kernel Performance Events Subsystem打交道。使用operf,就可以用普通用户的身份来profiling用户的应用程序了,当然如果需要对整个系统来profiling 的时候还是需要root权限的。

       ã€€ã€€å¦‚果硬件不支持OProfile使用performance counters,OProfile就只能工作在Timer Mode下了。Timer Mode只能在legacy profiling mode下使用,即只能通过opcontrol脚本来控制。

       ã€€ã€€Oprofile的website为:piled (JIT) code

       ã€€ã€€? 可以对整个系统做profiling

       ã€€ã€€? 可以观察CPU内部的细节,例如cache miss rate

       ã€€ã€€? 可以多源代码做annotation

       ã€€ã€€? 可以支持instruction-level的profiling

       ã€€ã€€? 可以生成call-graph profiles

       ã€€ã€€ä¸è¿‡OProfile也不是万能的,它也有自己的局限性:

       ã€€ã€€? 只能在x, ARM, 和PowerPC架构上生成call graph profiles

       ã€€ã€€? 不支持%精确的instruction-level profiling

       ã€€ã€€? 对dynamically compiled (JIT) code profiling的支持还不完善。

       ã€€ã€€æ— è®ºå¦‚何,Oprofile的功能都比gprof要强很多,代价是配置起来会比较麻烦。

       ã€€ã€€äºŒ. 编译Oprofile

       ã€€ã€€é¦–先最好在Linux kernel里面选中Oprofile driver,以获得全面的支持。

       ã€€ã€€ä¸‹è½½Linux kernel Source:从/Xilinx/linux-xlnx 可以下载到Xilinx提供的验证好的内核。如果不方便使用Linux下的git工具,可以单击页面上的releases找到相应的版本下载tar ball。下载的时候最好选tar.gz格式的,而不是zip格式的,因为后者在处理symbol link的时候有可能会出问题。

       ã€€ã€€å› ä¸ºç¬”者使用的是Xilinx Linux pre-built .7,所以这里下载的是linux-xlnx-xilinx-v.7.tar.gz

       ã€€ã€€è§£åŽ‹ç¼©åŽï¼Œç”¨ä»¥ä¸‹å‘½ä»¤è°ƒå‡ºLinux kernel的配置界面:

       ã€€ã€€export ARCH=arm

       ã€€ã€€export CROSS_COMPILE=arm-xilinx-linux-gnueabi-

       ã€€ã€€make xilinx_zynq_defconfig

       ã€€ã€€make xconfig 或者make menuconfig

       ã€€ã€€åœ¨é…ç½®ç•Œé¢ä¸Šå°†ä»¥ä¸‹ä¸¤é¡¹å‹¾ä¸Šï¼š

       ã€€ã€€General setup --->

       ã€€ã€€[*] Profiling support

       ã€€ã€€<*> OProfile system profiling

       ã€€ã€€ç„¶åŽmake uImage即可生成新的uImage,用来替换Xilinx Linux pre-built .7中的Linux kernel image。同时我们也需要vmlinux来检查profiling的结果。

       ã€€ã€€Oprofile需要popt, bfd, liberty库,要在嵌入式单板上使用这些库,需要手工完成交叉编译。

       ã€€ã€€é’ˆå¯¹popt 1.7,用以下命令完成编译:

       ã€€ã€€./configure --prefix=/home/wave/xilinx/oprofileprj/rootfs --host=arm-xilinx-linux-gnueabi --with-kernel-support --disable-nls && make && make install

       ã€€ã€€é’ˆå¯¹binutils 2.,用以下命令完成编译:

       ã€€ã€€./configure --host=arm-xilinx-linux-gnueabi --prefix=/home/wave/xilinx/oprofileprj/rootfs --enable-install-libbfd --enable-install-libiberty --enable-shared && make && make install

       ã€€ã€€ä¸è¿‡--enable-install-libiberty没有效果,所以需要手工把libiberty.a和libiberty.h拷贝到相应的位置。

       ã€€ã€€é’ˆå¯¹oprofile 0.9.9,用以下命令完成编译:

       ã€€ã€€./configure --host=arm-xilinx-linux-gnueabi --prefix=/home/wave/xilinx/oprofileprj/rootfs --with-kernel-support --with-binutils=/home/wave/xilinx/oprofileprj/rootfs && make && make install

       ã€€ã€€é…ç½®è¿‡ç¨‹ç»“束后可能会有以下提示,因为没有打算用GUI和profile JITed code,所以直接忽视之。

       ã€€ã€€config.status: executing libtool commands

       ã€€ã€€Warning: QT version 3 was requested but not found. No GUI will be built.

       ã€€ã€€Warning: The user account 'oprofile:oprofile' does not exist on the system.

       ã€€ã€€To profile JITed code, this special user account must exist.

       ã€€ã€€Please ask your system administrator to add the following user and group:

       ã€€ã€€user name : 'oprofile'

       ã€€ã€€group name: 'oprofile'

       ã€€ã€€The 'oprofile' group must be the default group for the 'oprofile' user.

       ã€€ã€€å°†ç¼–译完成的uImage,vmlinux,oprofile binary,重新编译的没有-pg的libjpeg binary以及tool chain的libc打包放到SD卡中,准备在ZC开发板上尝试profile djpeg。

       ã€€ã€€ä¸‰. 运行Oprofile

       ã€€ã€€æ­£å¸¸å¯åŠ¨åµŒå…¥å¼Linux后,在开发板的console上一次输入以下命令:

       ã€€ã€€mount /dev/mmcblk0p1 /mnt

       ã€€ã€€mkdir -p /home/root/work

       ã€€ã€€cd /home/root/work

       ã€€ã€€tar zxvf /mnt/jpeg-bin-nopg.tar.gz

       ã€€ã€€cd jpeg-bin/bin

       ã€€ã€€cp /mnt/park-x.jpg .

       ã€€ã€€export LD_LIBRARY_PATH=/home/root/work/jpeg-bin/lib

       ã€€ã€€cd /home/root/work

       ã€€ã€€tar zxvf /mnt/rootfs.tar.gz

       ã€€ã€€cd rootfs

       ã€€ã€€chown root:root -R

*

       ã€€ã€€cp -R bin/* /usr/bin

       ã€€ã€€cp -R lib/* /lib

       ã€€ã€€cp /bin/which /usr/bin

       ã€€ã€€cp /bin/dirname /usr/bin

       ã€€ã€€mkdir -p /home/wave/xilinx/oprofileprj/rootfs/share

       ã€€ã€€cp -R ./rootfs/* /home/wave/xilinx/oprofileprj/rootfs

       ã€€ã€€cd /home/root/work

       ã€€ã€€tar zxvf /mnt/libc.tar.gz

       ã€€ã€€cp ./lib/libstdc*.* /lib

       ã€€ã€€mkdir -p /home/wave/xilinx/libjpeg

       ã€€ã€€cd /home/wave/xilinx/libjpeg

       ã€€ã€€tar zxvf /mnt/jpeg-9.tar.gz

       ã€€ã€€cp /mnt/vmlinux /home/root/work

       ã€€ã€€cd /home/root/work/jpeg-bin/bin

       ã€€ã€€opcontrol --init

       ã€€ã€€opcontrol --vmlinux=/home/root/work/vmlinux

       ã€€ã€€opcontrol --setup --event=CPU_CYCLES:::0:1 --session-dir=/home/root/

       ã€€ã€€operf --vmlinux /home/root/work/vmlinux ./djpeg -bmp park-x.jpg > result.bmp

       ã€€ã€€opreport -l ./djpeg

       ã€€ã€€å®Œæˆè¿™ä¸€æ­¥åŽï¼Œæˆ‘们就可以看到profiling的结果了,在笔者的平台上看到的内容的主要部分如下:

       ã€€ã€€root@zynq:~/work/jpeg-bin/bin# opreport -l ./djpeg

       ã€€ã€€Using /home/root/work/jpeg-bin/bin/oprofile_data/samples/ for samples directory.

       ã€€ã€€CPU: ARM Cortex-A9, speed MHz (estimated)

       ã€€ã€€Counted CPU_CYCLES events (CPU cycle) with a unit mask of 0x (No unit mask) count

       ã€€ã€€samples % image name symbol name

       ã€€ã€€ . libc-2..so /lib/libc-2..so

       ã€€ã€€ 7. libjpeg.so.9.0.0 ycc_rgb_convert

       ã€€ã€€ 7. libjpeg.so.9.0.0 jpeg_idct_x

       ã€€ã€€ 7. libjpeg.so.9.0.0 decode_mcu

       ã€€ã€€ 6. libjpeg.so.9.0.0 jpeg_idct_islow

       ã€€ã€€ 6. djpeg finish_output_bmp

       ã€€ã€€ 2. libjpeg.so.9.0.0 jpeg_fill_bit_buffer

       ã€€ã€€ 1. djpeg put_pixel_rows

       ã€€ã€€ 0. vmlinux __copy_from_user

       ã€€ã€€ 0. libjpeg.so.9.0.0 decompress_onepass

       ã€€ã€€ 0. libjpeg.so.9.0.0 jpeg_huff_decode

       ã€€ã€€ 0. vmlinux get_page_from_freelist

       ã€€ã€€ 0. vmlinux __memzero

       ã€€ã€€ 0. vmlinux __copy_to_user_std

       ã€€ã€€ 0. vmlinux _raw_spin_unlock_irqrestore

       ã€€ã€€ 0. vmlinux do_page_fault

       ã€€ã€€ 0. vmlinux __generic_file_aio_write

       ã€€ã€€ 0. vmlinux _raw_spin_unlock_irq

       ã€€ã€€ 0. vmlinux free_hot_cold_page

       ã€€ã€€ 0. vmlinux vector_swi

       ã€€ã€€ 0. vmlinux handle_pte_fault

       ã€€ã€€ä»Žç»“果中我们可以看到libjpeg.so.9.0.0, djpeg和vmlinux中的symbol name已经可以被正确的解析出来了,和gprof的结果基本一致。相比gprof,oprofile可以在更大的范围内完成profiling。

       ã€€ã€€æˆ‘们还可以用以下命令观察源代码中特定行的执行时间,进一步缩小优化的范围,达到事半功倍的效果。

       ã€€ã€€opannotate --source ./djpeg > opannotate.txt

       ã€€ã€€å››. 小结

       ã€€ã€€é€šè¿‡å®žéªŒï¼Œæˆ‘们可以看到Oprofile可以提供更丰富的profiling结果,可以更好的帮助开发者找到瓶颈,通过有针对性的优化提升软件 性能;profiling的结果也可以帮助开发者将性能瓶颈代码通过Xilinx HLS工具用硬件加速器来实现,从而为进一步提升整个嵌入式系统的性能打开了大门。

Linux环境源码安装GCC/CMAKE

       为了在Linux环境下源码安装GCC和CMAKE,我们需要遵循详细的步骤和策略。对于GCC源码,我们可以从GitHub-gcc-mirror/gcc获取4.4.6版本。接下来,进入下载后的GCC源代码目录。

       在配置和编译GCC时,首先应该明确指定安装的目录,避免冲突。可能在配置脚本时遇到错误,这时候需要解决依赖项问题。分别安装MPFR、MPC和任何其他必要的依赖库。对于GCC8.3及以上版本,内部集成脚本能够简便地获取这些依赖库。

       安装库路径后,再次执行配置文件,加入库路径参数,确保安装的每个步骤顺利进行。配置完成后,整个GCC安装过程即宣告成功。

       为了测试GCC是否正确安装,遵循指导进行验证。

       CMake的安装同样关键,可以通过直接指定需要的GCC版本来简化安装流程。在CMake命令行参数中指定GCC路径也是可行的。

       在运行GCC4.4.6编译的程序时,可能存在系统路径问题,这是因为我们选择的是不替换安装方式。因此,需要额外操作,确保所需的库被正确添加到路径中。

       遇到GCC多版本引起的ABI兼容问题时,如果编译链接过程中遇到“undefined reference to"“std::__cxx ***””错误,这提示可能是C++ ABI问题。处理方法是,针对GCC5.1之前版本发布的libstdc++中新增的ABI,通过添加定义-D_GLIBCXX_USE_CXX_ABI=0来解决该问题。

       对于GDB版本的问题,特别在GCC.1的使用中,要求C++的编译器,导致了旧版本GDB启动出现Segment Fault。解决办法是升级GDB版本。

       附录中提供了一些额外资源,例如Mingw下载,适用于位和位Windows的最新版x_-win-sjlj;CMake下载链接以及GCC的GitHub地址等。遵循这些资源和提示,能够帮助用户顺畅进行Linux环境下的GCC和CMAKE的源码安装与配置。

c++protected继承和private继承是不是没用的废物?

       既然你所统计的项目里出现了 private 继承和 protected 继承,这不正说明确实有他们的用武之地吗?

       让我们来康康 C++ 代码的标杆——STL 的源码,是怎么做的:

       先来康 GCC 自带的 libstdc++ 的实现:

       vector, list, deque, forward_list, unordered_(multi)set/map 的底层都有用到 protected 或 private 继承。

       比如 vector 会空基类压缩优化技术,这只能用继承实现,而使用组合时就没有压缩的效果。

       考察下面代码,这是对 vector 压缩 allocator 字段原理的简化实现:

       如果 vector 直接 public 继承自 allocator,根据类型兼容原则,在指针和引用语义下,子类同时也可被视作是父类。那 vector 也能被当做 allocator 用了?这会引发语义混乱。

       而改成 private 或 protected 继承就不会了:

       这时候编译器会报错,这阻止了上面的情况发生。这样的例子比比皆是。

       还有 tuple 对空类字段的压缩,也采用了这个手法。

       2)既然谈到了 tuple,我们就来考察一下 tuple。

       这次我不亲手写代码了,就百度一下,随手找找一篇博客现场打脸好啦。

       百度搜“std::tuple 实现”,第一篇博客用常规思路来实现 tuple,即:取到第一个模板参数后,作为一个数据成员,然后递归继承 tuple。这份实现没有用到空类成员压缩优化,不过没关系,反正这个优化也不是强制的。

       但是,如果使用 public 继承,类型兼容原则会导致 tuple 是 tuple 的子类,那么就可以当父类去用。这将引发大坑,比如接收二元组参数的函数接收到的居然是一个三元组。这种低质量的库在业务代码里是不可用的。

       总结一下,protected private 继承能暴露问题,避免不当使用时的隐患;空基类优化的需求使得必须用继承实现,而 public 继承会产生奇怪的语义,这决定了 protected private 继承在模板库中很有用。

       业务代码在使用继承时,往往只是为了利用多态性,而模板库在设计时会考虑到所有场景,所以 protected private 继承在模板库中用得多,在业务代码中用得少。

       最后,private protected 继承虽然在实践中用得相对较少,但他们绝不是像 vector, auto_ptr 这样的实在是非常拉垮的设计。他们在模板编程中十分有用!