# 基本工具

# SSH

创建公私钥

ssh-keygen

将本地公钥和私钥上传到服务器:

# 方法 1
ssh-copy-id -i ~/.ssh/id_rsa.pub <server>
# 方法 2
cat ~/.ssh/id_rsa.pub | ssh <server> 'cat >> ~/.ssh/authorized_keys'

# RSYNC

能够同步更新两处计算机的文件与目录,并适当利用差分编码以减少数据传输量。——Wikipedia

基本用法:

# rsync [option] source destination 同步的策略是将目标地址中没有但源地址有的文件同步
rsync A B
rsync -r A B  # 递归同步,如果 A 是个文件夹就会递归同步 A 下的所有内容
rsync -a A B  # 递归同步的同时同步元信息,比如文件权限
rsync --delete A B  # 在同步过程中删除只存在于 B 而不存在于 A 的内容(相当于让目标 B 和源 A 保持一致)
# A 和 B 都可以是远程的地址
# example: guojunyi@dl1:/home/guojunyi/B

# 开发工具

# SISD vs SIMD vs SIMT

  • SISD:单个指令操作单个数据。exp:a [i] + b [i]
  • SIMD:单个指令操作多个数据。exp: a [i-i+4] + b [i-i+4]
  • SIMT:单个指令调用多个线程。单个指令会调用不同的硬件进行计算。

# SIMD: AVX/SSE

高级向量扩展指令集(Advanced Vector Extensions, AVX)是 x86 架构微处理器中的指令集。——Wikipedia

# 一个例子

// SISD
vectorAdd(float* a, float* b, float* c)
{
    for (int i = 0; i < 8; i++)
    {
        c[i] = a[i] + b[i];
    }
}

float 4 字节占用 32bit,长度为 8 的 float 数组一共是 256bit。

// SIMD
__m256 vectorAdd(__m256 a, __m256 b, __m256 c)
{
    return _mm256_add_ps(a, b);
}

在 AVX 指令集中,使用上述指令可以一次性返回 256bit 数据的加和。但代价是需要先将原有的存放 8 个 float 数据的数组转化成对应的 256bit 向量。

# 优点和缺点

  • 更高速的计算方法
  • 更高的开发复杂度
  • 更复杂的 CPU 架构

# SIMT: CUDA/ROCM

CUDA (Compute Unified Device Architecture, 统一计算架构) 是由 NVIDIA 推出的一种集成技术,是其对 GPGPU (General Propose Graphic Processing Unit,通用目的的图形处理器) 的正式名称。
ROCm 是 AMD (Advanced Micro Devic) 的软件栈,用于 GPU 编程。——Wikipedia

// CUDA
__global__ void addVector(float* a, float* b, float* c)
{
    int tid = blockIdx.x;
    if (tid < 8)
        c[tid] = a[tid] + b[tid];
}

上述程序会启动多个并行的流程同时操作。每个流程中拿到的 tid 是不同的。

# SIMT:OPENCL

OpenCL (Open Computing Language,开放计算语言) 是一个为异构平台编写程序的框架,此异构平台可由 CPU、GPU、DSP、FPGA 或其他类型的处理器与硬体加速器构成。——Wikipedia

__kernel void vector_add(float* a, global const float* b, global float* c)
{
    int gid = get_global_id(0);
    if (gid < 8)
        c[tid] = a[tid] + b[tid];
}

# MULTI-THREAD: OPENMP

OpenMP 是一套支持跨平台共享内存方式的多线程并发的编程 API。——Wikipedia

为了利用多线程,我们可以使用一些更底层的库进行开发(如 Linux 下可以使用 pthread),OpenMP 提供了一种更统一、简洁且跨平台的方式进行开发。

// OpenMP
vectorAdd(float* a, float* b, float* c)
{
    # pragma omp for
    for (int i = 0; i < 8; i++)
    {
        c[i] = a[i] + b[i];
    }
}

# 性能调优

# CPU

// CPP20
if (n > 0) [[likely]]
{
    // ...
}
else [[unlikely]]
{
    // ...
}

# GPU

一些补充:

  • 线程束分化
  • GPU 内存模型:GPU 有多种不同的内存(global memory, constant memory, texture memory),如果访问的数据在多个不同内存中,一次性无法读完所有需要的数据,这会极大浪费 GPU 的带宽。在单个线程束访存时(假设每个线程访问不同的数组),相比于传统的存储方式(每个数组拥有连续的存储区域), a[0]b[0]c[0]d[0] 这样的存储方式对 GPU 的执行会更有效率。
  • 并发:首先将数据拷贝到 GPU 中,随后启动 GPU 上的进程执行内容,最后再将数据拷贝回 CPU(从 GPU 的片上内存拷贝回主存),如果完整地经历这个步骤实际上十分低效。可以将每一个步骤分成三份,拷贝完一部分数据就进行处理,同时进行下一部分数据的拷贝(流水线化),这样可以提高效率。

# RDMA

在数据中心领域,远程直接内存访问(Remote Direct Memory Access, RDMA)是一种绕过远程主机操作系统内核访问其内存中数据的技术,由于不经过操作系统,不仅节省了大量 CPU 资源,同时也提高了系统吞吐量、降低了系统网络通信延迟,尤其适合在大规模并行计算机集群中有广泛应用。——Wikipedia

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

John G 微信支付

微信支付

John G 支付宝

支付宝