最近碰到好几次与DNS相关的场景,一个是当我们给网络设备配置一个IP地址后,抓包看可以看到进行了多播初始化过程,如果要ping其他主机,还会进行ARP、ICMP报文交互,但是在ARP之前还会看到一些MDNS报文,另一个在给博客配置域名时需要设置域名记录为CNAME类型,在此对DNS、MDNS进行一个学习和总结。

阅读全文 »

智能指针是C++11引入的特性,用于解决忘记delete而出现的内存泄露问题,是行为类似指针的类对象。

4种智能指针

C++有4种智能指针:auto_ptr、shared_ptr、unique_ptr、weak_ptr,其中auto_ptr在C++11中被弃用,weak_ptr需要配合shared_ptr使用,并不能算是真正的智能指针。

unique_ptr:代替了原有的auto_ptr,它们都采用所有权模式,实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。

shared_ptr:采用引用计数实现共享式拥有,多个共享指针可以指向同一个对象,该对象和其他相关资源会在最后一个引用被销毁的时候释放。

weak_ptr:只能和shared_ptr搭配使用,用来解决循环引用问题。

实现原理

智能指针将常规指针进行包装,当智能指针对象过期时,让它的析构函数对常规指针进行内存释放。

移动语义

左值和右值

一个表达式的计算结果要么是左值,要么是右值。左值是在内存中持久存储的,位于内存具体的某个地址上;右值只是一个临时存储的值。

  • 如果一个表达式仅由一个变量名组成,那么它一定是左值。
  • 函数表达式中的参数:在调用函数时,参数是存在寄存器里的,所以是右值
  • 函数返回值:如果返回的是引用,那么是左值,其他情况返回的都是

移动构造

std::move函数

这个函数并没有移动任何东西!仅仅是做了一个类型转换,你甚至可以像下面这样简单地实现一个move函数:

1
2
template <typename T>
T&& move(T &x) noexcept { return static_cast<T&&>(x); }

网络拥塞的原因与危害

网络拥塞(congestion control)是由发送方的发送速率(transmission rate)过高引起的,会导致网络资源没有被充分利用,影响带宽和延时性能

我们假设有这样一种场景:有两台主机A和B,它们分别与目标主机创建了TCP连接,A和B的传输路径上共享了一个路由器,A和B都以v bytes/s的速率发数据,数据包到达该路由器后,通过同一个链路(outgoing link)转发到目标主机,该链路的最大容量为R。路由器的链路以最大容量在传输数据时,如果路由器还收到新的包,会将其缓存在路由器中。

阅读全文 »

DMA是一种硬件机制,用于支持在外设主机内存之间直接进行数据读写,而无需CPU的参与。由于CPU全程没有参与,因此硬件需要通过中断信号通知CPU DMA的完成状态。当然CPU也可以选择轮询寄存器的方式获取DMA的完成状态,但这就有点两边都不讨好了,会让CPU和DMA控制器都处于繁忙状态,在重数据轻计算场景下可能会看到这种用法。

阅读全文 »

创建一个仓库

  1. 在github上创建一个远程仓库

  2. 在本地创建一个本地仓库,创建README.md,push -u origin main到远程仓库

阅读全文 »

NCCL Makefilemake build生成目标动态链接库、静态链接库以及需要安装到系统目录中的头文件。

include xxx.mk

在Makefile的一开始使用include指令包含了两个.mk文件

1
2
include ../makefiles/common.mk
include ../makefiles/version.mk

在 Makefile 中,include 是一个指令,用于包含其他 Makefile 或规则文件。当使用 include 指令时,Makefile 会读取并解析指定的文件,并将其内容合并到当前的 Makefile 中,这样可以将多个 Makefile 或规则文件组织在一起,使得整个构建过程更模块化和可维护。

阅读全文 »

在实现一个系统之后,我们总希望能够优化它的性能,系统性能优化通常可以分为两个阶段:性能分析和性能优化。其中,性能分析的目的是查找性能瓶颈、热点代码,分析引发性能问题的原因。perf这个性能分析工具在分析网卡延时性能时非常方便,在此对perf进行学习与总结。

perf简介

perf是Linux的一款性能分析工具,能够进行函数级和指令级的热点查找,可以用来分析程序中热点函数的CPU占用率,从而定位性能瓶颈。

就函数级分析而言,perf的基本工作方式是每隔一段固定时间,在CPU上产生一个中断,查看当前CPU上运行的是哪个进程、哪个函数,然后给对应的进程和函数的计数加一,这样就知道CPU有多少时间在某个进程或某个函数上,perf的缺省采样频率是4000/s。

阅读全文 »

有时候我们希望在现有源码基础上添加一些新特性,在此记录一下怎么使用rpm源码安装软件包。

通常拿到的rpm源码文件是以.src.rpm结尾的,首先我们需要使用以下命令得到源码文件:

1
rpm2cpio <xxx.src.rpm> | cpio div
阅读全文 »

事情是这样的,我使用别人为我提供的一个软件包,这个软件包依赖于现有内核源码树的模块A,并提供了内核驱动模块B,而我的上层应用程序依赖于这个软件包。而我想在内核模块A和B中添加一些打印信息,重新编译并加载到系统中,覆盖原有的模块。但是当我在rpmbuild目录下执行rpmbuild -ba module_name.spec命令的时候,终端提示我修改的行数超出了限制,并且提示了一些与patch相关的错误信息。

阅读全文 »

Vector addtion

向量加法C = A + B是最简单的数据并行计算,相当于入门级的“Hello world”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__global__ void vecAddKernel(float* A, float* B, float* C, int n) { 
int i= blockDim.x*blockIdx.x + threadIdx.x;
if(i<n) C[i] = A[i] + B[i];
}

void vecAdd(float *A, float *B, float *C, int n) {
int size = n * sizeof(float);
flost *d_A, *d_B, *d_C;

cudaMalloc((void**)&d_A, size);
cudaMemcpy(d_A, A, size, cudaMemcpyHostToDevice);
cudaMalloc((void**)&d_B, size);
cudaMemcpy(d_B, B, size, cudaMemcpyHostToDevice);

cudaMalloc((void**) &d_C, size);
vecAddKernel<<<ceil(n/256.0, 256)>>>(d_A, d_B, d_C, n);

cudaMemcpy(C, d_C, size, cudaMemcpyDeviceToHost);

cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
}

CUDA版本的vertor addition分为以下几个步骤:

  1. 在程序的一开始需要包含cuda.h头文件,它包含了CUDA API函数和内建变量
  2. 申请GPU内存,将主机内存中的向量A、B拷贝到设备内存中
  3. 在GPU上并行执行向量加法核函数
  4. 将结果拷贝回主机内存,并释放设备内存

GPU有自己的DRAM,称为全局内存(global memory),上述的第2步和第4步在主机内存和设备全局内存中来回传输数据。cudaMalloc可以申请设备全局内存,使用完后用cudaFree释放设备内存。cudaMemcpy可以在主机内存和设备内存之间传输数据。

在第3步中,所有GPU上的线程执行相同的程序,称为单程序多数据(SPMD)并行编程。

  • 当主机代码启动核函数,CUDA运行时系统创建一个包含多个线程的网格(grid),grid由线程块(block)组成,每个block最多包含1024个线程。由于硬件特性,线程块中每个维度的线程个数应该是32的倍数。?
  • 内建变量threadID、blockID存放在设备寄存器中,每个线程都有它们自己的寄存器存放这些值。
  • 核函数中的i是局部变量,这是每个线程私有的变量。
  • 线程块之间的执行顺序是随机的
阅读全文 »
0%