March 23, 2023

继续学习神经网络

这段时间忙游戏项目之外,继续花了几天学习神经网络。

上一篇 blog 发布以后,收到了图灵的朋友的 email 。然后,我收到了一大堆(九本)图灵出版的关于人工智能的中文书。通常出版社的同学给我邮寄新书,或多或少是希望我能写点什么。我不想刻意帮人宣传新书,但倒是不介意推荐一些我自己读过的不少的东西。

这次收到的书太多,当然没有全部读完。但书的内容相关性都很强(差不多一个主题)。去年的时候,我读了《如何阅读一本书》,里面提到读书的四个层次。第四个层次就是就一个主题同时读多本书是非常有意义的。这次,我也颇有收获。

阅读全文 "继续学习神经网络" »

March 08, 2023

学习神经网络的一点笔记

最近 AI 很火。我从读书的时候就对 AI 有兴趣,90 年代的时候读过一本关于神经网络的书。但当时没有能力完全理解。2000 年初刚毕业那会儿想搞明白点,又研究过一段时间。了解了很多相关知识,感觉自己弄明白了,但却没有真正动手实践过。

现在,所有人都看得到,AI 已经变成了一个可以真正帮助我们提高生产力的工具了。我觉得有必要好好学习一下。我并不期望几篇文章就可以搞清楚,那样只会让自己好像懂了,和人聊天估计够用,想理解它还是得自己动手。真正写几段代码,才有触碰的感觉,明白别人到底在解决什么问题。

一开始,我是从维基百科的 Machine learning 开始读的。顺着看了一整天,了解了近年发展的脉络。好多词条,乱七八糟的笔记记了一大堆,感觉快消化不了了。疑问也积累了很多,觉得看下去效率会越来越低。不如换一条路。

然后我开始读 Neural Networks and Deep Learning 这本书。读了两章后,我想,手写数字识别看起来是一个非常好的实践手段,不如自己写一遍最快。有这么一个基础,后面可以继续修修补补,沿着前人的轨迹走一下,可以更好的理解为什么。

阅读全文 "学习神经网络的一点笔记" »

February 14, 2023

Aura 一个嵌入式小语言

上周看到了 Redis 作者的新玩具语言 Aocla ,感觉很有启发。它是 FORTH 和 Lisp 的杂合体,又增加了一些内嵌局部变量的支持。非常像我前两年给我们数学库做的一个小东西。最初的想法是为数学库设计一个 DSL 潜入 Lua ,在做复杂的数学计算过程时,可以把计算过程停留在 C Side ,减少 Lua 和 C 之间的边界成本。最初的版本是我模仿 FORTH 设计的基于栈的小语言。希望牺牲一些表达能力,换取一点性能。但实用起来过于别扭,后来又增加了一些特性却没有本质改进。最后终于决定把这个 DSL 彻底从数学库中剥离了

阅读全文 "Aura 一个嵌入式小语言" »

February 06, 2023

同一 Entity 包含多个同类 Component 的问题

ECS 中,同一个 Entity 是否可以由多个同类型的 Component 构成?在 Unity 中,答案是可以。我们的引擎在设计之初也是可以的。

当时有一个问题:在 Lua 中,如何访问同类型的 Component ?如果有多个同类 Component ,最自然的方式是把它们放在一个数组里。但是、绝大多数情况下我们用不上这个特性,每次访问 Component 都加一次 [1] 或 [0] 的数组索引显得画蛇添足。若单个 Component 不用数组,多个才用数组,写起来又有极大的心智负担。因为这样做,它们就成了两个不同的类型。

后来,我们干脆利用 Lua 的特性,把数组和 Component 本身放在一个 table 中。如果有多个 Component 就把这个数组直接放在第一个 Component 的 table 内。就这样用了一段时间后,最后还是受不了这个脏技巧。等到用 C 编写 luaecs 后,就砍掉了这个特性。

ECS 不是万能灵药。如果需要让相同的 Component 聚合在一起,那么就使用额外的数据结构,或是不只使用一个 world 。这是我们目前实践给出的答案。去年在 luaecs 的 issue 9 也讨论过类似问题。

阅读全文 "同一 Entity 包含多个同类 Component 的问题" »

January 20, 2023

最近开发中解决的一些性能问题

今天是年前最后一天工作,我想对最近做的一些事情做一些记录。

我们在使用自研引擎开发游戏时,遇到了不少和预期设计有距离的问题,针对问题再反思了原有的设计并做出改进。我认为、凭空设计一个通用游戏引擎是不可能的,必须结合实际项目,做许多针对性的实现。但同时应不断反思,避免过多的技术债。在最近一年,我参与的引擎具体编码工作很少,更多的是站在一个反思者位置,监督代码和设计的演变。

我们的引擎主体框架是基于 Lua 的,受益于 Lua 的动态性,可以很方便的把各个模块粘合在一起。但是、Lua 和 C/C++ 相比,又有两个数量级的性能差异,对于渲染代码而言,若将和 GPU 沟通的 API 完全放在 Lua 的 binding 层,对于对象数量巨大的场合,很容易出现性能问题。我估计、在手机环境这个“巨大” 差不多在 10K 这个数量级吧,而 PC 环境还能支撑到 100K 左右。

Lua 项目的优化无非两条路:使用 jit 技术、把热移到 C side 。正如 Roberto 所言,"Finally, keep in mind that those two options are somewhat incompatible" 这两条路需要的操作往往是互斥的。而我不喜欢 jit 带来的复杂度和不确定性,所以选择了后者。

为了解决大数量对象的批量操作问题,我在 2021 年进入了 luaecs 。这个库现在已经是引擎的核心,专门用来解决 Lua 处理大数据重复事务的性能问题。通过 luaecs ,我们可以把对象的初始化这个繁杂的过程使用 Lua 编写,而每帧都迭代的事务用 C 来实现。

一般来说,如果 10K 是场景可渲染对象的数目的话,那么对于很多游戏场景还是适用的。但如果Lua 调用的图形 API 放在太底层,手机上(以 Apple 的 A9 芯片为下线)一个流畅的场景却很难支撑到 10K 对象。这是因为,每个可渲染对象需要一系列参数传到图形 API 层,设置 VB/IB 渲染状态,尤其是大量的 uniform ,这些 API 差不多会在 10 个调用左右,它们会吃掉一个数量级,最终 Lua 层能流畅处理的数量大约只剩下 1K 左右了。

阅读全文 "最近开发中解决的一些性能问题" »

January 10, 2023

虚拟文件系统的 mod 机制

上次谈游戏引擎的虚拟文件系统是去年 10 月了。最近我们又做了一些修改。

我们的虚拟文件系统有两个工作模式。一种模式主要用于编辑器和开发环境,所有的文件名和路径都基于原生文件系统,我们叫它编辑器模式;另一种模式被称为运行时模式,主要用于运行时环境。文件均用类似 git 仓库的形式,用文件内容的 hash 值作文件名,储存在一颗 Merkle tree 上,并通过一个专门的 file server 为运行环境提供资源的更新服务。

在编辑器模式下,并不是直接映射原生文件系统的整棵目录树的,而是增加了一个 mount 配置,可以把很多不同的目录装配在一起。当初这么设计是希望提供一定的灵活度,方便游戏项目可以把引擎提供的基础功能和资源组装进来。

阅读全文 "虚拟文件系统的 mod 机制" »

December 20, 2022

covid-19 感染康复记录

月初还和同事调侃,这次谁也躲不掉,感染是迟早的事。最近全家都中招了,好在病毒这次还算轻柔,差不多都痊愈了。在此记录一下这次的历程。

起点是广州的全面开放。老婆在家已经被关了快一个月,憋得不行。开放第一个周末,就约了同事出去玩,周五晚上密室、周日下午(12 月 11 日)出去拍照。

我觉得广州已经放开,这次病毒的 R0 相当高,快速传播开无可避免,第一个周末外出有非常大的风险。所以取消了原本每个周末的攀岩活动,和两个孩子继续关在家中。儿子一直有点咳嗽,我有一些感冒,有流鼻涕的症状。

Day 0 (12 月 12 日周一)

老婆被通知一起玩的同事已经确诊,需要她居家办公,观察一天再考虑回办公室。

我当天正常上班了。这天我之前的感冒症状(流鼻涕)已经完全消失,精神状态非常好。

晚上她有一点低烧(38 度),自测抗原阴性,觉得是因为感冒。这一晚,女儿和妈妈睡觉。

阅读全文 "covid-19 感染康复记录" »

December 13, 2022

触摸屏上的一些交互设计问题

我们现在制作的游戏以手机优先,交互都是围绕着触摸屏来做。如果开发的时候总是在 PC 上用鼠标测试,很多交互问题都容易被忽视掉。所以,我们自研的引擎花了很大气力在手机设备上即改即所得。在开发时推荐开发人员直接在手机上修改、调试。这样更容易发掘出平时用鼠标操作难以察觉的问题。

btw,直接在手机上开发比在 PC 上开发还有另一个好处,就是随时能关注画面元素(尤其是字体)的大小是否合适。

阅读全文 "触摸屏上的一些交互设计问题" »

November 21, 2022

间断储存的字符串

绝大部分的基础数据结构都是定长的,很容易针对优化它们的内存管理。但字符串是一个例外。

内存管理和其它资源管理有明显的不同。管理内存有点像切蛋糕,从整块蛋糕上切下需要的那块,但归还的时候却因为支离破碎难以合并起来满足后续用途。举个极端的例子:如果内存堆有 2G 大小,如果碰巧在正中间分配了几个字节而从未释放,这个堆就被永久的分成了两个不足 1G 的分片。之后再无可能从这个 2G 大小的堆中分配出 1G 的内存块。

改进内存分配算法或许可以减轻内存碎片的危害,但即使是在此方面做了相当多努力的 jemalloc ,其表现也大大低于一般用户的预期。以我的经验,一个 16G 的内存堆,对于长期运行,需要大量反复分配释放内存的程序,通常能做到 10G 左右的峰值有效内存占用就不错了。这里说的有效内存使用,指你调用 malloc 传入的字节数之和。根据应用程序使用内存的方式不同,这个数字会有很大的不同。

60% 的内存使用率其实已经很好了,但还是会有很多人问,我的内存都去哪了?

阅读全文 "间断储存的字符串" »

November 17, 2022

skynet 1.6.0

最近半个月,因为广州防疫政策,我一直居家办公。找了点时间,给 skynet 做了一年一度的 release 。

这次的 1.6.0 版,相比去年的 1.5.0 版,没有太大的变化。主要是平时积累的一些 bugfix 。它所依赖的第三方库,例如 Lua , jemalloc 我都更新到了最新的版本。

值得一提的是,mongo 的 driver 也更新了。因为 mongo 在最新的版本中已经淘汰了旧的 wire protocol ,如果再不更新,就无法连接新版 mongo server 了。具体讨论可以参看 PR #1649 。因为 mongo 自己的设计原因,我们无法给出一个同时兼容新老版本协议的方案。从这点来看,我个人认为 redis 的底层协议设计就稳定的多。 这么多年更迭基本不需要修改。

阅读全文 "skynet 1.6.0" »

November 09, 2022

被干眼症结膜炎困扰的这几年

这几年我一直被干眼症和结膜炎困扰。疫情之前,每次洗澡后就双眼通红。但似乎并无其他影响,也没怎么在意。后来慢慢的,眼睛就容易发干,经常疲劳。严重的时候眼睛几乎睁不开。最受影响是在开车的时候,因为无法休息眼睛,特别难受。到晚上环境光线不足的时候,感觉远处看不清楚。

然后,视力突然断崖式下降。三年时间,每年体检,从 1.2 直落 0.7 左右。而我在 35 岁之前一直是双眼 1.5 的视力。本来 2020 年就想约眼科医生看看的,因为疫情去看五官科不方便就一直拖着,直到 2021 年底才去看了医生。

初步诊断结果是结膜炎、干眼症、视疲劳。另外,验光结果表明我有 150 度近视加 50 度散光。因为并不影响日常生活,便没有配眼镜。而且,我的视力是时好时坏。从办公室眺望珠江对面的楼顶招牌时,有时那些字清晰可见,有时则是重影。我感觉如果以后能解决干眼症和结膜炎的话,视力能稳定一些。

阅读全文 "被干眼症结膜炎困扰的这几年" »

October 17, 2022

电信宽带 ipv6 折腾记

周末在家里折腾 BT 下载,发现 UPnP 无法工作,便去光猫那里看看是什么情况。

我发现现在电信宽带默认已经是由光猫来拨号,家中的路由器是作为一个二级路由在使用,如果想让 UPnP 或 DMZ 工作起来,需要在光猫里设置。

查看光猫设备上印的默认管理员密码登录上去,没有找到太多设置选项。在网上搜了一下,需要一个超级管理员身份才能看到全部设置菜单。一般的说法是打电话问一下装宽带的师傅,但天色已晚,不想麻烦人。转念一想,有这么多家宽带设备要管理,电信应该用的是统一密码,或是有一些简单手段可以拿到这个密码才对。否则建立一整套管理系统成本实在太高了。

阅读全文 "电信宽带 ipv6 折腾记" »

October 08, 2022

引擎 IO 模块的变化和发展

我们游戏引擎的 IO 模块其实一直在修改。最初的版本到现在有四年多了

一直没有定稿的一部分原因是因为我们给引擎设定了一个比较高的需求:引擎本身也是可以从网络自更新的。而更新引擎本身必然依赖 IO ,包括 IO 模块自身。而我们引擎又基于一个多线程版本的 Lua 框架 ltask ,ltask 本身也是需要依赖 IO 模块启动的。这些后续的设计要晚于最初 IO 模块的设计,反复重构也就是必然了。

阅读全文 "引擎 IO 模块的变化和发展" »

Misc

Categories

Archives

Recent Comments