分类 technique 下的文章

legacy 体系:

SysVinit :
初始化脚本位于 /etc/init.d/,初始化脚本需要支持 start, stop, status 等命令
使用 service 命令运行初始化脚本
SysVinit 只启动一次,在之后不跟踪单个服务

新体系:

systemd 用于代替 SysVinit ,在初始化结束时, systemd 仍然作为守护进程运行。
使用 systemctlsystemd 交互,运行服务。

sudo systemctl enable [service] 开机启动服务
sudo systemctl disable [service] 不开机启动服务
sudo systemctl start [service]
sudo systemctl stop [service]
sudo systemctl restart [service]

systemd

systemd 是 boot 阶段第一个运行的 userspace 程序,在 kernel 初始化硬件后马上获得控制
systemd 通过 unit configuration file 管理资源
unit 包括 .service, .mount, .device 等文件
unit 保存在 /etc/systemd/system, /lib/systemd/system 等目录
/etc/systemd/system 优先级最高
通过 systemctl 与 systemd 交互
systemd 与 systemctl 之间通过 D-Bus 交互

journald 收集和管理 systemd 的 log
通过 journalctl 查询 log

发表于 sosp2003,经典系统工作 GFS

GFS 包括单个 master 节点。若干 chunkserver,被多个 client 同时访问

将文件分为大小固定的 chunk,每个 chunk 有一个全局唯一的 64位,由 master 在 chunk 创建时分配。
chunkserver 在本地以 linux 文件存储 chunk。每个 chunk 默认存储三个副本。

这是一个大坑,早晚要来填。。。

PCI BAR : base address register

之前做过劫持 cuda runtime 动态链接库的事情,在这里记录一下:

cudaError_t cudaMalloc ( void** devPtr, size_t size )
{
    if(!fp) {
        fp = fopen("/home/leenldk/sc/race/ASC2021-RACE/mem.out", "w");
    }
    cudaError_t (*lcudaMalloc) (void**, size_t) = (cudaError_t (*) (void**, size_t))dlsym(RTLD_NEXT, "cudaMalloc");
    cudaError_t ret = lcudaMalloc(devPtr, size);
    printf("cudaMalloc size : %#lx %#lx\n", size, (size_t)(*devPtr));
    fprintf(fp, "cudaMalloc size : %#lx %#lx\n", size, (size_t)(*devPtr));
    fflush(fp);
    return ret;
}

编译为动态链接库,使用 LD_PRELOAD 预加载


update 2022.11.2

C++ 动态库 加载,卸载 时调用函数 :

static void init() __attribute__((constructor));
void init() {}
static void fini() __attribute__((destructor));
void fini() {}

关于

论文: Linux Block IO: Introducing Multi-queue SSD Access on
Multi-core Systems

IO 块设备的吞吐发展迅速,2012 年 SSD 4K 随机读写速度达到 785K IOPS (是不是有点高?)
SSD 随机读写速度与顺序读写持平 (不太清楚)

传统 块设备 队列优点:

  • 统一接口

    缺点:

  • 效率低,导致一些应用跳过块数据管理层
  • 单队列,单锁,造成核间竞争
  • 只有一个核处理与块设备通信,其他核需要软中断与该核通信,并且对于不同 NUMA 下的内存不友好

解决方案:

两层队列
软件队列:每个 NUMA 上 或者每个核上 一个队列
硬件队列:每个块设备上 若干队列

tag : 指示 block IO 在 driver 提交队列中的位置,在 IO 完成时指示位置

代码

hctx : hardware context

每个 request_queue 包含若干 request,包含一个 percpu 的 blk_mq_ctx (queue_ctx) ,包含若干 blk_mq_hw_ctx

每个 request 有一个 blk_mq_ctx

每个 blk_mq_hw_ctx 中包含若干 blk_mq_ctx

目前维护了 hardcoding 的 per-cpu 软件队列

使用 sbitmap 维护 pending work

struct blk_mq_hw_ctx { // include/linux/blk-mq.h
    struct {
        spinlock_t        lock;
        struct list_head    dispatch;
        unsigned long        state;        /* BLK_MQ_S_* flags */
    }
    struct blk_mq_ctx    **ctxs;
    struct blk_mq_tags    *tags; // bitmap tag
}

struct blk_mq_ctx  { // block/blk-mq.h
    unsigned int        cpu; // ctx 对应的 cpu ?
}

struct blk_mq_tags { // block/blk-mq-tag.h
    struct request **rqs; // rqs[tag] 为下标 tag 对应的 request 
}

struct request_queue { //include/linux/blkdev.h
    struct percpu_ref q_usage_counter;
    struct blk_mq_ctx __percpu    *queue_ctx; // per cpu 的本队列 context
    struct blk_mq_hw_ctx    **queue_hw_ctx; // 所有 hardware dispatch queue context ? 
    unsigned int        *mq_map; // 每个 cpu 对应的 hw_ctx 编号 ?
}
struct request { //include/linux/blkdev.h
    struct request_queue *q;
}