从 RNN 到 Transformer | 深度学习 本文不会涉及复杂的数学推导,也不涉及训练方面的原理,仅讲述算法基本原理与推理流程。 RNN 与 encoder-decoder 结构RNNCNN 中的权重会在空间域上移动以提取特征,RNN 的权重则会在时间域上移动以提取特征。所以 CNN 一般用于处理空间域上的特征(图片等),RNN 则用于处理时间域上的特征(文本、语音等)。 经典的 RNN 要求输⼊和输出序列必有相同的时间⻓度: 每个时刻的 2023-12-01 深度学习
Taichi Codegen 源码解读 | Taichi version: 1.2.0 commit id: f189fd791 git repo: https://code.byted.org/UGC-SDK/Rosetta-taichi/tree/dev/v1.2.0 Overview我们以一个简单的 demo 为例,从源码层面过一下整个代码生成的流程: import taichi as ti # 初始化环境 ti.init(arch=ti.v 2023-11-15 Taichi
08 中间代码优化 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 流图 一个基本块中的代码要么全都执行,要么全都不执行。 指令 8 跳转到 指令 5,所以指令 5 和指令 9 都是首指令。同理指令 13 和指令 23 也是首指令。 常用的代码优化方法 复制传播本身不会优化代码,但是可以给删除无用代码带来机会。 2023-11-02 《编译原理》
06 中间代码生成 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 类型表达式 声明语句的翻译 B:生成基本类型关键字 C:生成数组下标表达式序列 T:标识符类型,C 为空串时 T 生成的是基本变量,不为空串时 T 生成的是数组变量 D:声明序列 P:一个声明序列就可以构成一个程序 以上两个例子过程比较长,请参考原视频。 简单赋值语句的翻译 2023-10-29 《编译原理》
05 语法制导翻译 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 语法制导翻译概述在语法分析的同时进行语义翻译,语法制导翻译即将两者放在一起实现的技术。语法制导翻译使用 CFG 来引导对语言的翻译,是一种面向文法的翻译技术。 比如一个变量,其属性就包括该变量是什么类型的,它的值是多少,存放在什么地方。类似地,表达式的属性也包括值、类型、地址等等。 2023-10-06 《编译原理》
04 语法分析 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 自顶向下分析概述 对于每一棵分析树,其最左推导和最右推导都是唯一的,因为在推导的每一步,当前句型的最左非终结符和最右非终结符都是唯一的。 自顶向下的语法分析采用最左推导方式: 总是选择每个句型的最左非终结符进行替换 根据输入流中的下一个终结符,选择最左非终结符的一个候选式 2023-10-03 《编译原理》
03 词法分析 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 正则表达式 正则定义 有穷自动机有穷自动机(finite automata, FA)具有一系列离散的输入输出信息和有穷数目的内部状态。 系统只需要根据当前所处的状态和当前面临的输入信息就可以决定系统的后继行为。每当系统处理了当前的输入后,系统的内部状态也将发生改变。 最 2023-09-26 《编译原理》
02 程序设计语言及其文法 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 基本概念字母表 $\Sigma$ 是一个有穷符号集合,如二进制字母表(即 {0, 1})、ASCII 字符集、Unicode 字符集等。 字母表上的运算包含以下几种: 乘法: 幂运算: 正闭包(positive closure): 克林闭包(Kleene closure): 2023-09-24 《编译原理》
01 绪论 | 《编译原理》 这一系列是编译原理 (哈工大陈鄞、郭勇)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 什么是编译 编译系统的结构 词法分析概述 语法分析概述 D: declaration T: type IDS: identifier sequence 语义分析概述语义分析的主要任务: 收集标识符的属性信息 种属(kind):简单变量、复合变量(数组、记录等)、过程等 类型( 2023-09-24 《编译原理》
循环优化 | 编译器 本文是系列视频 循环优化 的笔记。 循环展开和压紧基础概念 减少循环分支指令执行的次数 获得了更多的指令级并行 增加了寄存器的重用 循环展开的合法性 循环展开需要在不影响原程序语义的情况下进行,上图中的展开就会改变原始语义。 循环完全展开 过度循环展开可能会增加寄存器的压力,引起指令缓冲区的溢出。 尾循环处理 编译器循环展开 依赖复杂的情况下编译器无法进行循环展开。 Clang 中和循环展 2023-08-30 编译器
LLVM 编译器入门 | 编译器 本文是系列视频 LLVM 编译器入门 的笔记。 项目概述项目组成CONTRIBUTING.md flang llvm-libgcc README.md libc mlir SECURITY.md libclc openmp bolt li 2023-08-27 编译器
家庭公网 IP 的配置与应用 | 玩机 本文首发于少数派:家庭公网 IP 的配置与应用。 本文主要记录了家庭公网 IP 的申请和配置(以上海电信为例),以及在 NAS 管理、远程观影和游戏机串流等场景的应用。 家庭公网 IP 的申请与配置1. 公网 IP 申请公网 IP 的申请比较方便,只需要打电话给客服说你需要公网 IP 就行,客服会直接帮你操作,一般来说 24 小时内就能搞定了。注意有时候客服会问你要公网 IP 做什么,你就回答 2023-05-10 玩机
CMake 合并静态库 | C & C++ 本文转载自《Cmake 静态库链接静态库》,原文有删改。 问题一个静态库 B 依赖了静态库 A,同时在 CMakeLists.txt 使用 target_link_libraries(B A) 设定了 B 链接 A,但是在使用 B 时,发现静态库 B 中并没有 A 的符号。也就是说,cmake 并没有帮我把静态库 A 的符号添加到静态库 B 中。 实际上,cmake 确实不会合并两个静态库,那 2023-03-05 C & C++
ranlib 的作用 | C & C++ 本文转载自《ar、ranlib、nm命令详解》,原文有删改。 前边提到过,静态库文件需要使用 ar 来创建和维护。当给静态库增建一个成员时(加入一个 .o 文件到静态库中),ar 可直接将需要增加的 .o 文件简单的追加到静态库的末尾。之后当我们使用这个库进行链接生成可执行文件时,链接器 ld 却提示错误,这可能是:主程序使用了之前加入到库中的 .o 文件中定义的一个函数或者全局变量,但链接器 2023-03-05 C & C++
修改 dyld 寻找路径 | C & C++ 将动态库 yyy.dylib 的依赖寻找路径从绝对路径改为相对路径: install_name_tool -change /absolute/path/to/lib/xxx.dylib @rpath/xxx.dylib yyy.dylib 给库 yyy.dylib 添加依赖寻找路径(即添加 @rpath 的值): install_name_tool -add_rpath /path/to/lib 2023-03-05 C & C++
如何使用 LLVM 优化器 | 编译器 本文转载自《LLVM 之 IR 篇(3):如何使用 LLVM IR 优化器》,原文有删改。 摘要本文基于 release/12.x 版本的 LLVM 源码,介绍了 LLVM IR 优化的基本概念以及 opt 工具的使用方法。从而,初步了解 LLVM IR 优化器以便更深入地研究相关内容。 LLVM IR 优化概述根据优化发生的时期,LLVM IR 层面的优化可以分为如下两种: 编译期优化。 2023-03-05 编译器
课程笔记:AI 编译器后端优化 | 编译器 本文是以下教学视频的笔记:【AI编译器】系列之后端优化 概述 前端优化与后端优化的区别前端优化:输入计算图,关注计算图整体拓扑结构,而不关心算子的具体实现。在 AI 编译器的前端优化,对算子节点进行融合、消除、化简等操作,使计算图的计算和存储开销最小。 后端优化:关注算子节点的内部具体实现,针对具体实现使得性能达到最优。重点关心节点的输入、输出、内存循环方式和计算的逻辑。 后端优化的流程 生成低 2023-01-02 编译器
课程笔记:AI 编译器前端优化 | 编译器 本文是以下教学视频的笔记:【AI编译器】系列之前端优化 概述 算子融合(OP Fusion)融合方式 融合前:启动 CD 两个 kernel 融合后:启动 C+D 一个 kernel 融合前:启动 A 一个 kernel,并发 B/C 各自启动一个 kernel 融合后:并发 A+B/A+C 各自启动一个 kernel 融合前:启动 A 一个 kernel,并发 B/C 各自启动一个 2023-01-02 编译器
课程笔记:CHI Hierarchical Instructions | Taichi 本文是 Taichi 官方教学视频的笔记: Chi Hierarchical Instructions Overview“CHI” 含义是「气」。 Why CHI? Portability High performance Taichi features Sparse programming Differentiable programming Quantization …… Statem 2022-12-11 Taichi
课程笔记:SPIR-V 代码生成流程 | Taichi 本文是 Taichi 官方教学视频的笔记: 入门GPU编译,一堂课看懂SPIR-V | 快速上手Vulkan, OpenCL背后的技术 Compute ShadersResource Binding 对于参数和返回值,是特殊的数据结构,需要进行特殊处理。而对于其他普通的 buffer,则会先查找之前是否已经 bind 过,有的话就直接返回,否则生成一个新的 binding: 在访问完所有的 st 2022-12-11 Taichi
课程笔记:核函数执行流程 | Taichi 本文是 Taichi 官方教学视频的笔记: 入门必备|想要吃透 Taichi 代码库?快速区分 field 和 kernel,速览 Taichi 底层架构 原理解析 | Taichi 代码从编译到执行,都要经历哪些过程? Overview下面是一个简单的 Taichi 程序的示例: 数据容器的编译和指令的编译是分开的: Kernel Compilation在编译 kernel 时,经历 2022-12-10 Taichi
iCloud 上传卡住 | 玩机 macOS iCloud 上传卡住 的解决办法 MACOS ICloud同步上传或下载卡住/失败/正在上传xx个项目/断网/断链问题的临时解决方案 2022-11-25 玩机
TorchScript IR 中的类型体系 | PyTorch 之前的一篇翻译《JIT Technical Overview》简单介绍了 TorchScript IR 中涉及到的几个主要类,包括 Graph、Node、Block、Value、Type 等。本文主要是从 C++ 接口的角度梳理下这些类之间的关系。 Module::attributes()通过 torch::jit::Module::attributes() 方法可以获取到 module 中的所有 2022-10-14 PyTorch
使用任意字体 | 个人博客 在大多数 hexo 主题中,虽然可以指定自定义字体,但是如果这个字体在阅读者的电脑上并没有安装,还是会用回默认的系统字体,这就大大限制了自定义字体的范围。本文则介绍一种可以让 hexo 博客使用任意字体展示的方法。 使用任意字体 将下载好的字体文件(ttf 格式)放到 ${blog_dir}/source/fonts 文件夹下(没有该文件夹就新建一个)。 新建 ${ 2022-09-24 个人博客
什么是闭包? | 计算机基础 转载自《如何通俗地解释闭包的概念?》 现在有一个函数 f(x) = a + x,这个函数是不完整的:a 是多少? 有两个方法回答这个问题,第一种叫“动态作用域”,a 的值决定于函数调用时上下文中 a 的值,比如: a = 1 v = f(1) # 这里 v 为 2 动态作用域的问题是,函数每一次调用相同的参数未必返回相同的值,其返回值还取决于上下文的某些值。 第二种是“词法作用域”,a 的值 2022-08-20 计算机基础
macOS 常用软件 | 玩机 Maccy:剪贴板历史记录 快贴:跨平台剪贴板同步 LiuHai:隐藏设备屏幕 notch MenubarX:状态栏浏览器 超级右键:扩展右键菜单功能 BitBar:使用 Python 写菜单栏小程序 WGestures:右键手势 Karabiner Elements:按键映射 Keyboard Maestro:操作自动化 Itsycal:菜单栏日历 Bartender:隐藏菜单栏图标 TG P 2022-08-15 玩机
模板参数遍历 | C & C++ 普通写法void expand() {} template <typename T, typename... Args> void expand(T arg, Args... rest) { std::cout << typeid(arg).name() << std::endl; expand(rest...); 2022-08-06 C & C++
动态库的符号可见性 | C & C++ 在编译动态库时,可以通过 gcc 的 flag -fvisibility=[default|internal|hidden|protected] 参数修改动态库中符号的可见性,其中 default 表示符号可见,hidden 表示符号不可见,internal 和 protected 一般比较少用,这里不展开。cmake 对应的命令是 set(CMAKE_CXX_VISIBILITY_PRESET 2022-07-26 C & C++
《JIT Technical Overview》翻译 | PyTorch 本文是 PyTorch 官方文档 JIT Technical Overview 的中文翻译。对于看不太明白的部分,暂不翻译,直接放上原文。 概述JIT 可以独立于 Python 解释器运行和优化 PyTorch 程序。本文根据组件被组织成各个小节: 核心程序表示:JIT 执行的是 TorchScript,在语法上属于 Python 的子集。本节描述了TorchScript 程序如何在 JIT 中 2022-07-24 PyTorch
OpenCL 基本概念 | OpenCL OpenCL 是一个异构计算开放标准。支持 OpenCL 的各厂商设备的硬件实现可能不一样,但是都可以通过 OpenCL 来调度计算单元完成计算任务。 OpenCL 定义了四大模型:平台模型、执行模型、内存模型、编程模型。通过这些模型,可以使用相同的语言/语义来描述不同硬件上的并行计算。 平台模型平台模型描述了协同执行的单个处理器(host)以及一个或者多个能执行 OpenCL 代码的处理器(de 2022-06-22 OpenCL
new 和 make_shared 在内存上的区别 | C & C++ 先说结论:先 new 然后赋值的方式,会导致内存碎片化;make_shared 的方法分配内存,不会导致内存产生过多的碎片。 T* pt = new T; std::shared_ptr<T> p(pt); 上面这段代码是先在堆上分配一块内存,然后在堆上再建一个智能指针控制块,这两个东西是不连续的,会造成内存碎片化 std::shared_ptr<T> p = std:: 2022-04-30 C & C++
new 与 malloc 的区别 | C & C++ 首先区分两个概念:new 和 operator new。new 是一个关键字,和 sizeof 一样,我们无法修改其具体功能。new 主要做三件事:调用 operator new 分配空间、初始化对象、返回指针。本文中这两个概念都有涉及,注意区分。 申请的内存所在位置new 从自由存储区上为对象动态分配内存空间,而 malloc 函数从堆上动态分配内存。特别的,new 甚至可以不为对象分配内存,使 2022-04-30 C & C++
CUDA 经典问题:矩阵乘法 | CUDA 概述关于矩阵乘法,相关的文章比较多,这里推荐这个系列: 深入浅出GPU优化系列:GEMM优化(一):矩阵乘法优化的思路 深入浅出GPU优化系列:GEMM优化(二):不使用汇编的优化方法 深入浅出GPU优化系列:GEMM优化(三):使用汇编的优化方法 本文也是参考自上述三篇文章。 代码实现Baseline__global__ void matrixMultiplyKernel(float *A, 2022-04-01 CUDA
返回值优化 | C & C++ RVO(return value optimization,返回值优化)首先看一下这一段代码: Obj fun() { return Obj(); } int main() { Obj obj = fun(); } 在编译器不进行优化的情况下,这段代码一共会调用: 1 次构造函数:对应代码 Obj() 2 次拷贝构造函数: 函数返回使用到的临时 2022-03-28 C & C++
C++ 对象内存布局 | C & C++ 虚函数表带有虚函数的类在编译时会生成一个虚表,虚表中存放着一堆指针,这些指针指向该类每一个虚函数;编译器会为每个对象生成一个虚表指针,通常在对象的地址空间的最前端,指向该类所对应的虚表。 对于这样一个类: class Base { public: virtual void f(); virtual void g(); virtual void h(); 2022-03-17 C & C++
C++ ABI 兼容 | C & C++ 什么是 ABI 兼容问题?当我们的应用程序引用了一个以二进制形式发布的库时,在源代码层面,我们使用了这个库的 API;而在编译、链接之后,在运行时,我们的应用程序通过 ABI 在与这个库通信。从这个角度看来,ABI 只是 API 的底层实现,所以多数时候我们才不需要去关心这个问题。当人们提及 ABI 兼容时,一般主要是在说 Binary-compatible 即二进制兼容性。 C++ 如何解决 A 2022-02-09 C & C++
CUDA 经典问题:前缀和 | CUDA 问题对于数组 a,其前缀和为数组 b,a 和 b 的长度均为 n。对于任意 i < n 都满足 b[i] = a[0] + a[1] + ... + a[i]。 基本思路前缀和的思路如下: 将整个数据分成几个部分,每个部分分别计算前缀和,存入数组 output 中,然后将每个部分中最大的值存入一个数组 part 中 对上述数组 part 求前缀和 将 part 中的元素分别加到 outp 2022-01-28 CUDA
CUDA 经典问题:数组归约 | CUDA 归约(reduction)是指一种解题思路,是指将某个计算问题变换为另一个问题的过程。而数据归约计算则是指使用归约的方法求一个数组总和/最大值/最小值/均值等的操作。 求和块内归约下面给出的两个例子都是仅在 block 内完成归约,并没有完整实现求数组元素加和。 使用全局内存__global__ void ReduceSumKernel(int *in, int *out) { in 2022-01-21 CUDA
CUDA 经典问题:矩阵转置 | CUDA 使用全局内存进行矩阵转置__global__ void matrix_trans_kernel(int *in, int *out) { int i = blockIdx.x * blockDim.x + threadIdx.x; int j = blockIdx.y * blockDim.y + threadIdx.y; if (i < N && j 2022-01-15 CUDA
CUDA 知识点:线程束内同步函数 __syncwarp() | CUDA 当所涉及的线程都在一个线程束内时,可以使用开销更小的线程束内同步函数 __syncwarp()。该函数的原型为: void __syncwarp(unsigned mask = 0xfffffff); 该函数有个可选的参数,该参数是一个代表掩码的无符号整型数,默认值的全部 32 个二进制位都为 1,代表线程束中的所有线程都参与同步。如果要排除一些线程,可以用一个对应的二进制位为 0 的掩码参数。 2021-10-29 CUDA
CUDA 知识点:线程束洗牌函数 | CUDA CUDA 中的线程束内基本函数包括: 线程束表决函数(warp vote functions) 线程束匹配函数(warp match functions) 线程束洗牌函数(warp shuffle functions) 线程束矩阵函数(warp matrix functions) 其中,线程束匹配函数和线程束矩阵函数都只能在 Volta 及更高架构的 GPU 中使用。本文主要介绍线程束洗牌函数 2021-10-29 CUDA
CUDA 知识点:bank 冲突 | CUDA 什么是 bank 冲突?为了获得高的内存带宽,共享内存在物理上被分为 32 个(刚好等于一个线程束中的线程数目,即内建变量 warpSize 的值)同样宽度的、能被同时访问的内存 bank。我们可以将 32 个 bank 从 0~31 编号。在每—个 bank 中又可以对其中的内存地址从 0 开始编号。为方便起见,我们将所有 bank 中编号为 0 的内存称为第 1 层内存,将所有 bank 中编 2021-10-17 CUDA
CUDA 知识点:GPU utilization 是如何计算的? | CUDA 在编写 GPU 程序时,我们经常使用 nvidia-smi 命令查看某张显卡的 GPU 利用率,那么这个利用率是如何计算的呢? 通过官方的解释可以得知:GPU 利用率是指在上个采样周期(能在 1 秒到 1/6 秒之间,取决于具体的硬件产品)中,SM(流处理器)活跃的时间比例。这里的 SM 活跃是指有任意的 SM 活跃,这就意味着可以简单地在单个 SM 上运行 kernel 函数并在 host 和 2021-09-12 CUDA
CUDA 知识点:为什么锁页内存会更快? | CUDA CUDA 驱动程序通过检查内存范围判断某个地址是锁页内存还是分页内存。锁页内存存储在物理内存中,因此 device 可以在没有 CPU 帮助的情况下获取它(通过DMA)。分页内存在通过 DMA 访问时会产生缺页中断,并且它有可能在磁盘上。在这种情况下,device 需要访问分页内存的每一页,将其拷贝到锁页内存缓冲区,然后再将其通过 DMA 一页页拷贝到 device 上。所以,使用锁页内存更快是因 2021-09-12 CUDA
11 嵌套过程调用 | 《Let’s Build A Simple Interpreter》 在当前的代码实现中,过程对应的嵌套层级被写死成了 2,对于嵌套过程调用并不适配,需要做出修改。 首先需要为符号增加表示作用域层级的成员: class Symbol: def __init__(self, name, type=None): ... self.scope_level = 0 然后当符号被添加到符号表时为其记录作用域层级: class Scop 2021-08-28 《Let’s Build A Simple Interpreter》
10 执行过程调用 | 《Let’s Build A Simple Interpreter》 本文将解读执行过程调用的代码。 创建活动记录class ARType(Enum): PROGRAM = 'PROGRAM' PROCEDURE = 'PROCEDURE' def visit_ProcedureCall(self, node): proc_name = node.proc_name ar = Activ 2021-08-28 《Let’s Build A Simple Interpreter》
09 调用栈与活动记录 | 《Let’s Build A Simple Interpreter》 为了实现统一访问全局变量和局部变量,本文将把 GLOBAL_MEMORY 字典替换成调用栈与活动记录。 调用栈调用栈一个堆栈数据结构,将类似字典的对象作为其元素,用于跟踪当前正在执行的过程/函数调用。调用栈保存的类似字典的对象称为活动记录,也被称为“堆栈帧”或者“帧”。 class CallStack: def __init__(self): self._records = 2021-08-28 《Let’s Build A Simple Interpreter》
08 识别过程调用 | 《Let’s Build A Simple Interpreter》 本文的目标是确保当解释器读取一个带有过程调用的程序时,parser 会构造一个 AST,并为过程调用构建一个新的树节点。 Parser 新增 AST 节点 class ProcedureCall(AST): def __init__(self, proc_name, actual_params, token): self.proc_name = proc_name 2021-08-28 《Let’s Build A Simple Interpreter》
07 优化与重构 | 《Let’s Build A Simple Interpreter》 为了提供更好的错误消息,指出代码中出现问题的位置,例如:SyntaxError: Unexpected token -> Token(TokenType.SEMI, ‘;’, position=23:13),需要向解释器添加一些功能,具体包括: 添加错误代码和自定义异常:LexerError、ParserError 和 SemanticError 向 Lexer 类添加新成员以帮助跟踪标记 2021-08-28 《Let’s Build A Simple Interpreter》
06 过程声明与变量作用域 | 《Let’s Build A Simple Interpreter》 过程的定义过程声明是一个定义一个标识符(过程名)的语言结构,它将该标识符与一个 Pascal 代码块关联起来。 对于 Pascal 过程和它的声明: Pascal 过程没有返回语句,它们在到达相应代码块结尾时退出 Pascal 过程可以互相嵌套 无参数过程声明语法这是本节的测试程序: PROGRAM Part12; VAR a : INTEGER; PROCEDURE P1; VAR 2021-08-22 《Let’s Build A Simple Interpreter》
05 符号表与语义分析 | 《Let’s Build A Simple Interpreter》 符号表Pascal 是一个强类型语言,所以需要确保在向一个变量赋值时,类型是正确的(类型检查),以及确保变量在使用之前被声明。为了可以在运行时对程序源码进行解释/求值之前就识别出这样的问题,我们需要跟踪程序符号。符号表就是用来跟踪程序符号的组件。符号可理解为一些程序实体的标识符,可以标识程序实体的以下信息: 名字(例如“x”、“y”、“number”等) 类别(变量、子程序或内置类型等) 类型( 2021-08-21 《Let’s Build A Simple Interpreter》
04 Pascal 语言解释器 | 《Let’s Build A Simple Interpreter》 语法以下面的示例程序为例: BEGIN BEGIN number := 2; a := number; b := 10 * a + 10 * number / 4; c := a - - b END; x := 11; END. 一个 Pascal program 由一个点号结尾的复合语句组成。下面是一个 2021-08-21 《Let’s Build A Simple Interpreter》
03 基于 AST 的四则运算解释器 | 《Let’s Build A Simple Interpreter》 IR 与 AST在上一篇文章中,interpreter 的代码和 parser 的代码是混在一起的,且 interpreter 在 parser 识别出一个如加减乘除之类的语言结构之后会立刻对它进行求值。这种 interpreter 被称为语法导向解释器(syntax-directed interpreter)。它们通常在输入上做一个 pass 且只适合基础的语言应用。为了分析更复杂的编程语言 P 2021-08-12 《Let’s Build A Simple Interpreter》
02 四则运算解释器 | 《Let’s Build A Simple Interpreter》 这篇文章将给出一个针对合法的任意长度的四则运算的解释器。 概念与术语tokentoken 是一个有类型的值的对象。例如对于字符串“3 + 4”来说,“3”是类型为 INTEGER 值为 3 的 token,“+”是类型为 PLUS 值为 + 的 token。 lexer把输入字符串拆分成 token 的过程被称为词法分析(lexical analysis)。解释器中读取输入的字符串并把他转化成 t 2021-08-10 《Let’s Build A Simple Interpreter》
01 总述 | 《Let’s Build A Simple Interpreter》 主要是系列博客 Let’s Build A Simple Interpreter 的阅读笔记。因为是笔记,所以没有原文那种由易到难循序渐进的组织,而是尽量将核心的知识点进行总结。 首先区分一下两个概念:编译器和解释器。解释器和编译器的目标都是将某种高级语言的源代码翻译成另一种形式。编译器将源代码翻译成了机器码,而解释器在处理和执行源代码之前没有把它翻译成机器码。它们的区别可以用下面这张图解释: 2021-08-09 《Let’s Build A Simple Interpreter》
TorchScript 原理篇(下) - 运行模型 | PyTorch 上一篇描述了如何生成 IR,本篇主要描述如何运行 IR。 下面是本篇分析使用的例子: // load module torch::jit::script::Module module = torch::jit::load("my_func.pt"); // run module std::vector<torch::jit::IValue> inputs; inp 2021-07-29 PyTorch
TorchScript 原理篇(上) - 保存模型 | PyTorch 注:本文是在《PyTorch 源码解读之即时编译篇》 基础之上进行了一些修正和补充。 本文涉及代码来自 PyTorch 1.9.0 (commit_id = d69c22d)。为了方便查看,格式略微有变动。TorchScript 支持 script 多种类型,为了方便了解原理,本文选用最简单的 scripted funtion 进行解读。 下面是本篇分析使用的例子: def my_func(a: 2021-07-29 PyTorch
TorchScript 踩坑篇 | PyTorch 实用技巧list、dict 对象作为 module 的成员空的 list、dict 对象是不能直接作为 module 的成员变量的,如果要用的话,需要在构造函数之前进行声明。对于非空 list、dict 对象,则可以直接在构造函数中声明。 from typing import List, Dict class Foo(torch.nn.Module): # 需要预先声明 empt 2021-07-29 PyTorch
TorchScript 入门篇 | PyTorch 简介什么是 TorchScript?这里引用官方的介绍: TorchScript 是可以由 TorchScript 编译器理解、编译和序列化的 PyTorch 模型的表示形式。从根本上说,TorchScript 本身就是一种编程语言。它是使用 PyTorch API 的 Python 的子集。 简单来说,TorchScript 软件栈可以将 Python 代码转换成 C++ 代码。TorchS 2021-07-29 PyTorch
09 高级线程管理 | 《C++ Concurrency In Action》 线程池简单的线程池作为简单的线程池,其拥有固定数量的工作线程(通常工作线程数量与 std::thread::hardware_concurrency()相同)。工作需要完成时,可以调用函数将任务挂在任务队列中。每个工作线程都会从任务队列上获取任务,然后执行这个任务,执行完成后再回来获取新的任务。线程池中线程就不需要等待其他线程完成对应任务了。如果需要等待,就需要对同步进行管理。 下面的代码展示了一 2021-07-10 《C++ Concurrency In Action》
08 并发设计 | 《C++ Concurrency In Action》 线程间划分工作递归划分快速排序有两个最基本的步骤:将数据划分到中枢元素之前或之后,然后对中枢元素之前和之后的两半数组再次进行快速排序。这里不能通过对数据的简单划分达到并行,因为只有在一次排序结束后,才能知道哪些项在中枢元素之前和之后。当要对这种算法进行并行化,很自然的会想到使用递归。每一级的递归都会多次调用 quick_sort 函数,因为需要知道哪些元素在中枢元素之前和之后。递归调用是完全独立的 2021-06-06 《C++ Concurrency In Action》
07 设计无锁的并发数据结构 | 《C++ Concurrency In Action》 定义和意义使用互斥量、条件变量,以及 future 可以用来同步算法和数据结构。调用库函数将会挂起执行线程,直到其他线程完成某个特定动作。库函数将调用阻塞操作来对线程进行阻塞,在阻塞解除前线程无法继续自己的任务。通常,操作系统会完全挂起一个阻塞线程(并将其时间片交给其他线程),直到解阻塞。“解阻塞”的方式很多,比如互斥锁解锁、通知条件变量达成,或让“future 状态”就绪。 不使用阻塞库的数据结 2021-05-01 《C++ Concurrency In Action》
06 设计基于锁的并发数据结构 | 《C++ Concurrency In Action》 基于锁的并发数据结构线程安全栈——使用锁#include <exception> struct empty_stack : std::exception { const char* what() const throw(); }; template <typename T> class threadsafe_stack { priva 2021-04-18 《C++ Concurrency In Action》
微服务性能压测 | 系统开发 HTTPQPS = 处理完成所有请求数所花费的时间 / (总请求数/并发数) ab -k -p req.json -T application/json -c 1000 -n 10000 http://127.0.0.1:8080/xxx/yyy -k:保持连接 -r:在遇到 socket 接收错误后,不退出测试 -c:并发数 -n:总请求数 -v:日志等级,例如 -v 4 GRPCghz 2021-04-06 系统开发
05 内存模型和原子操作 | 《C++ Concurrency In Action》 原子操作和原子类型标准原子类型标准原子类型定义在头文件 中。这些类型的操作都是原子的,语言定义中只有这些类型的操作是原子的,也可以用互斥锁来模拟原子操作。标准原子类型的实现可能是这样的:它们几乎都有一个is_lock_free() 成员函数,这个函数可以让用户查询某原子类型的操作是直接用的原子指令(x.is_lock_free() 返回 true),还是内部用了一个锁结构(x.is_lock_f 2021-04-04 《C++ Concurrency In Action》
04 同步操作 | 《C++ Concurrency In Action》 等待事件或条件等待条件达成C++ 标准库对条件变量有两套实现:std::condition_variable 和 std::condition_variable_any,这两个实现都包含在 condition_variable.h 头文件的声明中。两者都需要与互斥量一起才能工作,前者仅能与 std::mutex 一起工作,而后者可以和合适的互斥量一起工作,从而加上了 _any 的后缀。因为std: 2021-03-17 《C++ Concurrency In Action》
03 共享数据 | 《C++ Concurrency In Action》 使用互斥量不推荐直接去调用 std::mutex 的成员函数,调用其成员函数就意味着必须在每个函数出口都要去调用 unlock()(包括异常的情况)。C++ 标准库为互斥量提供了 RAII 模板类 std::lock_guard,在构造时就能提供已锁的互斥量,并在析构时进行解锁,从而保证了互斥量能被正确解锁。某些情况下使用全局变量没问题,但大多数情况下,互斥量通常会与需要保护的数据放在同一类中,而 2021-03-14 《C++ Concurrency In Action》
CUDA 知识点:流与并发执行 | CUDA CUDA 流表示一个 GPU 操作队列,同一个流中的操作将以添加到流中的先后顺序而依次执行,不同流可以并行执行。可以将流类比成 CPU 编程中的“线程”的概念(注意不是 CUDA 编程概念中的线程):同一个“线程”中的任务串行执行,不同“线程”可以并行执行。 使用 CUDA 流,首先要选择一个支持设备 overlap 功能的设备,支持设备重叠功能的 GPU 能够在执行一个 CUDA 核函数的同时, 2021-01-28 CUDA
CUDA 知识点:性能分析 | CUDA 调试 CUDA 程序性能会用到的性能分析工具:nvvp & nvprof、NSight System。 nvvp & nvprof使用方法nvvp 是 nvprof 的 GUI 版本,都可以直接分析 CUDA 程序。在一般的使用场景下,分析 CUDA 程序有以下两个办法: 在服务端使用 nvprof 在命令行查看分析结果 nvprof ./main 在本地使用 nvvp 分析导出 2021-01-28 CUDA
全局构造函数在静态链接时为什么不生效? | C & C++ 隐式注册全局构造函数可以用来完成隐式注册功能(全局构造函即全局对象的构造函数)。 这个需求来源于对异构设备函数的管理。我需要在一个全局 map 中分别注册 CpuDevice、GpuDevice 两种内存管理类。我的目的是在不需要 GPU 的时候不链接相关的库,这样我不仅需要在 cmake 文件中做条件判断,还需要在显式调用注册函数的地方通过编译选项做条件判断。因此在扩展新的设备类型时,需要在至少 2021-01-10 C & C++
02 线程管理 | 《C++ Concurrency In Action》 线程管理基础特殊情况下的等待异常捕捉当在线程运行后产生的异常,会在 join() 调用之前抛出,这样就会跳过 join()。避免应用被抛出的异常所终止。通常,在无异常的情况下使用 join() 时,需要在异常处理过程中调用 join(),从而避免生命周期的问题。 void f() { func my_func(); std::thread t(my_func); 2020-12-21 《C++ Concurrency In Action》
OpenCV 如何实现双线性插值缩放 | 系统开发 背景最近在做一些视觉算法的跨平台移植,视觉算法移植中的一个环节是数据对齐,就是保证对于相同图片的输入,不同平台程序输出的结果是一致的。视觉算法整个流程可以分为三步:前处理、网络推理、后处理。其中后处理多是一些算法强相关逻辑,多为代码直接实现,移植难度不大(直接复制过来即可)。网络推理部分的数据对齐性则由负责推理引擎开发的同学保证。这样一来,我的关注点则多在如何正确的实现和原来平台行为一致的预处理操 2020-12-20 系统开发
01 概述 | 《C++ Concurrency In Action》 本系列笔记参考《C++ Concurrency in Action, 2nd Edition》及其中文翻译。 并行与并发并行指的是任务在物理上同时执行,并发指的是在任务在逻辑上同时执行。例如,在单核处理器上执行多个任务,处理器会通过快速切换时间片使多个任务看起来像是在同时执行,这便是并发;将多个任务分别分配到不同的处理器核上进行,这些任务在物理上是同时执行的,这便是并行。 随着多核处理器的普及, 2020-12-13 《C++ Concurrency In Action》
CUDA C++ 编程指引:其他运行时特性 | CUDA 初始化运行时库没有显式的初始化函数,在调用第一个函数时会自动初始化(除了错误处理和版本管理函数)。初始化时,会为每个设备生成一个所有主机线程可见的上下文。当主机端调用了 cudaDeviceReset() 函数,则会销毁掉该主机线程正在操作的设备的上下文。 进程间通信线程间通讯,可以很方便的通过共享内存的变量来实现。然而进程间通讯不行。 为了在进程间共享设备端内存的指针或者事件,必须使用 IPC 2020-11-28 CUDA
CUDA C++ 编程指引:多设备系统 | CUDA 枚举设备主机系统上可以有多个设备。下面的代码展示了怎样枚举这些设备、查询它们的属性、确定有多少个支持 CUDA 的设备。 int deviceCount; cudaGetDeviceCount(&deviceCount); int device; for (device = 0; device < deviceCount; ++device) { cudaDevic 2020-11-28 CUDA
CUDA C++ 编程指引:异步并发执行 | CUDA 并发行为CUDA 允许以下操作彼此之间并发执行: 主机端计算 设备端计算(内核函数执行) 主机端到设备端传输数据 设备端到主机端传输数据 设备端内部传输数据 设备间传数据 主机端/设备端并发执行为了易于使用主机和设备间的异步执行,一些函数是异步的:在设备完全完成任务前,控制权已经返回给主机线程了。包括: 内核函数执行(可以通过将 CUDA_LAUNCH_BLOCKING 设为 1,来禁用内核 2020-11-28 CUDA
CUDA C++ 编程指引:内存层级 | CUDA 设备内存运行时库提供了分配、释放、拷贝设备内存以及在设备和主机间传输数据的函数。这里的设备内存,指的是全局内存 + 常量内存 + 纹理内存。这张图很好地展示了内存结构: 设备内存分为线性内存和 CUDA 数组。CUDA 数组是不透明的内存布局,为纹理获取做了优化。线性内存可以用 cudaMalloc() 分配内存,用 cudaFree() 释放内存,用 cudaMemcpy() 复制数据,用 c 2020-11-28 CUDA
CUDA C++ 编程指引:编译 | CUDA 离线编译nvcc 可编译同时包含主机代码和设备代码: 分离主机和设备代码; 将设备代码编译成汇编形式(PTX 代码),再编译为二进制形式(cubin); 将 <<<...>>> 中的代码转化为 CUDA 运行库中的函数调用; nvcc 会借助其他编译器将主机端代码编译出来; 主机端代码和设备端代码被编译好后,nvcc 会将两段代码链接起来。 在线编译如果在编 2020-11-28 CUDA
CUDA C++ 编程指引:硬件实现 | CUDA SIMT 架构根据计算机历史上有名的的费林分类法(Flynn’s Taxonomy),如下图所示计算机体系架构可以简单分为四类,分别是: 单一指令流单一数据流计算机(SISD, Single Instruction Single Data) 单一指令流多数据流计算机(SIMD, Single Instruction Multiple Data) 多指令流单一数据流计算机(MISD, Multip 2020-11-28 CUDA
CUDA C++ 编程指引:编程模型 | CUDA 可扩展的编程模型使得已编译好的 CUDA 程序能够在任意核心的 GPU 上执行。 内核函数下面这段代码通过语法 <<<...>>> 指定使用 N 个线程去执行 VecAdd 函数,每个执行内核函数的线程拥有一个独一无二的线程 ID,可以通过内置的 threadIdx 变量在内核函数中访问。限定符 __global__ 声明某函数为内核函数,在设备上执行,只能从主 2020-11-28 CUDA
在腾讯云上部署博客 | 个人博客 配置关于页 配置服务器安全策略 在腾讯云产品界面搜索并选择“安全组” 新建安全组 3, 添加入站规则 添加出站规则 实例应用安全策略 安装配置 Nginx 安装 Nginx yum install -y nginx 建立博客目录 mkdir /root/hexo 添加 /root/hexo/index.html 用于检测配置 Nginx 是否成功 <! 2020-11-08 个人博客
个人域名备案 | 个人博客 对于想在国内建立个人网站的人来说,购买域名只是第一步,想要在国内使用这个域名还需要进行备案。域名在国内备案需要两步:管局备案和公安备案。本文主要介绍这两个备案的流程和注意事项。 前提条件需要有一台服务器。使用自己的服务器也可以,但是需要稳定的公网 IP,这就要看你的网络运营商了,这个流程我不太了解,此处不做阐述。这里推荐使用云厂商提供的云服务器服务,如果认证了学生身份就可以买到很便宜的云服务器,虽 2020-11-08 个人博客
使用 gperf 分析内存和 CPU | 系统开发 使用 gperf 工具查看内存和 CPU 使用情况,先以分析内存为例介绍整个流程。 内存安装yum install google-perftools yum install graphviz ghostscript # 输出 PDF 需要用到 运行# 配置 export LD_PRELOAD=libtcmalloc.so export HEAPPROFILESIGNAL=12 # 发送该信号以 2020-11-05 系统开发
OpenCV 常用操作 | C & C++ 遍历像素点for (int i = 0; i < mat.rows; ++i) { for (int j = 0; j < mat.cols; ++j) { std::cout << (float)mat.at<cv::Vec3b>(i,j)[0] << std::endl; std::co 2020-10-18 C & C++
模板的全特化与偏特化 | C & C++ 模板机制为 C++ 提供了泛型编程的方式,在减少代码冗余的同时仍然可以提供类型安全。特化必须在同一命名空间下进行,可以特化类模板也可以特化函数模板,但类模板可以偏特化和全特化,而函数模板只能全特化。C++ 的模板机制被证明是图灵完备的,即可以通过模板元编程(template meta programming)的方式在编译期做任何计算。 模板的声明类模板和函数模板的声明方式是一样的,在类定义/模板定 2020-08-31 C & C++
条款 41 - 条款 52 | 《Effictive C++》 Effictive C++ 条款 41 - 条款 52。 条款 41:了解隐式接口和编译期多态 类和模板都支持接口和多态 对类言接口是显式的,是通过函数签名实现的:函数签名描述了函数的参数和返回值;多态则是通过虚函数发生于运行期 对模板而言接口是隐式的,是通过有效表达式实现的:使用模板的表达式规定了该模板具有什么成员函数(比如表达式 T.ShowName() 则表明了模板 T 具有名为 ShowN 2020-08-30 《Effictive C++》
条款 31 - 条款 40 | 《Effictive C++》 Effictive C++ 条款 31 - 条款 40。 条款 31:将文件间的编译依存关系降至最低(接口与实现分离)如果类 A 的成员为另一个类 B 而非 B 的指针,那么当这个 B 的代码发生变动的时候 A 也要重新编译,这是因为编译 A 的时候需要申请和分配其成员的内存,如果其成员的内容发生变化,A 的内存结构也会改变,需要重新编译。如果将 B 换成 B 的指针,则对于上述情况就不需要重新编 2020-08-30 《Effictive C++》
条款 21 - 条款 30 | 《Effictive C++》 Effictive C++ 条款 21 - 条款 30。 条款 21:必须返回对象时,别妄想返回其 reference不要返回指针或引用指向一个局部静态对象。 条款 22:将成员变量声明为 privateprotected 并不比 public 更具封装性。 假设我们有一个 protected 成员变量,而我们最终取消了它,所有使用它的派生类都会被破坏,所以 protected 成员变量就像 pu 2020-08-30 《Effictive C++》
条款 11 - 条款 20 | 《Effictive C++》 Effictive C++ 条款 11 - 条款 20。 条款 11:在 operator= 中处理“自我赋值”确保当对象自我赋值时 operator= 有良好行为,应当保证有自我赋值安全性和异常安全性。 自我赋值不安全,异常不安全的实现(pb 会指向一个被删除的对象): Widget& Widget::operator=(const Widget& rhs) { 2020-08-30 《Effictive C++》
条款 01 - 条款 10 | 《Effictive C++》 Effictive C++ 条款 01 - 条款 25。 条款 01:视 C++ 为一个语言联邦C++ 并不是一个带有一组守则的一体语言,而是从四个次语言组成的联邦政府,每个次语言都有自己的规约。四个次语言包括: C Object-Oriented C++ Template C++ STL 条款 02:尽量以 const, enum, inline 替换 #define(宁愿以编译器替换预处理 2020-08-30 《Effictive C++》
源码编译 clang | C & C++ 从源码编译 clang,clang 可以用于 VS Code 后端以及支持 clang-format。 下载代码从官网这边下载源代码,包括以下四个文件: LLVM source code Clang source code Clang Tools Extra source code Compiler RT source code 注:可以在官网下载到的且支持 gcc 4.8.5 的 llvm 2020-08-09 C & C++
单例模式 | C & C++ 单例模式是使用最广泛的设计模式之一,其目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。 Eager Singletonclass Singleton { public: static Singleton& GetInstance() { return instance; } private: Singleto 2020-08-07 C & C++
CMake 指令、技巧与错误 | C & C++ 指令find_packagefind_package 的作用就是寻找第三方模块的头文件目录和库文件路径,并将其设为变量,返回提供给 CMakeLists.txt 其他部分使用。 find_package 首先会寻找并执行模块相关的 .cmake 文件。寻找顺序如下: 在寻找模块的时候显式指定了模块目录:find_package(${module_name} REQUIRED 2020-07-14 C & C++
Git 常用指令 | 系统开发 [TOC] 开发过程中常用的 Git 指令总结。 全局设置用户名和邮箱git config --global user.name "your_name" git config --global user.email "your_email@email.com" 协作开发# 拉取远程分支代码 git clone -b https://github.com/ 2020-07-09 系统开发
李沐:基于系统和算法的协同设计的大规模分布式机器学习 | 系统开发 这是李沐的基于系统和算法的协同设计的大规模分布式机器学习课程的笔记。 大规模机器学习问题内容 挑战 有限的通信带宽(远小于内存带宽) 巨大的同步开销 任务失败问题:任务跑得越久,被更优先级的任务抢占资源的概率就越大 需要解决的问题 分布式系统 处理大数据、复杂的模型 容灾 易用 大规模优化方法 高效的通信 保证好的收敛性 本文主要内容 分布式系统参数服务器架构 任务分割:将训练数据分 2020-06-12 系统开发
bthread | bRPC bthread 是一个 M:N 线程库,M:N 是指 M 个 bthread 会映射至 N 个pthread,一般 M 远大于 N。由于 linux 当下的 pthread 实现(NPTL)是 1:1 的,M 个 bthread 也相当于映射至 N 个 LWP。 之所以要采用这么一种 M:N 的机制,是为了兼顾当前多核 CPU 以及调度竞争上,考虑两种极端情况,一是每个用户线程对应一个内核线程,如 2020-05-26 bRPC
bvar | bRPC bvar 是多线程环境下的计数器类库,方便记录和查看用户程序中的各类数值。 特性 bvar 不能代替所有的计数器,它的本质是把写时的竞争转移到了读:读时需要合并所有写过的线程中的数据, 而不可避免地变慢了,所以读写都很频繁或需要基于最新值做一些逻辑判断时,不应该使用 bvar。 当很多线程都在累加一个计数器时,每个线程只累加私有的变量而不参与全局竞争,在读取时累加所有线程的私有变量。虽然读比之前慢 2020-05-19 bRPC
Shell 常用指令 | 系统开发 字符串处理(awk)# 打印列信息 cat bench_log.txt | grep "Time used" | awk '{ print $(NF-1) }' # $NF 表示倒数第一列,$(NF-1) 表示倒数第二列 # 求均值 cat bench_log.txt | grep "Forward time cost&quo 2020-03-06 系统开发
多路复用 IO 模型中的函数 | 计算机基础 多路复用 IO 模型中的函数介绍。 select它仅仅知道了,有 IO 事件发生了,却并不知道是哪几个流(可能有一个,多个,甚至全部),所以只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以 select 具有O(n) 的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。 select 本质上是通过设置或者检查存放 fd 标志位的数据结构来进行下一步处理。这样所带 2020-03-01 计算机基础
网络 IO 模型 | 计算机基础 为了解决网络 IO 中的问题,学者们提出了 4 种网络 IO 模型: 阻塞 IO 模型、非阻塞 IO 模型、多路 IO 复用模型和异步 IO 模型。 阻塞 IO 模型大部分的 socket 接口都是阻塞型的。所谓阻塞型接口是指系统调用时(一般是 IO 接口)却不返回调用结果,并让当前线程一直处于阻塞状态只有当该系统调用获得结果或者超时出错时才返回结果。 实际上,除非特别指定,几乎所有的 IO 接口 2020-03-01 计算机基础
HTTPS | 计算机基础 HTTPS 简介。 浏览器在使用 HTTPS 传输数据的流程 首先客户端通过 URL 访问服务器建立 SSL 连接 服务端收到客户端请求后,会将网站支持的证书信息(证书中包含公钥)传送一份给客户端 客户端和服务器开始协商 SSL 连接的安全等级,也就是信息加密的等级 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站 服务器利用自己的私钥解密出会话密 2020-03-01 计算机基础
TCP 拥塞控制 | 计算机基础 TCP 的拥塞控制由 4 个核心算法组成:慢开始、 拥塞避免、快速重传和快速恢复。 慢开始发送方维持一个叫作拥塞窗口 cwnd (congestion window)的状态变量(注意区分发送窗口)。 拥塞窗口的大小取决于网络的拥塞程度, 并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的接收能力,发送窗口可能小于拥塞窗口。 慢开始算法的思路就 是,不要一开始就发送大量的数据, 2020-03-01 计算机基础
TCP 协议的三次握手和四次挥手 | 计算机基础 TCP 是一种面向连接的单播协议,在发送数据前,通信双方必须在彼此间建立一条连接。所谓的“连接”,其实是客户端和服务器的内存里保存的一份关于对方的信息,如 IP 地址、端口号等。TCP 可以看成是一种字节流,它会处理 IP 层或以下的层的丢包、重复以及错误问题。在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在 TCP 头部。TCP 提供了一种可靠、面向连接、字节流、传输层的服务,采 2020-03-01 计算机基础
svg 导出为指定分辨率的 pdf | Swift 以文本形式打开 svg 文件,修改 height 和 width 项,将其改成想要的分辨率,然后使用 AI 等矢量图编辑软件导出到 pdf 即可。 2020-02-09 Swift
调用 C++ | Swift Swift 不能直接调用 C++,需要通过 Objective-C/C++ 桥接。本文主要介绍了在 Swift 中调用 C++ 的一些技巧。 调用函数 新建 C++ 文件,勾选生成头文件。// CPPFile.hpp #include <stdio.h> class TestCPP { public: int add(int a, int b); }; 2020-02-04 Swift
常用操作 | Swift 发送本地通知// 发送通知 func sendNotification(title: String, subtitle: String = "", informativeText: String = "") { let userNotification = NSUserNotification() userNotification. 2020-02-03 Swift
延迟执行 | Swift 阻塞当前线程 sleep(5) 新建一个线程 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) { // do something } 2020-01-31 Swift
搜索引擎优化(SEO) | 个人博客 不同于在各大博客平台上写博客,自建博客想要在搜索引擎上被搜索到还是需要做一些工作。如果你的博客是部署在 Github Pages 上,在不用国内 CDN 的情况是无法被在百度上被检索到的,这是由于 GitHub 屏蔽了百度的爬虫,导致百度无法抓取 GitHub 上的内容。 Google验证网站所有权在 Google Search Console - 所有权 中进行所有权验证。 方法一:通过 HTM 2020-01-29 个人博客
判断 Mac 是否处于密码输入界面 | Swift 最近搞了一个人脸解锁 mac 的程序 FaceLock,其中需要判断 Mac 是否处于密码输入界面,为了正确识别这个状态,需要对锁屏相关的几种状态变化做一个梳理。 系统睡眠、屏幕睡眠、屏保程序、密码输入界面和锁屏之间的关系严格来讲,系统睡眠、屏幕睡眠、屏保程序、输入密码界面都属于锁屏,至少从系统事件角度来看是这样的:如果监测 com.apple.screenIsLocked 事件,进入以上四种状态 2020-01-29 Swift
SystemC 矩阵乘法 | Noxim 使用 SystemC 完成矩阵乘法。 向量乘法SC_MODULE(vector_mul) { // 端口定义 sc_in<bool> clk, rst_n; sc_in<sc_int<WIDTH> > vec1[KK], vec2[KK]; sc_out<sc_int<WIDTH * 2> > v 2020-01-07 Noxim
使用 EverBlog 发布印象笔记到博客 | 个人博客 整个发布流程分为两步:1. 从印象笔记中获取笔记内容;2. 发布笔记。对于第一个步骤,有两种方法:一种是通过印象笔记的 JavaScript SDK 从服务器获取笔记内容,一种是通过 JXA(JavaScript for Automation)从印象笔记客户端获取笔记内容。两者都各有优缺点:前者跨平台,但是印象笔记的 token 有时效性(7 天),需要经常申请,比较麻烦,而且 API 有拉取次数 2020-01-05 个人博客
SystemC 基础 | Noxim SystemC 是一个系统级软/硬件协同设计语言,用 SystemC 可以很方便地实现一个软件算法的硬件实现,以及完成一个系统级的设计。SystemC 是 C++ 的一个第三方库,有着 C++ 的很多语法特性,学习成本较低。本文主要介绍 SystemC 的一些基本语法。 模块 (module)模块是 SystemC 设计中的基本设计单元。模块可以使得设计者将一个复杂的系统分割为一些更小但易于管理的 2020-01-03 Noxim
iOS 常用越狱插件 | 玩机 iOS 13 Bytafont 3 - 更换英文字体 http://repo.bytafont.com/latest 最好配合 Bytafont Tweak mode 进行使用 使用 iFonts 安装字体(可从 App store 获取) Shadow - 屏蔽越狱检测 http://ios.jjolano.me Snapper 2 - 增强截图功能 Big Boss CCVPN 2020-01-01 玩机
在 GitHub 上部署博客 | 个人博客 Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。 环境安装 安装 node.js 安装 Hexonpm install -g hexo 创建静态博客mkdir your_blog cd your_blog hexo init hexo s # 本地预览 Github 设置创建仓库在github上创 2019-12-26 个人博客
基础架构 | Noxim 介绍 Noxim 的主要架构。 Tile Node = PE + Router 一般使用网格结构 每个 tile 包含一个路由器和一个 PE 每个非边界 tile 连接东南西北四个临近的 tile (可选)当允许无线传输时,一些节点可以和 Radio-hub 相连 Wormhole & Flits 从源到目的地的传输过程中,每个中间节点无法存储数据包 需要很多 buffer 会有存储 2019-12-25 Noxim
XY 路由算法 | Noxim 介绍 Noxim 中常用的 XY 路由算法 XY 路由算法路由算法确定数据分组在网络中按照何种路径从源节点传输到目的节点。通常简答的路由器采用的都是 XY 维序路由算法,该算法是一种确定性路由算法,只要给定源地址与目的地址,就能唯一确定条路由路径。它将网络中所有路由器都用一个二维坐标 (X,Y) 表示,分组中的地址信息也是用二维坐标 (X,Y) 表示。 设当前路由器的坐标为 (cur_x,cur_ 2019-12-25 Noxim
配置文件 default_config.yaml 解析 | Noxim # Simple default config of a 4x4 mesh # Each parameter is overwritten when corresponding command line value is set # # NOC & WIRED CONFIGURATION NOC基本设置 # # Topologies: # MESH # BUTTERFLY # 2019-12-24 Noxim
编译与运行 | Noxim 使用两种方式(二进制安装和源码编译)在 Linux 和 macOS 上安装 Noxim。 直接安装(Linux)wget --no-check-certificate https://raw.githubusercontent.com/davidepatti/noxim/master/other/setup/ubuntu.sh export LD_LIBRARY_PATH=$LD_LIBRARY 2019-12-24 Noxim
11 文件系统 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 基本概念 文件系统:种用于持久性存储的系统抽象 分配文件磁盘空间 管理文件块(哪一块属于哪一个文件) 管理空闲空间(哪一块是空闲的) 分配算法(策略) 管理文件集合 定位文件及其内容 命名:通过名字找到文件的接口 最常见:分层文件系统 文件系统类型(组织文件的不同方式) 提供 2019-10-20 《操作系统》
线程同步方法 | 计算机基础 自旋锁while (抢锁(lock) == 没抢到) {} // 只要没有锁上,就不断重试 互斥锁while (抢锁(lock) == 没抢到) { 本线程先去睡了请在这把锁的状态发生改变时再唤醒(lock); } 操作系统负责线程调度,为了实现「锁的状态发生改变时再唤醒」就需要把锁也交给操作系统管理。所以互斥锁的加锁操作通常都需要涉及到上下文切换 2019-07-28 计算机基础
10 进程间通信 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 概述(Inter Process Communication, IPC) 直接通信与间接通信 直接通信 进程必须正确的命名对方: send(P, message) - 发送信息到进程 P receive(Q, message) - 从进程 Q 接受消息 通信链路的属性 自动建立 2019-05-22 《操作系统》
09 死锁 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 死锁问题 一组阻塞的进程持有一种资源等待获取另一个进程所占有的一个资源 系统模型 可重复使用的资源 在一个时间只能一个进程使用且不能被删除 进程获得资源,后来释放由其他进程重用 处理器、I/O 通道、主和副存储器、设备和数据结构,如文件、数据库和信号量 如果每个进程拥有一个资源并请 2019-05-19 《操作系统》
08 信号量与管程 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 信号量 抽象数据类型 一个整型(sem),两个原子操作 P(): sem 减 1,如果 sem<0,等待,否则继续 V(): sem 加 1,如果 sem<=0,唤醒一个等待的 P 信号量类似铁路 初始化 2 个资源控制信号灯 信号量使用 信号量是有符号整数 2019-05-19 《操作系统》
07 同步 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 一些概念 Race Condition(竞态条件) 系统缺陷:结果依赖于并发执行或者事件的顺序/时间 不确定性 不可重现 如何避免竞态 让指令不被打断 Atomic Operation(原子操作) 原子操作是指一次不存在任何中断或者失败的执行 该执行成功结束 或者根本没有 2019-05-19 《操作系统》
06 调度 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 背景 上下文切换 切换 CPU 的当前任务,从一个进程/线程到另一个 保存当前进程/线程在 PCB/TCP 中的执行上下文(CPU 状态) 读取下一个进程/线程的上下文 CPU 调度 从就绪队列中挑选一个进程/线程作为 CPU 将要运行的下一个进程/线程 调度程序:挑选进程/线程 2019-05-17 《操作系统》
05 进程与线程 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 进程描述(静态) 进程的定义 一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程 进程的特点 动态性:可动态地创建、结束进程 并发性:进程可以被独立调度并占用处理机运行;并发并行 独立性:不同进程的工作不相互影响 制约性:因访问共享数据/资源或进程间同步而产生制约 2019-05-17 《操作系统》
04 虚拟内存 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 起因 在计算机系统中,尤其是在多道程序运行的环境下,可能会出现内存不够用的情况,怎么办? 如果是程序太大,超过了内存的容量,可以采用手动的覆盖(overlay)技术,只把需要的指令和数据保存在内存当中 如果是程序太多,超过了内存的容量,可以采用自动的交换(swapping)技术,把 2019-05-17 《操作系统》
03 内存分配 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 概述 操作系统在内存管理方面的任务 抽象:逻辑地址空间 保护:独立地址空间 共享:访问相同内存 虚拟化:更多的地址空间 在操作系统中管理内存的不同方法 程序重定位 分段 分页 虚拟内存 按需分页虚拟内存 连续内存分配:地址空间与地址生成 地址空间定义 物理地址空间:硬件支持 2019-05-17 《操作系统》
02 启动、中断、异常和系统调用 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 主要模块的分布 内存 BIOS:位于主板上一个芯片内,加电后率先放入内存 硬盘 OS BootLoader:一般位于位于第一个硬盘的第一个主引导扇区 图中地址为 BIOS 的位置 加电后执行的任务 POST (Power On Self Test,加电自检) 执行 BIO 2019-05-17 《操作系统》
01 概述 | 《操作系统》 这一系列是操作系统 (清华大学向勇、陈渝)视频课的课堂笔记,主要是课堂 PPT 和部分讲授内容的文字版,仅供参考。 操作系统内核的特征 并发(同一时间点有多个程序运行) 计算机系统中同时存在多个运行的程序需要 OS 管理和调度 共享 “同时”访问 互斥共享 虚拟 利用多道程序设计技术,让每个用户都觉得有一个计算机专门为他服务 异步 程序的执行不是一贯到底,而是走走停停,向前推进的速度不 2019-05-17 《操作系统》
Tmux | 玩机 Install tmux on rhel/centos 7# install deps yum install -y kernel-devel ncurses-devel # download sources for libecent and make and install curl -OL https://github.com/libevent/libevent/releases/downl 2019-03-28 玩机