CXL 学习笔记

背景 前段时间学习了 PCIe,趁此机会,进一步学习一下密切相关的 CXL。 CXL 的标准是公开下载的:https://www.computeexpresslink.org/download-the-specification,我目前参考的是 2022 年 8 月 1 日的 CXL 3.0 版本。 CXL 设备类型 CXL 对 PCIe 的重要的扩展,一是在于让设备可以和 CPU 实现缓存一致性(CXL.cache),二是可以做远程的内存(CXL.mem)。 具体下来,CXL 标准主要定义了三类设备: CXL Type 1: 设备带有与 CPU 一致的缓存,实现 CXL.io 和 CXL.cache CXL Type 2: 设备带有自己的内存和与 CPU 一致的缓存,实现 CXL.io,CXL.cache 和 CXL.mem CXL Type 3: 设备带有自己的内存,实现 CXL.io 和 CXL.mem CXL 传输层 CXL.io CXL.io 基本上就是 PCIe 协议: CXL.io provides a non-coherent load/store interface for I/O devices. Figure 3-1 shows where the CXL.

Read More

PCIe 学习笔记

背景 最近在知乎上看到 LogicJitterGibbs 的 资料整理:可以学习 1W 小时的 PCIe,我跟着资料学习了一下,然后在这里记录一些我学习 PCIe 的笔记。 下面的图片主要来自 PCIe 3.0 标准以及 MindShare 的 PCIe 3.0 书本。 分层 PCIe 定义了三个层:Transaction Layer,Data Link Layer,Physical Layer,和 TCP/IP 四层模型很像。PCIe 也是基于 Packet 传输的。 Transaction Layer Transaction Layer 的核心是 Transaction Layer Packet(TLP)。TLP 格式: 即可选的若干个 Prefix,一个 Header,可选的 Data Payload,可选的 Digest。 Prefix 和 Header 开头的一个字节是 Fmt[2:0] 和 Type[4:0] 字段。Fmt 决定了 header 的长度,有无数据,或者这是一个 Prefix。 它支持几类 Packet: Memory: MMIO Read Request(MRd)/Completion(CplD) Write Request(MWr): 注意只有 Request,没有 Completion AtomicOp Request(FetchAdd/Swap/CAS)/Completion(CplD) Locked Memory Read(MRdLk)/Completion(CplDLk): Legacy IO: Legacy Read Request(IORd)/Completion(CplD) Write Request(IOWr)/Completion(Cpl) Configuration: 访问配置空间 Read Request(CfgRd0/CfgRd1)/Completion(CplD) Write Request(CfgWr0/CfgWr1)/Completion(Cpl) Message: 传输 event Request(Msg/MsgD) 括号里的是 TLP Type,对应了它 Fmt 和 Type 字段的取值。如果 Completion 失败了,原来应该是 CplD/CplDLk 的 Completion 会变成不带数据的 Cpl/CplLk。

Read More

在 ppc64le Linux 上运行 Nix

背景 之前尝试过在 ppc64le 的机器上运行 Nix,当时的尝试是把代码克隆下来编译,我还写了一个 Docker 脚本: # Based on https://github.com/NixOS/nix/issues/6048 # Build nixos/nix from source FROM ubuntu:20.04 RUN sed -i 's/ports.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list RUN apt-get update RUN DEBIAN_FRONTEND=noninteractive apt-get install -y \ autoconf-archive autoconf automake pkg-config build-essential git gcc g++ jq libboost-all-dev libcrypto++-dev libcurl4-openssl-dev \ libssh-dev libarchive-dev libsqlite3-dev libbz2-dev wget liblzma-dev libbrotli-dev libseccomp-dev bison flex libsodium-dev libgc-dev \ libgtest-dev libgmock-dev cmake unzip # Install editline - newer version required WORKDIR /root RUN wget https://github.

Read More

在 GNURadio Companion 中收听 FM 广播

背景 以前买过 RTL-SDR,用 Gqrx 做过收音机,当时还给 Homebrew 尝试提交过几个 sdr 相关的 pr,但是限于知识的缺乏,后来就没有再继续尝试了。 前两天,@OceanS2000 讲了一次 Tunight: 高级收音机使用入门,又勾起了我的兴趣,所以我来尝试一下在 GNURadio Companion 中收听 FM 广播电台。 我没有上过无线电相关课程,所以下面有一些内容可能不正确或者不准确。 安装 我的实验环境是 NixOS,所以是用下面的配置来安装 gnuradio 的: # SDR # https://github.com/NixOS/nixpkgs/pull/170253 (gnuradio.override { extraMakeWrapperArgs = [ "--prefix" "SOAPY_SDR_PLUGIN_PATH" ":" (soapyrtlsdr + "/lib/SoapySDR/modules0.8/") ]; }) soapysdr-with-plugins 其中 gnuradio 的 override 是为了让它可以找到 soapyrtlsdr 的库,否则它会找不到设备;soapysdr-with-plugins 是为了提供 SoapySDRUtil 命令,来确认它可以找到 RTL-SDR 设备: $ SoapySDRUtil --probe ---------------------------------------------------- -- Device identification ---------------------------------------------------- driver=RTLSDR hardware=R820T origin=https://github.com/pothosware/SoapyRTLSDR rtl=0 ---------------------------------------------------- -- Peripheral summary ---------------------------------------------------- Channels: 1 Rx, 0 Tx Timestamps: NO Other Settings: * Direct Sampling - RTL-SDR Direct Sampling Mode [key=direct_samp, default=0, type=string, options=(0, 1, 2)] * Offset Tune - RTL-SDR Offset Tuning Mode [key=offset_tune, default=false, type=bool] * I/Q Swap - RTL-SDR I/Q Swap Mode [key=iq_swap, default=false, type=bool] * Digital AGC - RTL-SDR digital AGC Mode [key=digital_agc, default=false, type=bool] ---------------------------------------------------- -- RX Channel 0 ---------------------------------------------------- Full-duplex: NO Supports AGC: YES Stream formats: CS8, CS16, CF32 Native format: CS8 [full-scale=128] Stream args: * Buffer Size - Number of bytes per buffer, multiples of 512 only.

Read More

ESXi 配置 LACP 链路聚合

背景 给 ESXi 接了两路 10Gbps 的以太网,需要用 LACP 来聚合。ESXi 自己不能配置 LACP,需要配合 vCenter Server 的 Distributed Switch 来配置。 步骤 参考文档:LACP Support on a vSphere Distributed Switch 第一步是创建一个 Distributed Switch。找到 Cluster,点击 ACTIONS,在 Distributed Switch 里面选择 New Distributed Switch。里面的选项都可以用默认的,按需修改。 第二步,找到刚刚创建的 Distributed Switch,点击 Configure,在 Settings 下点击 LACP,点击 NEW,选项可以用默认的,按需修改。 第三步,找到 Distributed Switch,点击 ACTIONS,点击 Add and Manage Hosts,找到要配置的主机,在 Manage physical adapters 这一步,找到要加入到链路聚合的 vmnic,每个要聚合的 vmnic 都在右边的 Assign uplink 处选择刚刚创建的 LAG 下的 Uplink,按顺序,一一对应。其余选项可以使用默认的。这一步配置好以后,在交换机上应该就可以看到 LACP 正常运转。 第四步,如果要把虚拟机连到链路聚合的网络上,找到虚拟机,点击 ACTIONS,点击 Edit Settings,新建一个网卡,Network adapter 处选择刚刚创建的 Distributed Port Group。这一步是让虚拟机多一个网卡,可以连接到 Distributed Switch 上。这一步配置好以后,虚拟机就可以收到来自其他物理机的网络流量,但是发送不出去。

Read More

Buildroot 2020.08 的 Fakeroot 版本过旧导致的兼容性问题

背景 最近在给之前的 Buildroot 2020.09 增加新的软件包,结果编译的时候报错: mknod: ....../dev/console: Operation not permitted 还有一个背景是前段时间把系统升级到了 Ubuntu 22.04 LTS。 研究 跑的时候没有用 root,而是用 fakeroot 跑的,按理说在 fakeroot 里跑 mknod 是不会报错的,我直接运行系统的 fakeroot 是正常的: fakeroot -- mknod -m 0622 test c 5 1 此时 fakeroot 会生成一个空文件,这是正常现象。那么为什么 Buildroot 里跑就不对了呢? 我仔细观察了一下,buildroot 用的是自己编译的 fakeroot,版本是 1.20.2,用这个版本跑就会报错: $ ./output/host/bin/fakeroot -- mknod -m 0622 test c 5 1 mknod: test: Operation not permitted 果然就出问题了。 用 strace 观察下区别: $ fakeroot -- strace mknod -m 0622 test c 5 1 newfstatat(AT_FDCWD, "test", {st_mode=S_IFREG|0644, st_size=0, .

Read More

从 TeX 到 PDF 的过程

背景 今天跑 xdvipdfmx 的时候出现了报错,忽然想研究一下,DVI 格式是什么,TeX 是如何一步步变成 PDF 的。 流程 实际上从 TeX 到 PDF 有不同的工具,其中可能经历了不同的转化过程。 我们今天来看一种比较原始的转换方式:从 TeX 到 DVI,从 DVI 到 PS,再 PS 到 PDF,主要目的是看看这些格式内部都是什么样子的。 从 TeX 到 DVI 举一个很小的例子,例如 test.tex 有如下的内容: Hello, world! \bye 在命令行中运行 tex test.tex,可以看到它生成了 test.dvi 文件: $ tex test.tex (test.tex [1] ) Output written on test.dvi (1 page, 228 bytes). Transcript written on test.log. 那么 DVI 就是 TeX 引擎输出的默认格式了。我们可以用 dviinfox 和 dviasm 工具来看它的一些信息: $ dviinfox test.dvi test.dvi: DVI format 2; 1 page Magnification: 1000/1000 Size unit: 1000x25400000/(1000x473628672)dum = 0.

Read More

用 Nix 编译 Rust 项目

背景 Rust 项目一般是用 Cargo 管理,但是它的缺点是每个项目都要重新编译一次所有依赖,硬盘空间占用较大,不能跨项目共享编译缓存。调研了一下,有若干基于 Nix 的 Rust 构建工具: cargo2nix: https://github.com/cargo2nix/cargo2nix carnix: 不再更新 crane: https://github.com/ipetkov/crane crate2nix: https://github.com/kolloch/crate2nix naersk: https://github.com/nix-community/naersk nocargo: https://github.com/oxalica/nocargo 下面我分别来尝试一下这几个工具的使用。 下面出现的一些命令参考了对应项目的文档。 cargo2nix 卖点 cargo2nix 的 README 提到了它的卖点: Development Shell - knowing all the dependencies means easy creation of complete shells. Run nix develop or direnv allow in this repo and see! Caching - CI & CD pipelines move faster when purity guarantees allow skipping more work! Reproducibility - Pure builds.

Read More

invalid date 报错与时区的关系

背景 最近在验题的时候,@HarryChen 发现了一个现象: $ date -d "1919-04-13" date: invalid date ‘1919-04-13’ $ TZ=UTC date -d "1919-04-13" Sun Apr 13 00:00:00 UTC 1919 也就是说,这个现象与时区有关,那么为啥 1919-04-13 是一个不合法的日期呢? 时区 实际上,对于某一个时区来说,有的时间是不存在的,最常见的就是夏令时。在 Timezone DB 里可以看到,恰好在 1919 年 4 月 13 日发生了一次 UTC+8 到 UTC+9 的变化,因此零点变成了一点,就变成了不合法的日期。 这个数据,实际上保存在 tzdata 中,可以用 zdump 工具查看: $ tzdata -v Asia/Shanghai Asia/Shanghai Fri Dec 13 20:45:52 1901 UTC = Sat Dec 14 04:45:52 1901 CST isdst=0 Asia/Shanghai Sat Dec 14 20:45:52 1901 UTC = Sun Dec 15 04:45:52 1901 CST isdst=0 Asia/Shanghai Sat Apr 12 15:59:59 1919 UTC = Sat Apr 12 23:59:59 1919 CST isdst=0 Asia/Shanghai Sat Apr 12 16:00:00 1919 UTC = Sun Apr 13 01:00:00 1919 CDT isdst=1 Asia/Shanghai Tue Sep 30 14:59:59 1919 UTC = Tue Sep 30 23:59:59 1919 CDT isdst=1 Asia/Shanghai Tue Sep 30 15:00:00 1919 UTC = Tue Sep 30 23:00:00 1919 CST isdst=0 Asia/Shanghai Fri May 31 15:59:59 1940 UTC = Fri May 31 23:59:59 1940 CST isdst=0 Asia/Shanghai Fri May 31 16:00:00 1940 UTC = Sat Jun 1 01:00:00 1940 CDT isdst=1 Asia/Shanghai Sat Oct 12 14:59:59 1940 UTC = Sat Oct 12 23:59:59 1940 CDT isdst=1 Asia/Shanghai Sat Oct 12 15:00:00 1940 UTC = Sat Oct 12 23:00:00 1940 CST isdst=0 Asia/Shanghai Fri Mar 14 15:59:59 1941 UTC = Fri Mar 14 23:59:59 1941 CST isdst=0 Asia/Shanghai Fri Mar 14 16:00:00 1941 UTC = Sat Mar 15 01:00:00 1941 CDT isdst=1 Asia/Shanghai Sat Nov 1 14:59:59 1941 UTC = Sat Nov 1 23:59:59 1941 CDT isdst=1 Asia/Shanghai Sat Nov 1 15:00:00 1941 UTC = Sat Nov 1 23:00:00 1941 CST isdst=0 Asia/Shanghai Fri Jan 30 15:59:59 1942 UTC = Fri Jan 30 23:59:59 1942 CST isdst=0 Asia/Shanghai Fri Jan 30 16:00:00 1942 UTC = Sat Jan 31 01:00:00 1942 CDT isdst=1 Asia/Shanghai Sat Sep 1 14:59:59 1945 UTC = Sat Sep 1 23:59:59 1945 CDT isdst=1 Asia/Shanghai Sat Sep 1 15:00:00 1945 UTC = Sat Sep 1 23:00:00 1945 CST isdst=0 Asia/Shanghai Tue May 14 15:59:59 1946 UTC = Tue May 14 23:59:59 1946 CST isdst=0 Asia/Shanghai Tue May 14 16:00:00 1946 UTC = Wed May 15 01:00:00 1946 CDT isdst=1 Asia/Shanghai Mon Sep 30 14:59:59 1946 UTC = Mon Sep 30 23:59:59 1946 CDT isdst=1 Asia/Shanghai Mon Sep 30 15:00:00 1946 UTC = Mon Sep 30 23:00:00 1946 CST isdst=0 Asia/Shanghai Mon Apr 14 15:59:59 1947 UTC = Mon Apr 14 23:59:59 1947 CST isdst=0 Asia/Shanghai Mon Apr 14 16:00:00 1947 UTC = Tue Apr 15 01:00:00 1947 CDT isdst=1 Asia/Shanghai Fri Oct 31 14:59:59 1947 UTC = Fri Oct 31 23:59:59 1947 CDT isdst=1 Asia/Shanghai Fri Oct 31 15:00:00 1947 UTC = Fri Oct 31 23:00:00 1947 CST isdst=0 Asia/Shanghai Fri Apr 30 15:59:59 1948 UTC = Fri Apr 30 23:59:59 1948 CST isdst=0 Asia/Shanghai Fri Apr 30 16:00:00 1948 UTC = Sat May 1 01:00:00 1948 CDT isdst=1 Asia/Shanghai Thu Sep 30 14:59:59 1948 UTC = Thu Sep 30 23:59:59 1948 CDT isdst=1 Asia/Shanghai Thu Sep 30 15:00:00 1948 UTC = Thu Sep 30 23:00:00 1948 CST isdst=0 Asia/Shanghai Sat Apr 30 15:59:59 1949 UTC = Sat Apr 30 23:59:59 1949 CST isdst=0 Asia/Shanghai Sat Apr 30 16:00:00 1949 UTC = Sun May 1 01:00:00 1949 CDT isdst=1 Asia/Shanghai Fri May 27 14:59:59 1949 UTC = Fri May 27 23:59:59 1949 CDT isdst=1 Asia/Shanghai Fri May 27 15:00:00 1949 UTC = Fri May 27 23:00:00 1949 CST isdst=0 Asia/Shanghai Sat May 3 17:59:59 1986 UTC = Sun May 4 01:59:59 1986 CST isdst=0 Asia/Shanghai Sat May 3 18:00:00 1986 UTC = Sun May 4 03:00:00 1986 CDT isdst=1 Asia/Shanghai Sat Sep 13 16:59:59 1986 UTC = Sun Sep 14 01:59:59 1986 CDT isdst=1 Asia/Shanghai Sat Sep 13 17:00:00 1986 UTC = Sun Sep 14 01:00:00 1986 CST isdst=0 Asia/Shanghai Sat Apr 11 17:59:59 1987 UTC = Sun Apr 12 01:59:59 1987 CST isdst=0 Asia/Shanghai Sat Apr 11 18:00:00 1987 UTC = Sun Apr 12 03:00:00 1987 CDT isdst=1 Asia/Shanghai Sat Sep 12 16:59:59 1987 UTC = Sun Sep 13 01:59:59 1987 CDT isdst=1 Asia/Shanghai Sat Sep 12 17:00:00 1987 UTC = Sun Sep 13 01:00:00 1987 CST isdst=0 Asia/Shanghai Sat Apr 16 17:59:59 1988 UTC = Sun Apr 17 01:59:59 1988 CST isdst=0 Asia/Shanghai Sat Apr 16 18:00:00 1988 UTC = Sun Apr 17 03:00:00 1988 CDT isdst=1 Asia/Shanghai Sat Sep 10 16:59:59 1988 UTC = Sun Sep 11 01:59:59 1988 CDT isdst=1 Asia/Shanghai Sat Sep 10 17:00:00 1988 UTC = Sun Sep 11 01:00:00 1988 CST isdst=0 Asia/Shanghai Sat Apr 15 17:59:59 1989 UTC = Sun Apr 16 01:59:59 1989 CST isdst=0 Asia/Shanghai Sat Apr 15 18:00:00 1989 UTC = Sun Apr 16 03:00:00 1989 CDT isdst=1 Asia/Shanghai Sat Sep 16 16:59:59 1989 UTC = Sun Sep 17 01:59:59 1989 CDT isdst=1 Asia/Shanghai Sat Sep 16 17:00:00 1989 UTC = Sun Sep 17 01:00:00 1989 CST isdst=0 Asia/Shanghai Sat Apr 14 17:59:59 1990 UTC = Sun Apr 15 01:59:59 1990 CST isdst=0 Asia/Shanghai Sat Apr 14 18:00:00 1990 UTC = Sun Apr 15 03:00:00 1990 CDT isdst=1 Asia/Shanghai Sat Sep 15 16:59:59 1990 UTC = Sun Sep 16 01:59:59 1990 CDT isdst=1 Asia/Shanghai Sat Sep 15 17:00:00 1990 UTC = Sun Sep 16 01:00:00 1990 CST isdst=0 Asia/Shanghai Sat Apr 13 17:59:59 1991 UTC = Sun Apr 14 01:59:59 1991 CST isdst=0 Asia/Shanghai Sat Apr 13 18:00:00 1991 UTC = Sun Apr 14 03:00:00 1991 CDT isdst=1 Asia/Shanghai Sat Sep 14 16:59:59 1991 UTC = Sun Sep 15 01:59:59 1991 CDT isdst=1 Asia/Shanghai Sat Sep 14 17:00:00 1991 UTC = Sun Sep 15 01:00:00 1991 CST isdst=0 Asia/Shanghai Mon Jan 18 03:14:07 2038 UTC = Mon Jan 18 11:14:07 2038 CST isdst=0 Asia/Shanghai Tue Jan 19 03:14:07 2038 UTC = Tue Jan 19 11:14:07 2038 CST isdst=0 可以看到,它列出来了历史上 Asia/Shanghai 时区的变化历史。具体的历史,可以查看 中国时区。

Read More

Ceph Cookbook

概念 OSD:负责操作硬盘的程序,一个硬盘一个 OSD MON:管理集群状态,比较重要,可以在多个节点上各跑一个 MGR:监测集群状态 RGW(optional):提供对象存储 API MDS(optional):提供 CephFS 使用 Ceph 做存储的方式: librados: 库 radosgw: 对象存储 HTTP API rbd: 块存储 cephfs: 文件系统 认证 Ceph 客户端认证需要用户名 + 密钥。默认情况下,用户名是 client.admin,密钥路径是 /etc/ceph/ceph.用户名.keyring。ceph --user abc 表示以用户 client.abc 的身份访问集群。 用户的权限是按照服务类型决定的。可以用 ceph auth ls 显示所有的用户以及权限: $ ceph auth ls osd.0 key: REDACTED caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * client.admin key: REDACTED caps: [mds] allow * caps: [mgr] allow * caps: [mon] allow * caps: [osd] allow * 可以看到,osd.

Read More