找回密码
 -注册-
查看: 6609|回复: 59
打印 上一主题 下一主题

全内存播放开发笔记

[复制链接]
跳转到指定楼层
1
发表于 2024-3-3 17:46 | 只看该作者 回帖奖励 |正序浏览 |阅读模式 来自 北京
本帖最后由 中关村东路 于 2024-3-3 20:20 编辑

全内存播放开发笔记

内存的速度和延迟都远优于各种形式的硬盘,流行的Linux音乐发行版,如GentooPlayer,HQplayer OS,AudioLinux, Euphony都提供内存系统功能,把整个操作系统都放到内存中。本帖回顾主流内存系统的实现,讨论前三者的优劣,之后简要介绍我实现并开源的另外一种方案【1】。Euphony做的比较粗糙我不喜欢没深入用过,不过从网页介绍【2】来看和AudioLinux原理相同。

【1】https://github.com/zhjie/ramroot
【2】https://euphony-audio.com/hesk/knowledgebase.php?article=14
【3】http://erji.net/forum.php?mod=viewthread&tid=2253401&extra=
【4】http://erji.net/forum.php?mod=viewthread&tid=2272124&extra=
【5】https://github.com/arcmags/ramroot
【6】http://erji.net/forum.php?mod=viewthread&tid=2284715&extra=


来自 2楼
 楼主| 发表于 2024-3-3 17:46 | 只看该作者 来自 北京
1. GentooPlayer的tmpfs方案

在我之前的帖子《Roon系统硬核安装笔记》【3】中,介绍了GentooPlayer方案的内存系统实现。大致原理是先挂载tmpfs的目录,从根目录把整个系统文件同步过去,之后再通过mount -o bind命令用新的内存目录覆盖掉原磁盘目录,这样读写的就都是内存中的tmpfs了。不过这种实现有两个问题,一个是尽管我在【3】中提出了让磁盘自动休眠的方案,但磁盘事实依然是无法umount的,如果这时候把盘拔下来再去访问根目录就会出问题——不够优雅。二是整个系统会load两次——依然是不够优雅,而且消耗很大。虽然我自己的电脑上长期都用这套方案,不过总想折腾出一个漂亮一些的实现。

【3】http://erji.net/forum.php?mod=vi ... =2253401&extra=

回复

使用道具 举报

来自 3楼
 楼主| 发表于 2024-3-3 17:46 | 只看该作者 来自 北京
2. HQplayer OS的initramfs方案

Initramfs不是新鲜技术了,原理是在系统正式启动到根目录之前,先启动到一个比较小的cpio格式的initramfs.img里,同时会把这个img完全load到tmpfs中。这是内核自身提供的功能,原设计是用来维护raid啊,光盘启动啊,网络启动啊,zfs/unionfs啊,等等特殊设备的,在initramfs中折腾好这些设备之后再boot到实际系统中。HQplayer OS就用这个方案直接把整个最终系统都写入这个initramfs.img中,只不过最后并没有boot进实际硬盘,而是在initramfs里直接用hqplayerd了。这套方案逻辑上是没有问题的,但实际用起来就会比较麻烦了,因为整个系统都在生成initramfs.img的时候被固定住了无法修改,别说新增软件了,就是改个密码,改个主机名,增加个ssh公钥都麻烦。当然也都能,就是真的麻烦,感兴趣的详见我在本站的帖子【4】。

【4】http://erji.net/forum.php?mod=vi ... =2272124&extra=

回复

使用道具 举报

来自 4楼
 楼主| 发表于 2024-3-3 17:46 | 只看该作者 来自 北京
3. AudioLinux的zram+initramfs方案

今年春节前我阅读了AudioLinux的内存系统代码,不是他自己开发的,而是用了开源的【5】。这段代码实现的很工程师很漂亮,流传度也很高,和ArchLinux高度耦合,换成其他系统是不能运行的。但这并不是让我不满意的原因。这套方案基于zram,也是把工作放在了initramfs里。大致原理是,在initramfs中先用zram生成一个大小为一半内存的块设备,之后把这个块设备当成一个普通磁盘,分区,格式化,再把实际硬盘数据同步到这个块设备的根分区上来,最后boot到这个块设备而不是硬盘。看起来是不是很优雅,但这套方案有个不漂亮的地方,那就是块设备,比如磁盘啊,tf卡啊,一般都是低速设备,在Linux下会被缓存起来,算是充分利用硬件吧。不过这套方案里的块设备实际上却是内存,也就相当于给内存再缓存一遍内存。这就不仅是不优雅了,本来读一条数据,从内存读过就可以了,现在要读了之后再写入内存缓存中一份,消耗加倍了还要多,从性能上要远低于前两种方案,可以说是非常不科学了。

【5】https://github.com/arcmags/ramroot

回复

使用道具 举报

来自 5楼
 楼主| 发表于 2024-3-3 17:47 | 只看该作者 来自 北京
4. 我实现并开源的tmpfs+initramfs方案

读者读到这里应该已经能想到我的方案【1】了吧,那就是在initramfs中,不生成块设备zram,而是生成一个tmpfs作为最终的根目录。是不是听起来很简单?其实实现起来更简单。我的源里核心代码有三个文件,init, ramdisk.sh, gen_initramfs-ARCH.sh。

4.1. init

init文件,是initramfs.img的入口,修改或编写这个文件是本方案的核心。我的init文件修改自/usr/share/genkernel/defaults/linuxrc,是gentopo的内核编译软件genkernel提供的gentoo默认脚本。如果你用的是archlinux,应该看/usr/lib/initcpio/init。源里init文件最后几行代码是我写的,做的事情是用tmpfs生成一个占用一半系统内存的/ram_chroot,从/mnt/.ramdisk文件夹同步根目录数据。如果你的内存很大能轻松容纳整个磁盘,也可以直接从磁盘根目录同步过来。我的/mnt/.ramdisk文件夹是在ramdisk.sh中生成的,生成的时候把系统中一些没什么用的文件夹去掉了。最后一句switch_root之后,系统就boot到内存系统中了。注意下面脚本在启动之前先umount了实际硬盘,这也是从原理到性能都优于GentooPlayer方案的地方。

  1. mkdir /ram_chroot
  2. mount -t tmpfs -o rw,noatime none /ram_chroot
  3. cp -a "${CHROOT}"/mnt/.ramdisk/* /ram_chroot/

  4. mount --move /proc /ram_chroot/proc
  5. mount --move /sys /ram_chroot/sys
  6. mount --move /dev /ram_chroot/dev

  7. umount ${CHROOT}

  8. good_msg "Switching to real root: switch_root /ram_chroot ${init} ${init_opts}"
  9. exec switch_root /ram_chroot "${init}"
复制代码


4.2. ramdisk.sh

ramdisk.sh其实是可有可无的,生成一个小一些新的root_fs放在/mnt/.ramdisk/,exclude掉了一些没用又占空间的文件,比如/usr/src内核源码等等。主要是因为我的树莓派只有2g内存,虽然也足够把整个系统都同步过来,不过为了战未来还是写了这段脚本。需要指出的是,我的系统中/bin /lib /lib64 /sbin四个目录是软链接的,并没同步过去,如果你的系统原本不是软链接就全同步过去。总之让/mnt/.ramdisk看起来和/基本上一样就好了,注意不要把/mnt自己也同步过去了。

4.3. gen_initramfs-ARCH.sh

树莓派和x86我是分开写的,主要是因为树莓派用config.txt控制启动入口,x86我用了grub控制启动入口。我同时提供了如下树莓派的config.txt,意思是kernel/initramfs的文件名分别是kernel和initramfs,你如果不喜欢我的口味可以按需改脚本,注意别改followkernel这个是关键字。


  1. kernel kernel
  2. initramfs initramfs followkernel
复制代码


gen_initramfs-ARCH.sh文件一共要做三件事:先mount了/boot分区,该删除删除该备份备份,之后从服务器把交叉编译生成的内核文件同步到/boot,如果你是本地编译就不需要这步了;之后把刚刚出炉的initramfs解压缩,把init文件替换为我们刚刚改好的那个,再重新打包回initramfs.img;最后把这个文件部署到/boot分区,配置grub等等启动项。以x86/grub为例,现在boot到新生成的这个initramfs.img就是内存启动,boot到编译生成的那个就是硬盘启动。需要指出两点,一个是这段脚本中我利用了genkernel的一个配置生成了一个名为kernel的内核链接,和一个名为initramfs的initramfs.img链接;一个是我在编译内核时用的xz压缩。如果你不喜欢这种设置可能需要对应修改自己的代码。

4.4. 关于是否成功执行

启动系统之后执行df,如果你的根目录类型是none或者tmpfs就对了。更进一步还可以执行mount命令不用参数,可以看到目前mount的所有目录中没有磁盘。注意曾经mount过的磁盘是不能再次mount的,这个方案也允许用户自己执行mount /dev/sda2 /mnt; mount /dev/sda1 /mnt/boot 这种命令。

4.5. 关于日常维护

逻辑上,直接boot到刚刚生成的磁盘分区就可以日常维护了,不过实际上有更简单的办法。直接boot到内存系统中,用mount命令把磁盘挂载起来,之后用我在本站的帖子【6】中介绍的chroot方法,就可以直接进入硬盘系统使用包管理软件进行软件安装了,记得最后执行ramdisk.sh同步一下即可。

【1】https://github.com/zhjie/ramroot
【6】http://erji.net/forum.php?mod=vi ... =2284715&extra=



回复

使用道具 举报

来自 6楼
 楼主| 发表于 2024-3-3 17:48 | 只看该作者 来自 北京
5. 小结

本帖简要回顾了目前流行的tmpfs方案,initramfs方案和zram方案三种内存系统实现,介绍了我实现并开源的tmpfs+initramfs方案。如果对你有用,欢迎回帖讨论支持。

也再次重申,我不是科学派,不是玄学派,不排斥线材,也不排斥指标,但本帖只讨论方案,不讨论听感。请不要以听不出来之类为由在本帖下攻击我或网友。另外,我并不是程序员只是一个普通理工男,代码供自己使用,方案完全开源免费分享给大家,具体如何应用到读者的机器或者产品中需要你自己斟酌。


回复

使用道具 举报

来自 28楼
 楼主| 发表于 2024-3-11 16:04 | 只看该作者 来自 北京
lalekuku 发表于 2024-3-11 14:08
明白了。
我的是arm板子,还没想出软件层面给emmc或tf卡断电的办法,
automagic内核的arm源码能用来 ...

其实是可以切断的,

  1. echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmcblk/unbind
复制代码


回复

使用道具 举报

60
发表于 2024-6-11 20:17 | 只看该作者 来自 北京
中关村东路 发表于 2024-6-11 19:37
是个目录,感兴趣的话搜一下initramfs,很老的技术

我去学习一下
回复

使用道具 举报

59
 楼主| 发表于 2024-6-11 19:37 | 只看该作者 来自 北京
lalekuku 发表于 2024-6-11 18:27
感谢!看上去比较高深,学习了。
最后一行是启动新系统,那么运行这几行脚本代码的系统去哪里了?
看上 ...

是个目录,感兴趣的话搜一下initramfs,很老的技术
回复

使用道具 举报

58
发表于 2024-6-11 18:27 | 只看该作者 来自 北京
本帖最后由 lalekuku 于 2024-6-11 18:54 编辑
中关村东路 发表于 2024-6-10 22:12
第三行,${CHROOT} 就是tf卡。/ram_chroot/是tmpfs,也就是内存。把tf卡复制之后,在倒数第三行umoun ...

感谢!看上去比较高深,学习了。
最后一行是启动新系统,那么运行这几行脚本代码的系统去哪里了?
看上去${CHROOT} 是个变量,它代表的真实设备是什么名?比如类似于我板子上的/dev/mmcblk0p1这样的块设备?那么我直接umount这个设备可以吗?

试了试umount /dev/mmcblk0p1,不提示错误,但好像也没效果。umount /dev/mmcblk0的话提示not mounted。
回复

使用道具 举报

57
 楼主| 发表于 2024-6-10 22:12 | 只看该作者 来自 北京
lalekuku 发表于 2024-6-10 21:30
如果在启动系统之前就已经umount tf卡了,为啥我刷在tf卡上的系统能正常启动?这是啥原理?[/ba ...
  1. mkdir /ram_chroot
  2. mount -t tmpfs -o rw,noatime none /ram_chroot
  3. cp -a "${CHROOT}"/mnt/.ramdisk/* /ram_chroot/

  4. mount --move /proc /ram_chroot/proc
  5. mount --move /sys /ram_chroot/sys
  6. mount --move /dev /ram_chroot/dev

  7. umount ${CHROOT}

  8. good_msg "Switching to real root: switch_root /ram_chroot ${init} ${init_opts}"
  9. exec switch_root /ram_chroot "${init}"
复制代码


第三行,${CHROOT} 就是tf卡。/ram_chroot/是tmpfs,也就是内存。把tf卡复制之后,在倒数第三行umount,最后一行启动系统
回复

使用道具 举报

56
发表于 2024-6-10 21:30 | 只看该作者 来自 北京
中关村东路 发表于 2024-6-10 20:43
你如果用的是我的脚本,在启动系统之前就已经umount tf卡和emmc了,只不过没关掉pci设备的供电

如果在启动系统之前就已经umount tf卡了,为啥我刷在tf卡上的系统能正常启动?这是啥原理?

umount tf卡的脚本在哪个文件里?想学习一下
回复

使用道具 举报

55
 楼主| 发表于 2024-6-10 20:43 | 只看该作者 来自 北京
lalekuku 发表于 2024-6-10 15:35
还需要umount啊?我这个板子只能用外置tf卡启动,没有内置emmc。该怎么umount  tf卡?

你如果用的是我的脚本,在启动系统之前就已经umount tf卡和emmc了,只不过没关掉pci设备的供电
回复

使用道具 举报

54
发表于 2024-6-10 15:35 | 只看该作者 来自 北京
中关村东路 发表于 2024-6-10 14:19
umount之后就可以直接拔tf卡了。这段代码切断的不是tf的电源,是读卡器的电源

还需要umount啊?我这个板子只能用外置tf卡启动,没有内置emmc。该怎么umount  tf卡?
回复

使用道具 举报

53
 楼主| 发表于 2024-6-10 14:19 | 只看该作者 来自 北京
lalekuku 发表于 2024-6-10 11:44
再次请教。上面这个切断tf卡电源的方法(echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmcblk/unbind),是 ...

umount之后就可以直接拔tf卡了。这段代码切断的不是tf的电源,是读卡器的电源
回复

使用道具 举报

52
发表于 2024-6-10 11:44 | 只看该作者 来自 北京
本帖最后由 lalekuku 于 2024-6-10 12:09 编辑
中关村东路 发表于 2024-3-11 16:04
其实是可以切断的,

再次请教。上面这个切断tf卡电源的方法(echo -n mmc0:0001 > /sys/bus/mmc/drivers/mmcblk/unbind),是从系统解绑mmc设备,确实好使。
那么解绑是否就意味着不再供电?毕竟设备一直插着。
解绑后可以拔掉TF卡吗?会不会损坏?不敢轻易动手。

由于内存空间有限,我没有把所有目录放入内存,还留了一些我认为不会再使用的目录在TF卡上。
解绑后目前NAA播放正常,暂时没有错误
回复

使用道具 举报

51
发表于 2024-3-26 16:25 | 只看该作者 来自 北京
中关村东路 发表于 2024-3-24 13:19
纠结了一下还是打算comment一句。

我在绿檀和github开源的一系列方案,一方面是让更多感兴趣的折腾型烧 ...

大佬的技术贴我基本全都看过,受益匪浅,感谢付出
回复

使用道具 举报

50
 楼主| 发表于 2024-3-24 13:19 来自手机 | 只看该作者 来自 北京
本帖最后由 中关村东路 于 2024-3-24 13:21 编辑

纠结了一下还是打算comment一句。

我在绿檀和github开源的一系列方案,一方面是让更多感兴趣的折腾型烧友了解技术细节,另一方面也是希望免费提供给国内厂家一些思路。据我所知,是帮到过一些国外公司和国内外烧友的。

有些公司找过我要交钥匙方案,我说的是我一方面不是程序员没这实力,另一方面成本上双方都不会接受,但帖子和代码都公开细节了,论坛和git上我也都有问必答,花点时间很容易就可以攒到自己系统。

还有一些在各种地点表现出奇怪的行为,有说自己早就用了我所有这些技术的(不是说pna,高总只是没认真看帖子。。),有说我杞人忧天他们公司不会有这些问题的。我想说的是,很丢脸。
回复

使用道具 举报

49
 楼主| 发表于 2024-3-24 12:45 来自手机 | 只看该作者 来自 北京
andygaof 发表于 2024-3-24 09:09
CelWare从4年前开始就一直是内存运行,内存播放,但是仍然摆脱不了硬盘的影响。基于自研赛耳之心主板的这 ...

高总没看内容吧,我这个全内存是拆掉硬盘运行的,硬盘还影响什么呢……
回复

使用道具 举报

48
发表于 2024-3-24 09:09 | 只看该作者 来自 北京
huangshun839500 发表于 2024-3-3 20:32
你让那些能听出不同硬盘声音的骚友肿么办

CelWare从4年前开始就一直是内存运行,内存播放,但是仍然摆脱不了硬盘的影响。基于自研赛耳之心主板的这一代产品,硬盘的影响愈加明显了。而且A硬盘加X内存比B硬盘声音好,不代表A硬盘加Y内存也比B硬盘好。测试了20多种硬盘加内存的组合才定型了新一代NS的硬盘和内存。

整体感觉上,你的系统越强,越敏感,一些原来认为不是问题的因素就会变得是问题。例如你优化了交换机,然后发现原来换线电给光猫影响有,但是也没那么大,换了牛逼交换机和数播后,发现原来光猫的影响这么大。
回复

使用道具 举报

47
 楼主| 发表于 2024-3-24 01:58 | 只看该作者 来自 北京
本帖最后由 中关村东路 于 2024-3-24 01:59 编辑
Victor_Derbobo 发表于 2024-3-23 19:26
请教一个技术问题:

线电带华擎j3455+矩声usb卡 naa/cm4 roon ready

是,华擎j3455用做hqplayer的naa。否,矩声pcie转usb卡就是一个ti芯片的usb口,不过加了个时钟加了线性供电。是,梅是dac直连usb。

我主力系统有两个网桥,另外一个是树莓派compute module 4(cm4),加一个主板算是一个自己攒的arm电脑,或者理解为diy的树莓派4b吧。用一些手段可以通过roon ready认证,也输出给梅。

我平时听音乐习惯是按专辑听,如果是高码率pcm就直接用roon ready输出给解码,如果是44.1/16或者dsd就用hqplayer升频到dsd1024。
回复

使用道具 举报

46
发表于 2024-3-24 00:13 | 只看该作者 来自 中国
太强了
回复

使用道具 举报

45
发表于 2024-3-23 23:44 | 只看该作者 来自 中国
中关村东路 发表于 2024-3-23 16:01
你说的肯定是对的,最终肯定是要被载入到内存里才能被播放的...但这个载入过程就会导致大几个数量级的延 ...

受教了,多谢
回复

使用道具 举报

44
发表于 2024-3-23 19:26 | 只看该作者 来自 中国
中关村东路 发表于 2024-3-23 00:36
我就是业余瞎玩,很多基础的东西都不懂用到什么学什么。

主系统是i3 10105, 96g, 光纤网卡的roon core ...

请教一个技术问题:

线电带华擎j3455+矩声usb卡 naa/cm4 roon ready

这里我确认一下我的理解是否正确:
硬件:
华擎主机是充当NAA的角色
后面接了一块矩声的USB卡做界面?(这里不确定)
再往后就是梅做DAC

cm4是指的什么?

软件方面,roon ready是指的软件对吗(我看当下很多市售数播有提到这个)?它是装在华擎主机里,还是装在矩声机器里?

敬请解惑,谢谢!!!
回复

使用道具 举报

43
 楼主| 发表于 2024-3-23 19:03 | 只看该作者 来自 北京
Victor_Derbobo 发表于 2024-3-23 17:03
4090。。。豪!

我后面打算去学习Linux。因为根据我自己的观察,Daphile虽然好,但是还得是把Linux弄 ...

多交流
回复

使用道具 举报

42
发表于 2024-3-23 17:03 | 只看该作者 来自 中国
中关村东路 发表于 2024-3-23 00:36
我就是业余瞎玩,很多基础的东西都不懂用到什么学什么。

主系统是i3 10105, 96g, 光纤网卡的roon core ...

4090。。。豪!

我后面打算去学习Linux。因为根据我自己的观察,Daphile虽然好,但是还得是把Linux弄熟悉,才能更上一层楼。有问题再来请教您。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | -注册-

本版积分规则

Archiver|手机版|粤icp备09046054号|耳机网-耳机大家坛

粤公网安备 44030602000598号 耳机大家坛、www.erji.net、网站LOGO图形均为注册商标

GMT+8, 2024-12-25 00:36

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表