[Fundamental] From Online Softmax to Flash Attention V3

Flash Attention from Fundamental Series

August 10, 2024 · 7 min · chenghua.Wang

mllm框架浅析(一)-以QWen0.5B为例

以Qwen0.5B为例解析mllm的基本实现,CPU Backend

June 28, 2024 · 8 min · chenghua.Wang

【施工中】6xKx16 SGEMM Kernel on X86-AVX

How to impl high performance 6xKx16 micro kernel

June 16, 2023 · 5 min · chenghua.Wang

浅析机器学习中的并行模型和自动并行方法

数据并行、模型并行、流水并行、专家混合

May 2, 2023 · 3 min · chenghua.Wang

CUDA: NSight System

Usage of Nsight System

April 18, 2023 · 6 min · chenghua.Wang

XV6 Lab 5: Copy On Write

xv6 中的 fork() 系统调用将父进程的所有用户空间内存复制到子进程中。如果父进程很大,复制可能需要很长的时间。更糟糕的是,这项工作通常是无用的:fork() 之后通常是子进程的 exec(),它放弃了复制的内存,没有使用复制过来的大部分内存。如果父代和子代都使用了复制的页面,并且其中一个或两个都写了它,那么这个复制才是真正需要的。 所以写时复制(copy on write, cow) 这个技术变得十分的重要。在这个 lab 中,我们需要实现一个写时复制的 fork()。我们需要修改原本的 fork() 程序中做内存申请的模块,同时我们还需要实现 usertrap 来在写时(在实际写的时候碰到 cow flag,抛出分页错误)的时候处理这个 trap。 因为一个程序很可能被 fork() 了很多的分支,所以我们需要一个计数器来确定这个 page 是要被释放还是保留。 一般来说,一个正常运行的程序在写时复制的时候会有下面几个流程: fork() 出一个子进程 child。 child 拥有父进程的页的引用,并且页的 flag 有 cow 标识。 并且要把 页 引用 ++ child 需要向自己的页中写入新的数据. 此时需要重新分配内存,页引用 –。 当 child 返回的时候,可能有内存需要由 kernel 转换到 user。 当父进程销毁的时候,如果计数器为 0,则销毁,反之,不变。 每一页都需要一个计数器来进行计数,所以我们需要在 kernel 中加入一个数组来记录,查阅 xv6 book,我们发现有如下的图: Fig 1. memlayoutXV6 手册 我们需要在 kernel data 之后的区域内申请一块内存来作为计数器存储的数组。我们可以在 kalloc.c 中实现。 // ./kernel/kalloc.c struct { struct spinlock lock; struct run *freelist; // lab 5 uint* ref_cnt; struct spinlock ref_cnt_lock; char * pa_start; } kmem; 在这个 kmem 结构体中加入了一个 ref_cnt_lock 来保证计数器的正确引用。一个 ref_cnt pointer 来指示 ref array 的起始位置,使用 pa_start 来表示实际的 free memory 的起始位置。我们还需要修改初始化程序来正确的申请计数器数组,并且对 free memory 填充上一个初始值。...

March 17, 2023 · 4 min · chenghua.Wang

XV6 Lab 4: Traps

RISC-V assembly Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf? Register: a0, a1, a2…, a7 for integer arguments. Register fa0, fa1, fa2…, fa7 for float arguments. Register a2 holds 13 when we call printf(). Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.) Compiler inlined f(8) and g() in printf() function....

March 5, 2023 · 6 min · chenghua.Wang

XV6 Lab 3: Page Table

MIT 6.S081 Lab3 website 做 Lab 3 需要提前阅读 XV6 book,了解 RISC-V SR39 的地址格式,并且实验中大量用到了页表的准换函数,需要查阅 XV6 手册。不过,熟记 RISC-V 的地址说实在的没有什么用处,通过这个实验理解页表的工作方式并且 hands on 才是真的。 Speed up system calls 目前有很多的操作系统(Linux)在用户区和内核区之间共享一块数据(Read-Only for user),这样用户在进行系统调用的时候就不需要陷入内核态后,由内核态拷贝数据进用户态,而是将数据写在这个共享的区块内。这样可以加快操作系统的运行速度(毕竟大部分系统调用需要的内存消耗是很小的,内存的消耗在当今已经不是问题)。 在本实验中我们需要使用 ugetpid() 来进行加速获得进程的 pid。 首先就是为每一个进程创建一个页表作为共享内存区块。我们发现在 kernel\memlayout.h 中已经为我们定义好了需要的数据结构: struct usyscall { int pid; // Process ID }; 那么我们只需要在 kernel/proc.c /proc.h 中加入代码,来实现进程创建时创建页表,销毁时销毁页表的动作就行了。 在 proc.h 中,我们需要在进程的 PCB 中加入新的数据结构: struct proc { ... struct usyscall *usyscall; // using read only shared data to accelerate. ... } 为了让进程的正常创建和释放,我们需要向进程创建和销毁函数中加入对应的页表操作代码。...

March 2, 2023 · 3 min · chenghua.Wang