最新

CPU、ANE、GPU 连接同一块统一内存的简约概念插画

用一个矩阵乘法看懂 ANE、GPU 与统一内存

最近看 Kapitsa 的 ANE 实现时,我想先弄明白一个很小的问题:如果只计算两个矩阵相乘,数据究竟怎样进入 Apple Neural Engine,答案又从哪里回来? 于是把例子收进一个 main.mm 文件:输入是两个 2×2 矩阵,计算图内嵌在文件里,乘法交给 ANE,最后打印结果。本文先把硬件和内存关系画清楚,再顺着这个例子读代码。 1. ANE 是什么,它和 GPU 有什么区别? ANE(Apple Neural Engine)是苹果的神经网络加速器,可以归入 NPU。它与 GPU 是并列的计算单元,不是 GPU 内部的一种核心。 它们都能做大量乘加运算,但面向的软件接口和硬件取舍不同: 计算单元 在这里怎样理解 常见工作

By chainhelen

xv6 系列一(搭建环境)

准备 需要三个部分 1. RISC-V 工具链 2. 虚拟机 3. xv6源码 1. 工具链 RISC-V工具链 RISC-V 建议采用手动编译的方式,brew install riscv-tools相对于来说比较卡 git clone --recursive https://github.com/riscv/riscv-gnu-toolchain 代码下载时间比较久 问题: a. 如果下载sub module下载失败了,需要进入 riscv-gnu-toolchain目录下,重新执行 git submodule update --init --recursive 下载 b. 遇到错误/bin/

By chainhelen

关于沟通

近一年,严格来说可能是11个月,我时常反思关于沟通的问题。一直到近几个月的沉默。我理解都是沟通是原罪。以下言论都是我抹去了大多性格上的短板因素,刚好也是去年这个时候开始想这个因素变量(令自己恐怖的是这个件事我竟然想了一年,老是觉得是上周的事情),这么做是为了减少计算量,我需要计算自己这点上的影响数值。 1. 首先要把自己的位置放正,其次要把态度放正。位置是要明白自己需要产生多大的影响,而且能产生多大的影响,这是一种base,目的与能力的一种权衡;其次态度可以使自己更加客观看自己,不容易受情绪影响,下的结论会更贴近真实客观。 2. 需要明白沟通是需要载体,我们将 model 简化,单对单场景,载体是人。沟通方式,无非是语言、文字、可视化资料。但是往往令人忽略的是沟通载体的差异性,也就是所谓的共识。排除掉所有性格(情绪)的外界因素,剩下影响共识的是经历和学识。或者说“共识”是 “经历和学识”的一种高度抽象,然而“经历和学识”还是太过于抽象,于是在我的认知范畴内将其转化为可计算的。难点在于如何作为简化计算公式和输

By chainhelen

golang 神坑range

总结一下碰到的一些range问题,尤其是边loop边delete的骚操作,我一直以为是人家开源库的bug,直到我看到golang官方也这么用。 首先是比较经典的问题,我们团队之前确实有人写这样代码出事了。 v是数据复制 1. 代码本意是为了获取每个slice每个元素的指针,构造成新的slice type P struct { Name string Age int } func main() { o := []P{ P{"chain1", 20}, P{"chain2", 21}, P{"chain3", 22}, } oPointer := make([]*P, 0, 3) for _, v := range o { oPointer = append(oPointer, &v)

By chainhelen

golang 非协作式抢占

最近因为dlv里面有个bug,关于go1.14版本之后非协作式抢占扩大了调试状态下的一些协程问题。 于是就找了原始的提议看了看,恩,果然大部分都看不懂!!! 利用google/baidu式的翻译,手敲了一遍,并且存疑的地方都加了一点东西,算是给自己一点做个笔录吧,后面有理解更深的地方会更新一下自己的理解。 翻译笔录英文版本如链接 摘要 go 当前在编译器插入的函数序章中插入协作抢占点。在大多数情况下,这足以让golang开发人员忽略抢占细节,专注于编码清晰的并行代码,但是这种方式有着非常尖锐的问题,以至于我们一次又一次的看到它降低了开发人员的体验。当它出现错误时候,就会呈现出惊人的错误现象,导致未知的系统层面的延迟问题,甚至有时候会完全冻结(就是卡住不动的意思)。因为这个是存在于golang语言语义之外的语言实现问题,这些错误是非常令人吃惊的,并且非常难以调试。 @dr2chase已经投入了大量的精力在循环中建立协作抢占点的原型,这是解决这个问题的一种方法。然而,即使是复杂的方法也会导致在紧密循环(我理解就是死循环或者短时间无法跳出的循环)中无法接受的减速(这种

By chainhelen
丢弃包袱

丢弃包袱

可能一时也没有想好起什么题目,脑袋里的思绪大概是往14年那飘,当时关于纯粹体系构想在心里初步形成。某天晚上手写了很长的一篇文章,一直作了保留。那时候状态就是疯狂否定自己以前的思维模式,无论是学习还是生活都按照既有思路(根理论)出发,得出一个基本行为模式。如果不说的这么抽象(或者玄乎),可能跟平时常说的"人设"这个词最像。所有的行为都需要严格按照"既定的人设"进行,不可违反,否则就类似计算机中了病毒(或者严重bug),无法正常生存下去。 甚至当时有种想法现在看来很傻,心里按照既定公式来计算每个人的"纯粹度",以此在"纯粹"这个维度来将人分强弱等级。公式有许多的输入参数,而且公式是需要不停地更正的,因为变量因素这个东西实在是很难控制,只能通过局部最优解去揣测全局最优。这些我自己总结的思考方式对我的影响实在深远,不利的一面也异常明显。我会花大量精力去列举出大量繁琐的公式,长时间进行调参以规整自己的行为模式。 可是最近几个月,一连串的事情让我措手不及,我甚至连调整参数的空余都没有,就已经被击败了。我开始反思,想参考别人的思维方式。

By chainhelen

思考

不战而屈人之兵

背景 最近有很多事情变化太快,对于局势的不解,反而让我有更多的时间反思了. 前提 首先个人不是神,不可能想全所有的细节进行推演. 局势上宏观任何的变动对于微观上都可能是致命的,甚至无法预料. 而恰恰宏观势的观察异常困难,尤其是面临各种信息差的时候. 核心竞争力 个人反思一下,对于任何一家企业招人,它愿意招你的根本条件是什么?(这里排除极个别异常的情况) 是你能给这家公司带来利益,那么利益是经由你怎么产生的,这个就是你在这家公司的价值 对于个人(普通员工)直接带来利益的手段,就是解决问题 如何花费最小的代价解决不同层面的问题决定了你在这家公司的职级 这里扔去网上那些对于核心竞争力这个词的定义,思考一下同样情况下竞争力 即基本技能水平达到与你同样门槛的其他人,你是如何表达出你的优势,从而让上层人员优先选择你. 见胜不过众人之所知,非善之善者也. 形 始终要明确一点,你的影响力一定是由人进行传播的. 换句话说,就是你需要明白时刻与你影响力的载体进行打交道 如何花费最小代价(尤其是一些行为后遗症)达到传播的效果,快准狠 另外对于形的分类而言,

By chainhelen

go

调试器与GO

调试器 如果把调试器看成一个产品的时候,首先他应该具体的功能有哪些? 1. 断点 2. 代码与当前断点映射(例如查看源码) 3. 断点过后继续运行(继续执行,单步,单出) 4. 打印变量 附属的功能: 1. 打印调用栈 2. 打印堆栈 3. 函数调用 4. 条件断点 5. 反汇编 ... 调试状态 linux会有trace进程的状态,对被trace的进程可以进行控制 基本功能 断点 断点通常分为两种,硬件断点和软件断点 1. 先说硬件断点,这个我们(普通的后台开发)平时不太常用,对于x86系统来说, 是依赖寄存器DR0~DR7和2个MSR实现的 说直白一点,就是可以把内存地址放到寄存器内,当cpu进行 读、写、修改该地方内存时,就会触发trap 2. 而对于软件断点,

By chainhelen

2020年

背景 以前很少按年跨度来做总结(除了工作上),对于我而言总觉得年的跨度太长了 下面三张脑图的一些点是这两年陆陆续续补上去的 (svg矢量图可以右键在另一个tab里面打开,看起来比较清晰) 架构 这张图的第一版本是2年前我维护nodejs api 网关写的(表达的认知可能还是比较肤浅)以及后续在后端团队里面的补充 最核心的还是对于网关的认知,项目本身它承载着比较重要而且前沿的思想理论 (但是目前感觉这个项目没有充分完成它的使命,辜负了它的创始人) 分布式事务 18~19年在维护旧系统里面,遇到最恶心的问题之一:微服务之间数据不一致 尝试了一些解决方案,最后还是比较倾向柔性事务这个概念 (还有一些图,因为涉及了比较敏感数据,我感觉不应该放在blog上面) 技能 这个图主要是目前工作中遇到的问题,打算串起来

By chainhelen

tcp连接迁移

意义 搜了一下好像并没有文章讲这件事,网上的tcp迁移貌似讲的都是网关,跟upstream直连偷偷换连接(偷改四元组,类似负载均衡);;不过我说的可能跟其他人看到标题时候想的也不一样,实际主要说的是热更新tcp长链不断。 mosn 主要也是看了mosn(蚂蚁版本envoy)源码,这块挺有意思的。 实际上我也没有完全看明白它的实现,里面代码封装太多层(抽象,也不好调试)。比方说,conntion迁移的时候是和reader buffer的数据一起过去了,如何避免中间时间差的read buffer;我只是翻懂了大致的思路,然后自己写出来一个(写法上有一些差异)。 热更新 关于热更新:类似nginx或者go http服务的热更新,一般都比较熟知大致流程; 新进程继承listen port(子进程继承),并且接受新的http请求; 旧进程上面已存在的http请求正常运行至结束,旧进程在所有http请求关闭后自动退出; 所以新旧进程短时间可能会同时存在运行。 可以拿nginx和python来做个试验。 第一步:可以看到Nginx监听了80端口,没有任何连接

By chainhelen

b+

落盘的b+树(二)

事务 之前的b+树,并没有满足一致性的需求(或者说原子性), 因为涉及到写操作的时候,牵扯多了多个节点变更,如果出现其中一个节点写出现问题,整体上就没有办法恢复了. 所以加了一个分支,实现了出现部分写入问题,可以进行回滚. 解决 需要解决这种问题,目前必须采用double write,就是提前讲数据落在别的地方,等出现问题的时候能够从别处恢复 整体上记住一件事,出现double write的场景都是因为写是inplace update而不是append only redo/undo 例如mysql中innodb的undo和redo 都知道undo记录原始数据的值,本质上是逻辑日志(面向tuple记录) undo是保证原子性(另一个作用是为了mysql的快照读这种黑科技,mvcc) 而redo记录事务中数据变化后的数据,本质上是物理逻辑日志日志(面向page页,physical-to-a-page, logical-within-a-page),更像是"残缺"的快照 说残缺是因为如果快照下全部页的占用空间成本太高了,通常不会全部记录

By chainhelen

落盘的b+树

参考内容 项目地址: bptree 代码参考:主要参考了两个版本bplustree和go的内存版本bptree   定义参考:对于b+树的定义有太多了,主要参考了b+树总结 实现细节 1. 可以提前申请一些节点(leaf和node)结构的内存池,避免大量内存申请和释放 2. 每个磁盘块(系统和磁盘交互的最小逻辑单位)都是一个节点所占空间大小(会有浪费),需要序列化写入文件 3. 因为是递归操作,所以每一个函数当出现将某块磁盘节点映射成内存节点,都应该在函数结束前某个时机(可能其他调用了其他递归函数也进行了映射,造成数据覆盖)刷盘 4. 文件开始位置并不一定是根节点,因为节点会不断增加和删减,所以在读取文件时候需要check root   5. 还有一些事务性问题,比方当前节点已经刷盘,但是延伸更新父亲节点刷盘失败,这种情况暂时没有考虑   b+树优

By chainhelen

go

godbg 介绍

Start a new project, the debugger on linux platform for go. This project is inspired by dlv github地址 背景 没想到这个项目最终还是沦为为一个玩具。初次有这个想法是因为发现 gdb调试golang代码是可以进入runtime的指令,而dlv却不可以。例如像map这种的初始化 s := make(map[int]string, 20) 主要是dlv将runtime的代码都skip掉了,表示对golanger无需关心底层的逻辑,只需要关心自己编写的代码即可。 先看一下效果 实现 代码本身分为5个步骤,代码是在main.go 1. 获取生成含.debug可执行文件的路径 2. 编译创建可执行文件 3. 分析可执行文件里面的_zdebug的字段,以便后续调试使用 4. 执行可执行文件,并且ptrace

By chainhelen

nsq

nsq 支持分布式事务(四)

也许我就是个跑偏的人,这个系列越写越偏 基准测试 本来是跟原版里面./bench.sh做一些基准测试,在我这台垃圾电脑上面 写性能 最后发现如果没有SyncTimout(就是超时落盘)这个,dtnsq写竟然40w/s,而nsq才18w/s~20w/s 没办法加上了默认了SyncTimout(2s),但是dtnsq也是30w/s 大家在落盘之前都是内存操作,如果有性能差异,我猜测是 channel导致的 读性能 读性能没法比较,因为当前dtnsq根本没有做push,只是定时拉取 修改 我需要将一些代码细节优化(不是为了写性能),稍微向生产方向靠近再来进一步测试 优化定时器 之前的消费者的pull定时器是从nsqd里面触发的,很容易将整个nsqd``lock住 这里面改成每一个读backend自行维护一个定时器 控制反转 之前写代码的时候,有考虑一些控制反转,但是还需要细致下去,主要是为了做单元测试 不然现在改几行根本不敢确定有没有影响之前的功能 (未完待续)

By chainhelen

go

go源码阅读 slice

slice 对于slice来说,其实源码部分并不多,主要看一下make slice、growslice、slicecopy和copy 编译阶段 make slice语句跟map一样,在compile的typecheck阶段,将MAKE节点偷偷换成OMAKESLICE节点 关于oppend的代码实在/usr/local/go/src/cmd/compile/internal/gc/ssa.go的func (s *state) append(n *Node, inplace bool) ,这个是编译时代码 关于slice的代码在/usr/local/go/src/runtime/slice.go ,这部分是运行时代码 type slice struct type slice struct { array unsafe.Pointer len

By chainhelen