近年,一些本为内核处理的任务,分别出现用户态的实现,有的是为了提升开发灵活性(FUSE、userfaultfd),有的则是为了提高与外设通信的性能(SPDK、DPDK)。本系列文章对我所了解到的用户空间实现的内核机制进行使用介绍或原理分析。第一篇文章介绍用户态的缺页处理 — userfaultfd机制,以后还可能根据我的学习进度介绍userfaultfd的内核实现原理、FUSE的使用和原理、SPDK等内容。文章若有错误,恳请指正。

userfaultfd 机制让在用户控制缺页处理提供可能,进程可以在用户空间为自己的程序定义page fault handler,增加了灵活性,但也可能由于类似FUSE之于内核FS的问题(调用层次加深)而影响性能。

1. 基本使用步骤

以最基本的用户空间进行匿名页缺页处理为例,(例子代码基本来自userfaultfd的man page[1],)步骤大致如下: 阅读全文

一个文件的长度和它实际所占用的磁盘空间很可能是不同的,这主要涉及到稀疏文件(sparse file)和文件打洞(hole punching)的概念。这两个特性需要操作系统和文件系统的支持,目前Linux的ext4、XFS等文件系统都支持这两个特性。

稀疏文件 (Sparse File)

了解系数文件最直观的例子是,创建一个文件,然后用lseek定位到较大的偏移量,在这个偏移量实际写一些内容,这时实际占用的磁盘空间很小,但文件的长度却比较大。比如:

阅读全文

为了统计代码行数(lines of code, LoC),最简单的思路是用python读取每个所输入的代码文件的行数,然后加起来。

本实现分离了代码文件识别和统计,代码文件由用户给出。

1. 实现:

Python实现,用enumerate函数统计可以防止内存占用过大的问题,我们要的只是一个计数,每行读完扔掉即可(pass)。代码如下: 阅读全文

Bloom Filter 和 Cuckoo Filter有类似的用途,很多人将它们称为概率数据结构或者近似成员数据结构(approximate membership data structure)。最近看了一个Bloom Filter和一个Cuckoo Filter的比较好的实现,代码都是用C++实现,代码量也不大,读起来没有什么难度。

本文贴出来的是两个项目的大体构成,不涉及到空间、错误率等的理论分析,希望能给需要的新手一些帮助。

两个项目的网址如下: 阅读全文

Consistency这个词在计算机各领域用的很多,比如分布式系统、体系结构和存储系统等等。本文只探讨存储系统crash consistency。Crash Consistency问题在存储系统中都会存在(数据库、文件系统、dedup系统 …),即系统遭遇断电、崩溃等情况时,相关联的数据没有全部持久化可能导致的不一致。本文以文件系统为例进行说明,所有内容基于自己对相关资料的理解,如有错误,恳请指正!

崩溃为什么会导致不一致

下表整理自我的OSTEP笔记[1],我们假设了一个有data和inode、bitmap两种metadata的简单文件系统,下表给出了一些可能导致不一致的情况,其中N表示断电时没有写完,F表示断电时已经完成:

阅读全文

本文是对《A Primer on Memory Consistency and Cache Coherence》这本书前一半内容的记录和理解,主要涉及memory consistency model。

1. 引言

对于多处理器共享内存系统来说,consistency和coherence都关注的是共享内存(shared memory)及cache的正确性问题,而人们把这个问题拆成两个方面是为了更好地将这个复杂问题分治解决。

1.1 Consistency

一般需要被详细讨论的是多核(或线程)共享内存(shared memory)的consistency模型,因为单核单线程问题相对简单直观。内存consistency模型规定的是:多线程同时进行load/store操作时,怎样的执行顺序是对的,怎样是错的。比较简单直接的consistency模型包括sequential consistency、TSO(total store consitency,x86使用)等。 阅读全文

我们应该怎么分析QEMU代码中某段代码的性能呢?除了比较复杂的trace-event功能(我的博客中翻译过qemu tracing的文档),其实在QEMU自带有一个简单的profiler实现,它是一个简单的计时器封装。这篇博客主要介绍怎么在编译时开启、使用QEMU profiler,并说明怎么利用这个功能添加一个自己的计时器来分析QEMU中某段代码的性能。

1. 编译

我的代码是QEMU 2.12.0。要开启profiler功能,在编译前进行运行configure的时候,只要加入--enable-profiler选项就可以了,它会加入CONFIG_PROFILER这个宏定义。比如我用如下选项进行编译:

阅读全文

日记式的个人胡扯,没有一句话保证正确,谢谢围观,欢迎指正。。

通用与专用,没有好坏

首先举两个极端的例子:深度学习应用十分重要,因此人们愿意专门为它花钱设计新型专用芯片和硬件架构,甚至可能为了它的性能,没准以后会重新写了一个叫”DnnOS”(我自己瞎编的名字)操作系统;而Jc写的helloworld.py程序无论在Linux, Windows 95还是Win 10上怎么折腾,都是打印一行hello, world,没有任何区别的。

哪个更好的问题没有绝对的答案,也许深度学习的新型硬件没有键盘鼠标和显示器,DnnOS也只要实现一套新型硬件的驱动,复杂程度远远小于Linux和Windows。但是Jc的helloworld.py无论运行在多么复杂的系统上,都无法到一个好的深度学习模型所带来的价值;反过来说,即使这套新型深度学习工具再牛逼,可能都无法运行Jc的helloworld.py程序。 阅读全文

“写放大”(Write Amplification)在存储系统中是很常见的。但是,即使都是在存储系统中,“写放大”也有很多种,各种的写放大原理并不是很一样。下边根据自己的理解,进行了下总结,如有问题,恳请指正。

1. 读写单元较大导致的写放大

在文件系统中,读写单元固定,比如都是4K,这样,如果write函数写的数据小于4K,则要先把整块读入,再修改,再把新的4K整体写入(O_DIRECT情况除外)。这个过程可以称为 RMW (Read-Modify-Write),这就是File System的写放大问题。[1][2][5] (注意:Read-Modify-Write被更广泛地用在原子指令[3]和RAID[4]中。)

再如,在DBMS等应用层存储系统中,同样存在自己管理的读写单元,如MySQL的默认读写单元称为页,默认是16KB,所以一次读写只能以页的单位进行,这时,小于页的数据读写同样会带来整页的读写,进而造成了“写放大”,道理和文件系统是一样的。 阅读全文