Latest

Coroutine

从一般概念上说, 协程是特殊的函数调用: 被调用的函数可以在可控的位置被中断,然后在下一次调用时,继续从上次中断的位置继续执行。 本文主要通过Python的协程来介绍协程, 这是我唯一熟悉的一种协程实现. Classic Coroutine 下面的python代码很好的说明了协程的核心功能 def co_routine(): recv0 = yield 996 # hangs here after first coro.send assert recv0 == "Second" yield 711 # hangs here after second coro.send return def main(): coro = co_routine() # Create a new coroutine object value = coro.send(None)

By Edimetia3D

GDB with Python

这篇文章的主要应用场景是调试Python的C/C++ Extension 1. 同时使用pdb / gdb 进行调试. 通俗点说, 既可以break在 .py 文件中,也可以break在 .cc 文件中 2. 在gdb中不但可以获得常规的调试信息, 还可以获得python VM 的调试信息, 例如获得python的调用栈, 访问Python局部变量等. 这将会在调试exception时(如Segmentfalut)非常有用, 这种场景下, 定位 Python VM 正运行到哪一行代码往往可以提供一些直观的重要信息. 第一步: 编译源码以获得一些辅助数据. 我们并不真的需要使用从源码编译的Python, 但是一些调试相关的辅助文件需要从源码中获得, 包括 python-gdb.py及debug symbol等. 在 https://www.python.org/ftp/python/ 或 https://github.com/python/cpython

By Edimetia3D

Bazel Notes

这是一篇2019年左右的记录, 内容可能过时, 也不太全面 杂谈 Bazel是Google为Monorepo服务而开发的构建工具. 首先是巨大,当问题的规模变大,事情总是会变得更复杂. 而Google面对的"巨大Monorepo",应该是世间罕有的. 然后是Monorepo,这极大的影响了代码的组织风格.例如,你要写一个操作系统内核ProjectOS,还要写一个游戏ProjectGame.在传统的开发习惯中,这两个项目会组织到两个不同的Repo里,PorjectOS和ProjectGame之间无法直接相互引用,例如,你在ProjectOS里写了一个高级的数据结构,想要在Game里也使用,要么直接复制粘贴,要么是创建一个新的CommonRepo,把可公用的代码都放在Common里,然后两个项目各自引入Common作为依赖. 使用MonoRepo则不存在这个问题,Game可以直接依赖OS内的组件,按照Bazel的语法描述,就是在Game中可以直接使用@ProjectOS//path/to/package:AdvancedStruct.当然,你仍然可以选择重构一

By Edimetia3D

Unix related things

这是一篇2017年左右的记录, 仅用作分享 杂 * 在shell内能干的事,我们都可以比较简单地通过系统调用实现. * `称为反引号,^称为脱字符,常用来表示CTRL * windows的系统调用是不开放的,windows下只能直接使用windows.h里的windows API. * /dev目录下的设备是供用于程序直接使用的,主要由block,char,pipe,socket类型 * 并不是所有设备都能映射为这种形式 * /sys/device/目录称为sysfs,他下面存放了所有设备的信息.(不能直接从/dev获得任何设备信息) * udevadm info --query=all --name="/dev/sda1"可以用于查询/dev下某个设备对应的sysfs路径 权限系统 * 权限系统由两部分组成 * 文件属性:用于标注文件owner,所属组,以及权限的设定(默认只有owner和root可以修改权限设置) *

By Edimetia3D

Docker

这是一篇2017年左右的记录, 内容可能已经过时 * Docker的image类似于Git的repo,而docker的tag则类似于git的branch * 由于内核共享, Docker container 里的uid/gid是和宿主机复用的, 所以相关的鉴权系统也和系统一致. * 用户名可能不一致, container内可以使用自己的用户名. * 可以使用 --user来指定docker container内所有进程的执行身份 * Docker 可以近似为特化的虚拟机,除了Kernel外,所有的其余部分都可以是Docker独占的。 * 例如,可以制作完整的OS镜像,这些OS镜像除了没有内核,其余都和正常的OS是一致的。 * Docker之间的隔离相比VM要浅一些,可能存在一些安全问题;另一方面,VM则由于可攻击面更大,也有安全问题 * Docker可以说是一个Utility, 并没有自创新技术,所以Docker中的技术主体为Docker-Engine,它只是驱动整个体系高效的运转. * Docker是通过K

By Edimetia3D

Bitcoin and Blockchain

这是一篇越在2016年左右记录的笔记, 仅仅分享 比特币 比特币作为区块链的元祖, 引入了许多基本概念, 能作为学习区块链的开端. 目的 比特币的意图是实现一个去中心化的货币系统, 比特币的发行和支付由参与网络的所有节点所控制. 从原理上说, 所有节点都完全独立, 也就是说: 每个节点都拥有完整的货币数据,包括发行记录及支付记录; 每个节点都可以发行货币,也可以发起支付. 比特币主要解决了这个问题: 如何让网络中的所有节点都可以"彼此不信任"的"达成共识" . 彼此不信任是指:对于任意节点X而言, 其他节点彼此相同,没有特殊的"可信"节点(或者说,你无法判断某个节点是否可靠). "达成共识"是指, 所有节点最终都持有相同的货币数据, 主要是发行记录和支付记录. "达成共识"的结果是所有人都持有相同的数据,但是并不是说相同的数据就是正确的数据,这些相同的数据也可能是被攻击后产生的数据. 比特币的设计只是大概率的能避免被攻击而已. 除了上述问题外, 比特币及相关的其他工具都是服务于安全和性能.

By Edimetia3D

Shared Library

* 编译,链接,静态库与动态库 * 预备知识 * 编译: * Relocation * 静态链接 * 动态链接 * 细节问题 * 动态链接器如何确定可执行文件的所有依赖? * 文件定位的规则 * 动态relocation细节 * dlopen * fPIC * 控制DSO的dynsym符号导出 * Versioning (Version script) * Interpose * Good Practice 正确而高效的使用动态库是一个很复杂的话题,这需要开发者编译和链接有相当深入的理解. 本文主要关注"正确使用",这已经足够复杂. 这里主要是描述linux/gnu体系下编译器/链接器的行为(可能不适合其他系统,甚至不适合老版本的linux工具链), 这些行为的设计一般都有历史因素及兼容性的考量,所以某些部分可能看起来不够优美. 编译,链接,静态库与动态库 预备知识 编译: * 将单个编译

By Edimetia3D

The Building Blocks of Transformers

Transformer完全改变了2017年后NLP领域的模型方向, 从某种意义上说,Bert,GPT等模型都是Transformer模型的变体, 虽然模型结构有各种改变, 但是其中的一些基本计算单元则变化较小. Transformer几乎就是为了改善计算性能而专门设计的模型. 1. 完全没有RNN之类的循环计算需求, 这就极大降低了计算过程中的顺序依赖, 可以极大提高并行性. 2. 大量使用矩阵乘, 不使用卷积这种计算强度不够大的算子 正是由于Transformer使用到的基本计算单元非常简单, 几乎就只有 gemm, +-*/, layernorm, softmax, 也没有奇怪的计算流程, 所以原文的作者将其称为一个"简单"的模型是很有道理的. 本文就是简单记录Transfomer中使用到的基本计算单元. Basics 想要理解Transfomer计算流程的话, 可以参考 Transformer’s Encoder-Decoder: Let’s Understand The Model Architecture 如果有不清楚的地方, 可以参考Github 我这

By Edimetia3D

A note for cmake

A Note for CMake CMake可以说是目前C++项目的标准构建系统, 尽管它有很多不足, 但是它已经成功的替换掉了autoconf这一代的构建工具. 除非有足够的理由, 在选择构建系统时, CMake总是应当第一优先考虑. 我熟悉的构建系统只有CMake和Bazel, 事实上, 如果能满足若干客观条件的话, 我更愿意使用Bazel, 不过这篇主要记录的是CMake, 所以还是以CMake为主. 在我看来, CMake主要的优缺点如下: Pros: 1. Imperative: 可以把CMake当做一个脚本语言来阅读, 这更符合大家的编程习惯. 2. Widely-used: 你只要大致会使用CMake, 那么世界上的大部分项目都可以被你使用了. 3. Easy-at-beginning: 上手成本很低, 简单的binary和library都很容易被描述出来, 对新手友好. Cons: 1. Too many traps: 你必须要非常熟悉CMake, 才能写出稳定可靠的CMake脚本, 否则, 处处都有坑你的陷阱. reddit上曾有一个评

By Edimetia3D

A Strory of Mixin

Mixin Mixin是一种设计思想, 主要内容是: Mix some MixinClass into a CoreClass, so the CoreClass can get some new feature, or get enhanced. 与其他设计模式相比, Mixin的主要特点是它没有固定的编程pattern, 只是一种指导思想, 所以可能会有各种各样的具体设计自称为"Mixin", 因此, 当你看到一个"Mixin"设计时, 常常会想"我用XX不也可以实现这样的效果吗?", 这是非常正常的. 一般而言, 当设计实现了Mixin时, 常常会有以下特点: 1. 使用多继承或链式继承, 因为我们常常需要把多个MixinClass混合到CoreClass中,使用多继承或链式继承是非常直观的方法. 2. 尽管使用了继承, 但是一般不进行"覆写&

By Edimetia3D

Tablegen Language Tutorial

Tablegen Language Tutorial 很难想象,网络上竟然搜索不到可以称为"教程"的Tablegen资料. 唯一可靠的资料是官方的ProgRef, 作为一个Reference, 它是非常合格的, 详尽而精确, 但是如果把它作为教程来阅读, 则有一些缺点: 1. 过于详尽, 即便是一些不太重要的特性,也需要用完整精确的内容来描述. 2. 过于严谨, 即便是一些简单的特性,也需要用严格的方式来描述,比如 EBNF 风格的 syntax notation, 至少我的大脑是无法 zero cost 的 parse 这种notation的. 3. 内容排布不合理, 一些不重要的特性经常位于较为靠前的位置, 且总结性的内容较少. 为了避免这些问题, 本文将按 Quick Start 风格的 Tutorial 来组织,先熟悉最核心/最重要的概念, 再学习其他的功能. 通过这篇教程,你应该能够

By Edimetia3D

未分类

Lit and FileCheck

Lit And FileCheck Lit 和 FileCheck 是 LLVM 测试中常用的工具, 尽管二者功能上是完全独立的,但是搭配起来使用会显得更加方便. Lit Lit总的来说仅仅是一个 test-launcher, 它的主要功能就是发现测试,执行测试,收集结果. "发现测试"主要依赖于lit.cfg(或lit.site.cfg)文件标记来实现. 当一个目录下包含这个文件时, 那么这个目录就可以被用作lit的测试根目录, lit会自动的递归进入子目录查找测试文件. "执行测试"则相对简单, 每个"lit测试文件"都应该是文本文件,这些文本文件中 RUN: 将被视作标记,这个标记之后的内容就是执行测试的shell指令, 测试指令返回0则认为测试通过, 例如 RUN: echo jojo | grep jojo. 具体来说,

By Edimetia3D

未分类

比较运算符, Min, Max, Sort 和 Order

惭愧,突然发现又是没有blog的一年。这一年不断在尝试搞大新闻,写点大东西,到现在也没憋出来。倒是又在学习新东西的过程中看到了一些零碎的小知识,很有意思. 很巧,这个也是和比较运算符相关的,和一年前的blog竟然有所重合。 还是先上结论: 当需要为类型T定义比较运算符时,所有运算符最好保证语义整体一致 * 一般来说,这很容易达到,我们只需要实现operator<(lhs,rhs),即可引申定义出其余几个比较运算符. * 定义operator<=为 !(rhs < lhs) * 定义operator>为 rhs < lhs * 定义operator>=为 !(lhs < rhs) * 定义operator= 为!(lhr < rhs) && !(rhs < 1hs) * 定义operator!= 为

By Edimetia3D

布道

IEEE 754 的 inf 比较问题

首先上结论: 当涉及浮点数比较时,一定要考虑比较符号两侧都是inf的情况. 原因: inf==inf,inf<=inf,inf>=inf 这三个比较都为真(-inf同理),而这种结果可能与我们的期望不符. 解决方法: 1. 如果为真是可以接受的,那么直接使用比较运算符,例如a<=b 2. 如果为真是不可以接受的,那么应当使用作差,例如(a-b)<=0, 这种情况下,当a和b都为inf时,inf之间的运算会输出NaN,从而导致比较结果为false 例如,我有这样一个应用场景: 有射线R和两个平面S0及S1,我们需要求射线R与平面S0的交点p0,以及射线R与平面S1的交点P1. 且要求p0不能比p1离射线起点更远(可以重合) 假如我们用直线的参数方程来描述交点,显然,上面的目标很容易用 t0<=t1 来描述. 此时就可能出现 inf<

By Edimetia3D

记录

KD树与SKD树

KD树与SKD树 首先给出两个搜到的有点内容的KD树文章,论述的比我说的更完整(更冗长),可以先看,也可以看完本文再看. * https://www.zybuluo.com/l1ll5/note/967681 * http://www.whudj.cn/?p=920 主体思想 * KD树和SKD树都使用坐标轴对齐的最小包围盒来描述空间. * 例如,平面内,一堆点的点集对应的空间可以用点A=(min(all_x),min(all_y)),B=(max(all_x),max(all_y)) 对应的矩形空间来描述. 当点的个数变为1时,这个矩形空间也会自然地退化为一个点. * 构建时的主要思想: 每个节点node都对应了一个空间box(node),node->plane用一个超平面把这个空间box(node)一分为二,记为sub_left,

By Edimetia3D

记录

设计模式

For C/C++ user 很多设计模式相关的资料都是用Java来描述的,有必要简单补充一下Java和C++在OOP技术层面上的区别 * Java不支持任何形式的运算符重载 * Java明确区分接口和类,类只能从一个类派生,但是一个类可以实现多个接口 * 在Java中,所有方法默认是虚(virtual)的 * 对CPP而言,Java风格的接口可以视为一个只有pure virtual成员函数的基类,称为Interface * implement,is-a(inherit),has-a * implement: 特指继承Interface,并通过override实现其中函数的行为. * is-a: 特指继承普通类后,普通类和基类的关系. * has-a: 特指持有某个对象. 杂谈 * 设计模式可以说就是各种各样的"OOP最佳实践方法". 一个设计模式对应了一种组织代码的风格,对应了一种解决问题的策略. * 设计模式可以说是程序员的"行话",使用"行话"有利于交流,但是并不一定有利于问题的解决,简单优雅的解决问题总是

By Edimetia3D

C++系列

SomeCpp

零碎知识点 * fflush仅仅是为了输出而设计的, 标准中并没有说明它对输入缓冲的效果. * 一元运算符和=是右结合的,这和<<是完全不同的,a=b=c意味着a=(b=c),b=c将先执行,而a<<b<<c则是(a<<b)<<c,a<<b将先执行. * C++11后引入了thread_local型的生命周期,这种对象和线程的生命周期是一致的 * C++11中很多类型都支持列表初始化,a = {value1,value2...} * 列表初始化会额外检测是否可能存在信息丢失,如果可能存在丢失,则无法通过编译期检查. * 对于自定义类,支持列表初始化意味着存在这样的ClassName(initializer_list&

By Edimetia3D

C++系列

Some Multi Thread

C++标准库提供的 mutex 在大部分场合都足以保证线程安全, 但是当问题变得更加极端时,就可能需要使用lockfree风格的并行编程了. 而为了正确实现lockfree, 你将打开一扇新的大门, 接下来的名词都是在学习过程中必须正确理解的: memory model, reordering, weak(relax), strong(strict), fence, barrier, release, acquire, seq_cst, consume, mutex, futex, lockfree(lockless), synchronize-with, happens-before, ABA, DCLP, 背景 在单核时代,CPU设计中引入了很多特性,其中很重要的一点就是乱序执行,乱序执行的基本原则是:乱序执行的最终效果应当和顺序执行一致,这个原则在单线程下是比较容易保证的.例如,对于下面的代码,先写入a还是先写入b都不影响后序的指令执行的正确性,所以编译器及硬件都可以自行选择先执行哪一个. a = 8; b = 9; 当进入并行环境之后,乱序执行的基本原

By Edimetia3D

布道

Python for C++ Programner

这里谈一下个人的学习建议. 首先可以阅读官方的入门教程, 看完这一部分, 对于一个熟练的C++程序员, 应该可以凑合写出可堪一用的代码了. 对于大部分不以Python为主要工作语言的开发者,到此基本就足够了. 如果有时间,我建议直接阅读Python in a Nutshell第七章之前的内容(不含第七章),并不用完全看懂,大部分细节也不用去记忆,只需要看完即可,至此,你就能基本了解Python的运行机制, 写出质量稳定可控(不会存在低级错误)的代码了. 上面两步完成后, 对一个熟悉C++的程序员而言, 基本任何Level的Python资料都可以看了. 你可以继续看Python in a nutshell中感兴趣的部分,也可以选择Fluent Python. 在有相当多的开发经验之后,可以阅读Python Cookbook. 如果仍然想进一步深入, 那么你应该直接学习CPython解释器的实现,Python Developer’s Guide可以作为一个入口. 最后,本文仅仅简单扼要的说明了Python和C++不同的一些特性, 可以作为补充阅读. 书评

By Edimetia3D

C++系列

[Cpp基础][09]C++11多线程编程基础

C++11为多线程开发准备了一套标准的基础设施,主要为<thread>,<mutex>,<condition_variable>, 这套组件基本是"pthread"的标准化.本文主要介绍C++11多线程开发相关的基础内容.如果需要更多的细节,可以直接google或者查手册进行了解. 可调用对象 可调用对象在C++ 11中是非常重要的概念, 它使得"函数"变得更加像对象. 线程库完整的支持可调用对象. * 支持()运算符的对象都是可调用对象,这些工具的设计比较独立,可以在使用时再查reference,常见的有 * bind创建的对象 * lambda * 重载了()的类 * 函数/函数指针 * function<T>. std::thread * 标准库提供了std::thread来进行基础的线程管理,

By Edimetia3D

C++系列

C++ OOP编程综述

嵌套类和局部类 * 定义在类X内的类Y称为嵌套类,它就是一个普通类,只不过使用的作用域被限制了. * 定义在函数内的类Y称为局部类,这种类限制很多,主要用于在语言层面支持Lambda,实践中基本不用. struct(class)的内存布局 * C++的struct和class实例大小不会为0,即便它内部没有任何数据变量.主要是因为编译器总是需要为实例分配内存,使得对象能获得有效的地址,且不同对象的地址总应该是不同的. * 类型布局相关的名词有很多,如POD,Aggragate,naive等,具体我也不是很清楚,总之很麻烦. * 如果需要把sturct或class对象通过C风格直接从内存层面管理(如memcpy),那么要求它的内存布局是平凡的. * 只要类型涉及到virtual, 那类型实例的首地址存储的一定是vptr, 涉及virtual只需满足任意一个条件: * 直接或间接使用虚继承 * 直接或间接使用虚函数 一般规则 C++对象的内存布局对于理解多继承/虚继承非常重要, 基本要关注的有三点 1

By Edimetia3D