为什么Linux内核需要15+百万行代码?[关闭]


109

这个整体代码库的内容是什么?

我了解处理器体系结构的支持,安全性和虚拟化,但是我无法想象它超过60万条。

内核代码库中包含哪些历史和当前原因驱动程序?

那15+百万行是否包括每个硬件的每个驱动程序?如果是这样,那就引出了一个问题:为什么驱动程序嵌入在内核中,而不是将自动检测和安装的程序包与硬件ID分开?

对于存储受限或内存受限的设备,代码库的大小是否成问题?

如果所有这些内容都嵌入了,似乎会占用空间有限的ARM设备的内核大小。预处理器会剔除很多行吗?叫我疯了,但是我无法想象一台机器需要那么多的逻辑来运行我所了解的内核功能。

是否有证据表明,由于其不断增长的性质,其大小将在50多年后成为问题?

包含驱动程序意味着它将随着硬件制造而增长。

编辑:对于那些认为这是内核的本质的人,经过一些研究,我意识到并非总是如此。不需要这么大的内核,因为卡内基·梅隆(Carnegie Mellon)的微内核马赫(Mach)被列为示例,“通常在10,000行代码下”


9
早在2012年,仅司机就拥有500万条线路。190万条线用于支持不同的处理器体系结构。更多信息h-online.com/open/features/…–
史蒂夫

11
是的,我已经为一种语言编写了编译器,词法分析器和字节码生成器,并且正在进行完整的编码和递归操作,并且不需要10,000行。
乔纳森

5
(现在看,大约有2700条线)
乔纳森(Jonathan

4
您应该下载并配置,make menuconfig以查看在构建之前可以启用/禁用多少代码。
casey 2015年

6
@JonathanLeaders:我已经用不到100行的语言编写了用于LISP的完整编译器(如语言),并使用了渲染Mandelbrots的测试程序。始终视情况而定。
phresnel

Answers:


43

驱动程序维护在内核中,因此当内核更改需要对函数的所有用户进行全局搜索和替换(或搜索并手动修改)时,更改人员将完成更改。由人们进行API更改来更新驱动程序是一个很好的优势,而不是当它没有在较新的内核上编译时就必须自己动手。

备选方案(对于在树外维护的驱动程序会发生这种情况)是,补丁必须由其维护者重新同步以跟上任何更改。

快速搜索引发了关于树内驱动程序与树外驱动程序开发的争论

Linux的维护方式主要是将所有内容保留在主线存储库中。用来控制#ifdefs的config选项支持构建小型精简内核。因此,您绝对可以构建精简的精简内核,这些精简内核仅在整个存储库中编译一小部分代码。

Linux在嵌入式系统中的广泛使用已为Linux提供了更好的支持,因为它早于内核源代码树较小的几年前的Linux。超级最小4.0内核可能小于超级最小2.4.0内核。


4
现在,这对于为什么将所有代码整合在一起是合乎逻辑的,对我来说很有意义,它以节省计算机资源和过多依赖关系为代价来节省工时。
乔纳森(Jonathan)

8
@JonathanLeaders:是的,它避免了维护不太活跃的驾驶员的麻烦。考虑核心更改时,将所有驱动程序代码都包含在内可能也很有用。搜索某些内部API的所有调用程序可能会以您未曾想到的方式使用它,从而可能会驱动您正在考虑的更改。
彼得·科德斯

1
@jonathanLeaders出现在xd上,好像多余的行占用了很多额外的空间一样,在现代的测量中将其安装在PC上。
Junaga '16

3
@Junaga:您意识到linux具有很高的可移植性和可扩展性,对吗?在32MB嵌入式系统上浪费1MB永久使用的内核内存是一件大事。源代码的大小并不重要,但是编译后的二进制大小仍然很重要。内核内存不会分页,因此即使有了交换空间,您也无法找回它。
彼得·科德斯

1
@Rolf:很大,但是不是意大利面。目前,它的架构非常好,在核心代码和驱动程序之间没有来回双向依赖。在不破坏核心内核的情况下,可以省去驱动程序。当内部函数或API重构后,驱动程序需要以不同的方式使用它时,可能需要更改驱动程序,但这对于重构是正常的。
彼得·科德斯

79

CLOC对3.13运行,Linux是约12万行代码。

  • 700万LOC的驱动程序/
  • 200万LOC /
  • 内核中只有13.9万个LOC /

lsmod | wc 我的Debian笔记本电脑上的显示了158个在运行时加载的模块,因此动态加载模块是支持硬件的一种常用方法。

强劲的配置系统(例如make menuconfig)用于选择编译哪些代码(更贵点,该代码编译)。嵌入式系统.config仅通过它们关心的硬件支持(包括支持内置于内核或作为可加载模块的硬件)来定义自己的文件。


2
find /lib/modules/$(uname -r)/ -name '*.ko' | wc说3,000多一点。FWIW,这就是Debian,“通用操作系统”,它提供了一个完整的操作系统,可以在围绕Linux内核构建的任何现代计算机上运行。
drewbenn

3
计数模块是不够的,很多可能是通过配置内置的
Alex

5
我认为由此可以得出结论,Linux内核之所以庞大,是因为它支持各种设备配置,而不是因为它过于复杂。我们在这里看到实际上只有1500万条线在使用。尽管几乎所有事物都可能过于复杂,但至少我们可以在知道原因的情况下在夜间入睡
Jonathan

2
@JonathanLeaders:是的-以及用于奇怪设备的模块,还有用于晦涩的文件系统,网络协议等的模块...
psmears 2015年

6
@JonathanLeader我记得Linux启动时-即使让安装程序正常运行(如果它甚至有安装程序!)也很痛苦-仍然有一些发行版需要您手动选择鼠标驱动程序。进行网络之类的事情,或者禁止X窗口工作,这是一种通过仪式。在我的第一个Red Hat安装中,我必须编写自己的图形驱动程序,因为只有三个(!)驱动程序可用。默认情况下,使基础知识正常工作是成熟的标志-显然,您可以对只有几个硬件组合的嵌入式系统进行更多的调整。
a安2015年

67

对于任何好奇的人,以下是GitHub镜像的行数细分:

=============================================
    Item           Lines             %
=============================================
  ./usr                 845        0.0042
  ./init              5,739        0.0283
  ./samples           8,758        0.0432
  ./ipc               8,926        0.0440
  ./virt             10,701        0.0527
  ./block            37,845        0.1865
  ./security         74,844        0.3688
  ./crypto           90,327        0.4451
  ./scripts          91,474        0.4507
  ./lib             109,466        0.5394
  ./mm              110,035        0.5422
  ./firmware        129,084        0.6361
  ./tools           232,123        1.1438
  ./kernel          246,369        1.2140
  ./Documentation   569,944        2.8085
  ./include         715,349        3.5250
  ./sound           886,892        4.3703
  ./net             899,167        4.4307
  ./fs            1,179,220        5.8107
  ./arch          3,398,176       16.7449
  ./drivers      11,488,536       56.6110
=============================================

drivers贡献了很多的线数。


19
那很有意思。更有趣的是代码中潜在的弱点,程序员对此感到恼火:grep -Pir "\x66\x75\x63\x6b" /usr/src/linux/ | wc -l
jimmij 2015年

4
根据这项开创性的研究(如果过时), @ jimmij'\ x73 \ x68 \ x69 \ x74'可能更常见。
尼克T

3
随机事实:该文档更接近OP估计的600 000 LOC。
Davidmh,2015年

1
./documentation有超过500,000行代码?....什么?
C_B

2
@C_B @Davidmh我认为这是笔直的事情wc,它的好处是比“代码行”更易于定义:)
drewbenn 2015年

43

到目前为止,答案似乎是“是,有很多代码”,没有人用最合乎逻辑的答案来解决这个问题:15M +?所以呢?1500万行源代码与鱼价有什么关系?是什么使它如此难以想象?

Linux显然做了很多事情。比什么都重要……但是您的一些观点表明,在构建和使用它时,您不尊重正在发生的事情。

  • 并非所有内容都已编译。内核构建系统使您可以快速定义选择源代码集的配置。有些是实验性的,有些是旧的,有些不是每个系统都需要的。看一下/boot/config-$(uname -r)(在Ubuntu上)make menuconfig,您将看到多少被排除在外。

    这是目标可变的桌面发行版。嵌入式系统的配置只能提取所需的内容。

  • 并非所有内容都是内置的。在我的配置中,大多数内核功能都是作为模块构建的:

    grep -c '=m' /boot/config-`uname -r`  # 4078
    grep -c '=y' /boot/config-`uname -r`  # 1944
    

    需要明确的是,这些全部内置......正如他们可以打印出来,做成一个巨大的纸三明治。除非您为离散的硬件工作进行自定义构建(在这种情况下,您已经限制了这些项目的数量),否则这没有任何意义。

  • 模块是动态加载的。即使系统具有成千上万的可用模块,该系统也允许您仅加载所需的内容。比较以下输出:

    find /lib/modules/$(uname -r)/ -iname '*.ko' | wc -l  # 4291
    lsmod | wc -l                                         # 99
    

    几乎没有加载。

  • 微内核不是一回事。只需10秒看领先的图像到维基百科页面,你链接将突出他们的目的是在一个完全不同的方式。

    Linux驱动程序是内部化的(主要是动态加载的模块),而不是用户空间,并且文件系统类似地是内部的。为什么这比使用外部驱动程序更糟糕?为什么Micro更适合通用计算?


这些评论再次突出表明您没有理解。如果要在离散硬件(例如航空航天,TiVo,平板电脑等)上部署Linux,则可以将其配置为仅构建所需的驱动程序。您可以使用在桌面上执行相同的操作make localmodconfig。最后,您得到了一个零灵活性的微型目的内核构建。

对于像Ubuntu这样的发行版,可以使用单个40MB内核程序包。不,要解决这个问题,实际上,与将归档包保持4000多个浮动模块的大规模归档和下载方案相比,这实际上是更可取的。它为他们使用更少的磁盘空间,在编译时更易于打包,易于存储,并且对他们的用户(拥有一个可以正常工作的系统)更有利。

未来似乎也不是问题。CPU速度,磁盘密度/定价和带宽改进的速度似乎快于内核的增长速度。十年之内,一个200MB的内核软件包将不会终结。

这也不是一条单行道。如果不维护代码,确实会被踢出。


2
关注的主要是嵌入式系统。如您所示,您的系统上有4,000个未使用的模块。在某些小型机器人技术或航空航天应用中(阅读:不是通用计算),这将是不可接受的浪费。
乔纳森

2
@JonathanLeaders我认为您可以安全地删除它们。在台式机上安装,它们的存在的情况下,你突然的东西插入USB端口,或改变某些硬件配置,等等
迪迪埃·答:

1
对,就是这样。我仍然对这样的假设感到惊讶,比如“您可以随时插入USB设备,因此我们需要15m行代码”是在内核级别而不是发行版本级别编写的,因为在电话和各种操作系统中都使用了Linux。嵌入式设备。好吧,我想这个发行版确实可以自己删除列表。我只是想为可插拔的支持应该是添加剂,而不是减法,IE将一种通过增加包的来源,而不是告诉内核嵌入式ARM配置是百分之一的它的当前大小“选择加入”到它的发行
Jonathan

5
@Jonathan带领您永远不会在嵌入式系统上运行为桌面配置的内核。我们的嵌入式系统有13个模块,并删除了我们不需要的所有硬件支持(以及许多其他自定义设置)。停止将台式机与嵌入式系统进行比较。Linux运行良好,因为它支持所有内容,并且可以进行定制以仅包含您关心的内容。这些4k模块在台式机系统上确实很棒:当我的最后一台笔记本电脑死了时,我只是将硬盘驱动器放到了更新得多的笔记本电脑中,并且一切正常
drewbenn

3
这种原本好的/有价值的答案带有明显的愤怒和好斗的语气。-1。
TypeIA

19

Linux tinyconfig编译的源代码行数 tinyconfig气泡图 svg(提琴)

shell脚本从内核构建中创建json,与http://bl.ocks.org/mbostock/4063269一起使用


编辑:原来unifdef有一些限制(-I被忽略和-include不支持,后者用于包括生成的配置头)此时使用cat不会有太大变化:

274692 total # (was 274686)

脚本和过程已更新。


除了驱动程序,arch等外,还有很多条件代码是否编译取决于所选择的配置,这些代码不一定在动态加载的模块中而是在内核中构建。

因此,下载了linux-4.1.6的源代码,选择了tinyconfig,它没有启用模块,老实说,我不知道它启用了什么或用户可以在运行时使用它做什么,无论如何,请配置内核:

# tinyconfig      - Configure the tiniest possible kernel
make tinyconfig

建立内核

time make V=1 # (should be fast)
#1049168 ./vmlinux (I'm using x86-32 on other arch the size may be different)

内核构建过程会*.cmd使用命令行调用隐藏文件,这些隐藏文件也用于构建.o文件,处理这些文件并提取script.sh下面的目标和依赖项副本,并将其与find一起使用:

find -name "*.cmd" -exec sh script.sh "{}" \;

这个创建目标的每一个依赖副本.o命名.o.c

.c代码

find -name "*.o.c" | grep -v "/scripts/" | xargs wc -l | sort -n
...
   8285 ./kernel/sched/fair.o.c
   8381 ./kernel/sched/core.o.c
   9083 ./kernel/events/core.o.c
 274692 total

.h标头(已清理)

make headers_install INSTALL_HDR_PATH=/tmp/test-hdr
find /tmp/test-hdr/ -name "*.h" | xargs wc -l
...
  1401 /tmp/test-hdr/include/linux/ethtool.h
  2195 /tmp/test-hdr/include/linux/videodev2.h
  4588 /tmp/test-hdr/include/linux/nl80211.h
112445 total

@JonathanLeaders在开发它时很有趣,很高兴有人喜欢它
Alex

9

Tananbaum和Torvalds从一开始就在公众中讨论了整体内核的权衡问题。如果您不需要所有内容都进入用户空间,那么与内核的接口可以更简单。如果内核是单片的,则可以在内部对其进行优化(并且更加混乱!)。

我们将模块作为一种折衷方案已经有一段时间了。而且它还在继续进行DPDK之类的工作(将更多的网络功能移出内核)。添加的核心越多,避免锁定就越重要。所以更多的东西将进入用户空间,内核也会缩小。

注意,单块内核不是唯一的解决方案。在某些体系结构上,内核/用户空间边界并不比任何其他函数调用都要昂贵,这使得微内核具有吸引力。


1
“在某些架构上,内核/用户空间的边界并不比任何其他函数调用都要昂贵” –有趣!那是什么建筑?如果您不仅仅放弃任何种类的内存保护,看起来很难实现。
Voo

1
我浏览了Ivan Goddard的所有millcomputing.com视频(mill / belt cpu,非常类似于VLIW)。此特定声明是中心主题,在您观看安全视频之前,其含义并不明显。它是仿真中的POC架构,但可能不是唯一具有此属性的架构。
罗布

1
嗯,这解释了。根据我的经验(我将第一个承认我没有紧跟行业发展),有许多模拟架构,很少有人会在橡胶上路后立即兑现他们的要求,也就是说,在真正的硬件上。尽管它背后的想法在任何情况下都可能很有趣-并不是第一次提到特定的CPU。如果您发现具有此属性的现有体系结构,我将非常感兴趣。
Voo

1
顺便说一句,这是您提到的辩论的更多资源:en.wikipedia.org/wiki/Tanenbaum%E2%80%93Torvalds_debate
Jonathan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.