如果测量的事件超过一微妙,可以使用软件的系统定时器,在 Linux 系统上,可以通过clock_gettime系统调用访问系统定时器。在 C++ 中访问系统定时器的标准方式是使用std::chrono

1
2
3
4
5
6
7
8
9
10
11
12
#include <cstdint>
#include <chrono>

// 返回以纳秒为单位的经过时间
uint64_t timeWithChrono() {
using namespace std::chrono;
auto start = steady_clock::now();
// 运行一些代码
auto end = steady_clock::now();
uint64_t delta = duration_cast<nanoseconds>(end - start).count();
return delta;
}

如果测量的事件是纳秒级到一分钟,可以读取CNTVCT_EL0寄存器,这是一种硬件定时器,被实现为一个硬件寄存器。时间戳计数器是单调的,并且速率恒定,即它不受频率变化的影响。每个 CPU 都有自己的时间戳计数器,它就是所经过的参考周期数。可以认为是 ARM 上 rdtsc 的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static inline uint64_t
arm64_cntvct(void)
{
uint64_t tsc;
asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
return tsc;
}

static inline uint64_t
arm64_cntfrq(void)
{
uint64_t freq;
asm volatile("mrs %0, cntfrq_el0" : "=r" (freq));
return freq;
}

static inline uint64_t
rdtsc(void)
{
return arm64_cntvct();
}

注:代码来源https://blog.csdn.net/z20230508/article/details/136741584

但是读 CNTVCT_EL0 的方法也不能精确到 cpu cycle,因为其频率通常比 cpu 频率低很多,譬如在天玑9400的机器(我用的是 vivo 的 X200 Pro)上,TSC 的频率仅为13MHZ,但是 CPU 频率都是 GHZ 为单位的。

我查阅资料,看到可以通过读取 PMCCNTR_EL0 寄存器来达到 cpu cycle 精度定时,但是这个寄存器默认用户态不可访问,需要内核打开,在 6.6 内核上,按照https://ilinuxkernel.com/?p=1755目前我没有打开成功。而且在手机上大小核并且频率还会动态变化,各个cpu的频率不一样会导致计数不准确,所以用这个方法需要将测试用例绑核并且固定核的频率。

解压

1
2
3
4
5
mkdir rootfs
mv rootfs.cpio ./rootfs/rootfs.cpio.gz
cd rootfs
gunzip rootfs.cpio.gz
cpio -idmv < rootfs.cpio

重新打包

1
2
cd rootfs 
find . | cpio -o --format=newc > ../rootfs.cpio

文章翻译自 http://landley.net/writing/memory-faq.txt ,已有部分译文在内存那些事儿(上)

什么是文件映射?

文件映射是文件内容在内存中的镜像。映射的管理数据有:

  • 该映射对应哪个文件
  • 从文件哪个位置开始映射的
  • 映射页的读/写/执行权限

当文件映射通过 page fault 分配新的物理页时,页面内容是通过读取磁盘中对应位置的内容来初始化的。内核中会缓存着一些磁盘的文件页,这个缓存称为 page cache。新分配的物理页通常是和 page cache 共享的,在文件被读进内存的时候,其内容通常就会被内核缓存起来,这些缓存的页面可与进程共享,以降低系统内存的使用量。

对使用 MAP_SHARED 标志创建的文件映射进行写操作时会更新 page cache 内容,使更新后的文件内容立即对使用该文件的其他进程可见,并且最终 page cache 会被刷新到磁盘,更新磁盘上文件的内容。

对使用 MAP_PRIVATE 标志创建的文件映射进行写操作时会执行写时复制,即分配一个新的本地页面副本来存储更改。这些更改对其他进程不可见,并且不会更新到磁盘上。

请注意,这意味着对 MAP_SHARED 页面的写操作不会分配额外的物理页面(页面已经通过读取进入了 page cache,如果物理页面在其他地方需要(译注:如内存不足),数据可以刷新回磁盘),但对 MAP_PRIVATE 页面的写操作就需要分配额外的物理页面(page cache 中的副本与程序需要的本地副本会不一致,因此需要两个页面来存储它们,并且将 page cache 中的副本刷新回磁盘不会释放更改内容的本地副本)。

阅读全文 »

buddy 分配器是 linux 内核中的经典分配器,学习 linux 内存管理的肯定绕不开它,甚至学习其他 linux 子系统的也会学学它,因为实在是太经典了。作者想从根本理解 buddy 分配器的原理,所以找来了 buddy 分配器最初提出的文章:A fast storage allocator 和 knuth 在The Art of Computer Programming, Fundamental Algorithms, Volume 1. 中深入分析 buddy 分配器一节(2.5 节)阅读,下面内容算是这两处内容的笔记了。

阅读全文 »

设备:树莓派 3b+、sdcard、读卡器、usb 转串口线

基本信息:无显示器、串口连接

本文持续更新

连接 wifi

sudo raspi-config

image-20231110231257116

image-20230826171450641

接着输入 wifi 名字和密码

阅读全文 »

设备:树莓派 3b+、sdcard、读卡器、usb 转串口线

环境:Ubuntu 20.04.6 LTS

树莓派镜像

我选择最新的 arm64 镜像,可以从 https://downloads.raspberrypi.org/raspios_arm64/images/ 查找下载,写这篇文章时最新的是 https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2023-05-03/2023-05-03-raspios-bullseye-arm64.img.xz,下载之后得到 2023-05-03-raspios-bullseye-arm64.img.xz 文件:

阅读全文 »

环境:ubuntu 20.04

准备工作

1
2
$ sudo apt-get install qemu qemu-system-arm gcc-aarch64-linux-gnu gdb-multiarch
$ sudo apt install flex bison libssl-dev

编译内核

下载 Linux 源码:kernel 各版本下载

下载完内核之后,如放在 ~/linux-5.10 目录下:

1
2
3
4
$ cd linux-5.10
$ mkdir out
$ make O=out ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
$ make O=out ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j8
阅读全文 »
0%