neutron-dhcp-agent服务启动命令 /usr/bin/neutron-dhcp-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/dhcp_agent.ini 调用了neutron_service.Service.create()来创建的server。Service(n_rpc.Service)继承自neutron_lib.rpc,这次得去看看了,感觉应该也没啥看的。 Service(service.Service)继承自oslo_service.service.Service,里边只是个定义类接口,里边还有个线程池self.tg。 Service传入的manager为neutron.agent.dhcp.agent.DhcpAgentWithStateReport, 然后实例化,最后初始化父类。 DhcpAgentWithStateReport继承自DhcpAgent,再继承自manager.Manager, 然后继承自periodic_task.Per

Continue

供应商网络依赖的几个服务: neutron-server.service neutron-linuxbridge-agent.service neutron-dhcp-agent.service neutron-metadata-agent.service 自服务网络除了上边的几个服务外还依赖 neutron-l3-agent.service。 从这里也能看出,自服务网络支持三层模拟,这也是主要区别。自服务可以实现的功能就比较多,比如vxlan,FWaaS,LBaaS等。 先看看neutron-metadata-agent服务,这个服务主要功能是实例启动的时候为cloud-init获取metadata的时候转发用的。因为实例所在网络跟nova-api网络肯定不通的,所以需要一个中间转发,起这个作用的就是neutron-metadata-agent服务。看网上从实例到neutron-metadata-agent服务,中间还经过了haproxy,haproxy是l3-agent或者dhcp-agent启动的,这个也许也是分不同网络类型正好不同(但是我看官方安装文

Continue

linux内核使用许多likely和unlikely宏,这两个宏的内容为: #define likely(x) (__builtin_expect(!!(x), 1)) #define unlikely(x) (__builtin_expect(!!(x), 0)) 是用来告诉编译器,当前判断条件是否常用或者不常用。编译器根据提示,生成的二进制的代码流程会有相应改变,以达到让cpu尽可能的顺序执行的目的。gcc官方文档里说,使用-fprofile-arcs来进行实际的性能测试,说程序员对自己的程序的预测一般都是错误的。 然后我搜到是用gcov去做,使用了一下确实很直观。编译的时候,参数加上“-fprofile-arcs -ftest-coverage”。然后运行会生成 .gcda .gcno文件。用gcov source.c会生成相应代码的.gcov文件。vim编辑这些文件,就能看到源码形式的,每一行都执行了多少次。 这里说个疑问,前边说预测不准确,我当时看到那里还说真的是不准确。我之前就感觉明明会大概率走这个分支,然后加上提示后,速度却变慢了。但是当我用g

Continue

想到了三种方式,但是结果跟自己预想的不太一样,具体也没有细想。 第一种方式就是char*类型的strcmp比较,这种比较容易想到。但是效率中等。 第二种方式是使用类型__uint128_t,这个是gcc给出的类型,应该可移植性不太高,这种方式速度最快,char*用的时间是差不多1.5倍。 第三种方式是使用sse,并行试试,_mm_xor_si128和_mm_test_all_zeros进行比较,但是速度是最慢的,可能涉及类型的转换,看指令也非常的多。我还以为会是最快的。 除了第三种慢的意外,我第一种还对比了第一个char就不相等的情况,这种特殊情况我以为第一种会快,没想到还是慢,跟之前速度差不多。 我特意看了一下第二种方式的实现方式:通过两个xor,分别对比8字节,然后通过or操作把两个对比结果合并,然后通过test指令判断合并的结果是否为0,test指令会修改ZF标志位,最后通过jne判断ZF标志位进行跳转。

Continue

最近看c底层相关的指令,操作,编码,多线程,磁盘文件读写相关的看的比较多。不经理永远不知道这里边的东西有多少,还有很多不易理解的。由于时间仓猝,本来想好好整理一下,作为一个总结,但还是决定只是记一个笔记,而且内容来自搜索引擎,有一部分不是看的官方文档解释等,可能不正确,而且没有写全。以后无聊的时候想起来再搞吧(感觉用不到以后不会再搞了) 先说为什么写这个文章,我碰到一个问题。多线程读写文件,然后单线程读取,线上后读取结果不一致。之前有过分步的测试,是没有问题的。 然后我排查原因,先从读入手,发现数据有问题,然后转到看写。写先通过单独打印几条日志,和对写入的数据错误判断,在某个函数。这时候,我打开编译的debug模式,就是能打印更详细的日志,然后发现问题没了,数据正常了。然后我就玩起了编译参数。发现打印日志就没事,不打印就出问题了,然后我就想到是编译器给我优化过头了,那时候还是开始02的优化。因为那个函数不涉及多线程的操作。然后我去掉 -DNDEBUG参数,然后用assert()判断出是哪一行出了问题。然后实验了几个方法,发现都是可以的,于是网上搜索资料,大体比较了一下这集中

Continue

perf工具应该都听说过,我也试了一把,感觉很好很强大。 先使用sudo perf stat ./a.out命令,查看一下性能统计信息。结果展示为: Performance counter stats for './a.out': 2,740.62 msec task-clock # 3.903 CPUs utilized 39 context-switches # 0.014 K/sec 2 cpu-migrations # 0.001 K/sec 128,974 page-faults # 0.047 M/sec 10,394,863,898 cycles

Continue

Callgrind是valgrind的一个工具,能够分析程序运行效率,帮助找到程序瓶颈。 命令tool知道使用的valgrind的工具, valgrind --tool=callgrind ./a.out 运行完之后会生成一个callgrind.out.PID文件,然后执行下面命令进行分析 callgrind_annotate callgrind.out.PID 这个命令能够展示每个调用函数对应的执行指令的次数,展示已经排序,可以优先优化最顶部的函数。 cachegrind也是valgrind的一个工具,主要分析内存使用情况的,比如cpu cache的使用等。 简单使用命令: valgrind --tool=cachegrind ./a.out ==12810== ==12810== I refs: 13,413,053,205 ==12810== I1 misses: 3,851 ==12810== LLi misses: 3,552 ==12810== I1 miss ra

Continue

Valgrind可以模拟cpu执行你的程序,然后给出内存使用或者程序错误信息。之前只使用过gdb来调试程序逻辑错误,现在准备多看几个,包括性能方面的调试。 安装直接使用的apt源安装的,使用也比较简单。直接valgrind ./a.out允许程序,运行过程中会给出程序建议。 这个程序我有一个一百万长度的uint64的数组,提示了"Invalid write of size 8"的错误,Warning: client switching stacks? SP change: 0x6c55ef0 --> 0x64b4c60 to suppress, use: --max-stackframe=8000144 or greater 我搜了一下发现说是栈空间消耗太大,我改成calloc,两个错误提示都没了。 ==15130== HEAP SUMMARY: ==15130== in use at exit: 457,122,934 bytes in 4,659,095 blocks ==15130== total heap usage: 4,65

Continue

写个uint64_t的程序,涉及大小端的转换。 uint64_t x = 0x0123456789ABCDEF; On a 32-bit little-endian processor, it will appear in memory as EF CD AB 89 67 45 23 01 On a 64-bit little-endian processor, it will appear in memory as EF CD AB 89 67 45 23 01. On a 32-bit big-endian processor, it will appear in memory as 01 23 45 67 89 AB CD EF. On a 64-bit big-endian processor, it will appear in memory as 01 23 45 67 89 AB CD EF. 转换涉及#include <endian.h> uint64_t htobe64(uint64_t host_64bits); uint64_t htole6

Continue

零拷贝不是一个新技术了,之前一直接触不到这么底层的技术,最近看的比较多,所以从代码上研究了一下。 在应用程序做数据传输等操作涉及系统调用,而为了提高性能,就是从减少系统调用次数和减少内核空间和用户空间的数据拷贝次数入手的。 具体的我也没看代码,都是从网上总结学来的。 像mmap方式,是减少了内核空间和用户空间的数据拷贝,使用映射还是指针的能够共享内核空间。但涉及比如把一个文件内容通过网络发送的操作,还涉及内核空间的数据拷贝。 sendfile和splice就是解决内核空间的数据copy的,我看linux手册是page buffer指针的复制,所以没有做数据的copy。指针是通过pipe buffer存储的。 ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); ssize_t sendfile64(int out_fd, int in_fd, loff_t *offset, size_t count); 这俩的区别是sendfile64适合传送大文件,offset类型也决定了

Continue