群论(一)
时隔多年,重新回来学习群论。一方面是最近有些迷茫,一方面是感慨 LLM 在辅助学习上的强大。
商群、陪集
陪集的概念还好,但是其中的这个等价关系 ,其实我以前并没有那么摸得着头脑(或者说当年根本没有认真去想的欲望了,残念)。其实最常见的等价关系当然就是同余,但是同余我们通常使用加法而不是乘法的记号,所以看上去没那么显然。因为群上没有整数那样的取余运算,所以所谓的同余,比如看这个子群 ,同余就是说 ,而 用乘法的符号表示就是 。所以这里的 其实就是两者的差(商)。
时隔多年,重新回来学习群论。一方面是最近有些迷茫,一方面是感慨 LLM 在辅助学习上的强大。
陪集的概念还好,但是其中的这个等价关系 ,其实我以前并没有那么摸得着头脑(或者说当年根本没有认真去想的欲望了,残念)。其实最常见的等价关系当然就是同余,但是同余我们通常使用加法而不是乘法的记号,所以看上去没那么显然。因为群上没有整数那样的取余运算,所以所谓的同余,比如看这个子群 ,同余就是说 ,而 用乘法的符号表示就是 。所以这里的 其实就是两者的差(商)。
记录一个快两年前修过的 bug。
当时 .NET 6 快要 end of life 了,我们把一个服务从 .NET 6 升级到了 .NET 8。升级之后,有用户报了一个看起来不太相关的数据异常 bug。一番略过不表的定位之后,发现问题的根源是其中一个 .NET 和 C++ 的交互面错误地使用了不同的 bool 数据长度,.NET 使用了默认的 4 字节,但是 C++ 期待的是 1 字节,因此高 3 个字节里的未初始化脏数据导致了数据异常。
不过我真正想分享的是后面多问的这一句:为什么之前没有用户报告这个问题,而且结果还挺稳定,但是升级到 .NET 8 之后,很快就有用户报了问题?到底为什么 .NET 6 下这个 bool 长度不匹配没有导致问题,但是 .NET 8 就会出问题?
有段时间没有在这个 blog 上写文章了,主要原因还是最近代码阅读相关的总结要不就直接写到代码注释,要不就用 Karpathy 的 LLM Wiki 来整理,所以也没啥机会写新的博客文章。
我感觉 LLM Wiki 这套模式在借助 LLM 学习的场景下还挺合适的。用在代码阅读上也没什么问题,只需要稍微调整一下他原始提出的 source,用 code commit + source location 代替 source file,就能很好地支持代码阅读的记录。
我倒是把我的 LLM Wiki 保存到了 GitHub 上,不过考虑到内容大多由 LLM 生成,其中很多是没有经过我手动整理,所以目前还是 private repo 的状态。我再考虑考虑后面要不要公开,先放一个链接在这里。等哪天它不再 404,可以去看看:wiki。
Update:我把其中一部分内容渲染成了一个静态站点放在了 LLM Wiki,可以去看看效果。需要说明的是,里面的内容大多由 LLM 生成,并未经过我逐条人工校对,更适合作为通过 LLM 进行提问、检索和延展阅读的素材。这个站点本身主要是用来展示 LLM wiki 这种形式渲染出来的效果,实际使用场景下我觉得更适合作为本地的个人或团队 wiki 来部署。
之前看了 Mesa 的早期版本实现之后,我又开始看 Mesa 的最近版本的 OpenGL 实现了。不过,只能说有点选择错误,OpenGL 的实现实在是有太多历史包袱,驱动有非常多替应用层做的处理、回退逻辑。其中掺杂了大量固定管线(Fixed-function pipeline)时代的遗留代码,非 OpenGL Core profile 的部分也很影响阅读体验。所以我想先转去看 Vulkan 的实现,但是在此之前,想先总结一下 framebuffer 相关的一些阅读内容:一方面算是梳理了 OpenGL 底层的一些结构;另一方面,Framebuffer 的概念在 Vulkan 中也有对应的设计,这也为后续学习 Vulkan 打下基础。
在 Mesa 中,gl_framebuffer 主要包含多个 gl_renderbuffer 作为附件 (Attachment),可以想象成 Framebuffer 有多个插槽,每个插槽可以绑定到具体的 Renderbuffer 或 Texture。
对于 default framebuffer,即关联到 Window System 的 framebuffer 有:
而 user defined framebuffer 有:
在以前的 Linux 环境下, OpenGL 库的加载存在一个问题:多个厂商的实现没法很好地共存。具体来说,应用会用 libGL.so 这个 SONAME 去加载 OpenGL 实现,但是动态加载器的搜索路径通常是固定的(当然可以通过修改环境变量之类的方式去改变哪个 libGL.so 被加载,但是这样的方式是不现实的),因此以前没法很好地让多个厂商的实现并存,无法让多个进程选择不同的实现,甚至动态地去决定用哪个厂商的实现。
为此,现代 Linux 下的 libGL.so 的实现通常是由 libglvnd (The GL Vendor-Neutral Dispatch library) 实现的。这个实现允许多个厂商的 OpenGL 实现同时存在于机器上,允许多个进程动态地选择具体的实现。
它通过实现一个中心化的 libGL.so + 不同厂商提供的 libGLX_{vendor}.so, 根据 context 转发到对应厂商提供的 GL/GLX 实现,从而解决上述提到的问题。
┌───────────────────────────┐
│ Application │
└─────┬────────────────────┬┘
│ │
│ │
glXGetProcAddress glxxx return from glXGetProcAddress
┌─────▾────────────┐ ┌─▾────────────────┐
│ libGL ├─────▸ libGLdispatch │
└─────┬─────────┬──┘ └─┬────────────────┘
│ gl functions ┌────────────────────┐
│ └──────────┴───▸ libGLX_{vendor}.so │
glXxxx(Display*, ...) └─▴──────────────────┘
┌─────▾────────────┐ glX extension function
│ libGLX ├─────────────┘ ┌────────┐
│ ├───────────────▸ libX11 │
└──────────────────┘ └────────┘