JJ's blog

群论(一)

时隔多年,重新回来学习群论。一方面是最近有些迷茫,一方面是感慨 LLM 在辅助学习上的强大。

商群、陪集

陪集的概念还好,但是其中的这个等价关系 a∼b  ⟺  a−1b∈Ha \sim b \iff a^{-1}b \in H,其实我以前并没有那么摸得着头脑(或者说当年根本没有认真去想的欲望了,残念)。其实最常见的等价关系当然就是同余,但是同余我们通常使用加法而不是乘法的记号,所以看上去没那么显然。因为群上没有整数那样的取余运算,所以所谓的同余,比如看这个子群 3Z3\mathbb{Z},同余就是说 b−a∈3Zb - a \in 3\mathbb{Z},而 b−a=−a+bb - a = -a + b 用乘法的符号表示就是 a−1ba^{-1}b。所以这里的 a−1ba^{-1}b 其实就是两者的差(商)。

Read more...

为什么一个老 P/Invoke bool bug 在 .NET 8 才暴露:一次关于 SkipLocalsInit 优化的追查

记录一个快两年前修过的 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 就会出问题?

Read more...

关于 LLM Wiki

• edited

有段时间没有在这个 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/OpenGL 源码分析:framebuffer

之前看了 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 有:

  1. Double Buffer 机制: 用于 Window System 的 framebuffer 包含 front / back 缓冲(如果是立体视觉 stereo 模式,还会叠加 left / right 组合)。
  2. Depth / Stencil Buffers: 深度与模板缓冲。

而 user defined framebuffer 有:

  1. Color Buffers: 支持 Multiple Render Targets (MRT) 的 color0-7。

Read more...

libglvnd 实现分析

在以前的 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 │
└──────────────────┘               └────────┘

Read more...