我们希望将服务器上的操作系统从Ubuntu 10.04 LTS升级到Ubuntu 12.04 LTS.不幸的是,似乎运行已经变为可运行的线程的延迟从2.6内核到3.2内核显着增加.事实上,我们得到的延迟数字很难相信.
让我对测试更加具体.我们有一个运行两个线程的程序.第一个线程获取当前时间(使用RDTSC以滴答为单位),然后每秒发送一次条件变量.第二个线程等待条件变量并在发出信号时唤醒.然后它获取当前时间(使用RDTSC以滴答为单位).计算第二个线程中的时间与第一个线程中的时间之间的差异,并在控制台上显示.在此之后,第二个线程再次等待条件变量.大约第二次通过后,第一个线程将再次发出信号.
因此,简而言之,我们得到一个线程,通过条件可变延迟测量一次一次地进行线程通信.
在内核2.6.32中,这种延迟大约为2.8-3.5 us,这是合理的.在内核3.2.0中,这种延迟已经增加到大约40-100 us.我已经排除了两台主机之间硬件的任何差异.它们运行在相同的硬件上(双插槽X5687 {Westmere-EP}处理器,运行频率为3.6 GHz,具有超线程,speedtep和所有C状态关闭).测试应用程序更改线程的亲和力以在同一套接字的独立物理核心上运行它们(即,第一个线程在Core 0上运行,第二个线程在Core 1上运行),因此没有线程的弹跳套接字之间的核心或弹跳/通信.
两台主机之间的唯一区别是,一台运行Ubuntu 10.04 LTS,内核为2.6.32-28(快速上下文切换盒),另一台运行最新的Ubuntu 12.04 LTS,内核为3.2.0-23(缓慢的上下文)开关盒).所有BIOS设置和硬件都相同.
内核是否有任何变化可以解释线程被安排运行多长时间的这种荒谬的减速?
更新: 如果您想在主机和Linux版本上运行测试,我已将代码发布到pastebin供您阅读.编译:
g++ -O3 -o test_latency test_latency.cpp -lpthread
Run Code Online (Sandbox Code Playgroud)
运行(假设您至少有一个双核盒子):
./test_latency 0 1 # Thread 1 on Core 0 and Thread 2 on Core 1
Run Code Online (Sandbox Code Playgroud)
更新2:经过大量内核参数搜索,内核更改和个人研究的帖子后,我已经找出了问题所在并已发布解决方案作为这个问题的答案.
在Linux中,当需要从磁盘读取块时,进程状态会发生什么?它被阻止了吗?如果是这样,如何选择执行另一个过程?
我做到了 sudo cat /proc/1/maps -vv
我试图弄清楚输出.我可以看到很多共享库按预期映射到内存映射段.
7f3c00137000-7f3c00179000 r-xp 00000000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c00179000-7f3c00379000 ---p 00042000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c00379000-7f3c0037a000 r--p 00042000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c0037a000-7f3c0037b000 rw-p 00043000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c0037b000-7f3c00383000 r-xp 00000000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00383000-7f3c00583000 ---p 00008000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00583000-7f3c00584000 r--p 00008000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00584000-7f3c00585000 rw-p 00009000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00585000-7f3c0059b000 r-xp 00000000 08:01 21237220 /lib/x86_64-linux-gnu/libnih.so.1.0.0
7f3c0059b000-7f3c0079b000 ---p 00016000 08:01 21237220 /lib/x86_64-linux-gnu/libnih.so.1.0.0
7f3c0079b000-7f3c0079c000 r--p 00016000 08:01 21237220 /lib/x86_64-linux-gnu/libnih.so.1.0.0
Run Code Online (Sandbox Code Playgroud)
接近尾声有类似的东西
7f3c0165b000-7f3c0177e000 rw-p 00000000 00:00 0 [heap]
7fff97863000-7fff97884000 …Run Code Online (Sandbox Code Playgroud) 如果我加载内核模块并列出已加载的模块lsmod,我可以得到模块的"使用计数"(其他模块的数量与模块的引用).有没有办法弄清楚什么是使用模块?
问题是我正在开发的模块坚持它的使用计数为1,因此我不能用rmmod它来卸载它,但它的"by"列是空的.这意味着每次我想重新编译和重新加载模块时,我都必须重启机器(或者,至少,我无法找出任何其他方法来卸载它).
在这个问题的帮助下,我想学习并填补我的知识空白.
因此,用户正在运行一个线程(内核级),它现在调用yield(我假设的系统调用).调度程序现在必须将当前线程的上下文保存在TCB中(存储在内核中的某个地方)并选择另一个线程来运行并加载其上下文并跳转到它CS:EIP.为了缩小范围,我正在开发基于x86架构的Linux.现在,我想了解详细信息:
所以,首先我们有一个系统调用:
1)包装函数yield将把系统调用参数推送到堆栈.按下返回地址并产生一个中断,系统调用号码被推到某个寄存器上(比方说EAX).
2)中断将CPU模式从用户更改为内核并跳转到中断向量表并从那里到内核中的实际系统调用.
3)我猜调度程序现在被调用,现在它必须保存TCB中的当前状态.这是我的困境.因为,调度器将使用内核堆栈,而不是用于执行其操作(这意味着该用户堆栈SS和SP必须被改变),它是如何存储的用户的状态,而不会在该过程修改任何寄存器.我在论坛上看到有关于保存状态的特殊硬件指令,但是调度程序如何访问它们以及谁运行这些指令以及何时执行?
4)调度程序现在将状态存储到TCB中并加载另一个TCB.
5)当调度程序运行原始线程时,控件返回到包装器函数,该函数清除堆栈并恢复线程.
附带问题:调度程序是否作为仅内核线程(即只能运行内核代码的线程)运行?每个内核线程或每个进程都有一个单独的内核堆栈吗?
我一直在尝试开始使用kgdbNexus One.
我已经从https://android.googlesource.com中提取了内核,并启用了kgdb包括kgdbts测试使用的一切menuconfig.成功构建内核并将其刷新到设备(已解锁并运行CyanogenMod 7)
我也跟着上找到的说明 http://bootloader.wikidot.com/android:kgdb启用USB连接的要求作为一个串行连接kgdb(和测试,从通信ttyACM0到ttyGS0成功).
下列文件夹存在,表明kgdboc和kgdbts已建到内核:
/sys/modules/kgdboc/parameters
/sys/modules/kgdbts/parameters
Run Code Online (Sandbox Code Playgroud)
以下是dmesg的输出,显示kgdbts正在进行的测试显示(我认为)成功完成了测试:
# dmesg | grep kgdb
<6>[ 12.974060] kgdb: Registered I/O driver kgdbts.
<6>[ 12.981781] kgdbts:RUN plant and detach test
<6>[ 12.995178] kgdbts:RUN sw breakpoint test
<6>[ 13.002441] kgdbts:RUN bad memory access test
<6>[ 13.010864] kgdbts:RUN singlestep test 1000 iterations
<6>[ 13.019042] kgdbts:RUN singlestep [0/1000]
<6>[ 13.077850] kgdbts:RUN …Run Code Online (Sandbox Code Playgroud) 我希望有人可以解释linux内核源代码中使用的__user宏的细微差别.
首先,宏观:
# define __user __attribute__((noderef, address_space(1)))
Run Code Online (Sandbox Code Playgroud)
现在,经过一些谷歌搜索后,我读到这个宏允许一个指针指定属于用户地址空间,并且不应该取消引用它.
我可能会遗漏一些明显的事实,但有人可以解释这样一个宏的含义吗?例如,这个宏的使用位置有什么好的例子?如果我错过了一些明显的东西,请再次原谅我.
为了把它放在某些环境中,我在检查一些USB代码(linux/usbdevice_fs.h)时遇到了宏.我只是在寻找对内核中使用的这个宏(或其他类似的宏)的一般理解.
谢谢你的期待!
用你自己的话来解释,什么是抢占以及它对(linux)内核意味着什么?
拥有可抢占内核有哪些优缺点?
据我所知,initrd充当块设备,因此需要文件系统驱动程序(如ext2).内核必须至少有一个用于检测文件系统的内置模块initrd.在本文中,介绍了初始RAM磁盘的新模型initramfs,它写成:
但是由于缓存,ramdisks实际上浪费了更多的内存.Linux旨在缓存从块设备读取或写入的所有文件和目录条目,因此Linux将数据复制到ramdisk和从"ramdisk"复制到"页面缓存"(用于文件数据)和"dentry cache"(用于目录条目) .假装是块设备的ramdisk的缺点是它被视为块设备.
什么page cache和dentry cache?在段落中,是否意味着数据被复制,因为ramdisk被视为块设备,因此所有数据都被缓存?
相反,ramfs:
几年前,Linus Torvalds有一个很好的想法:如果Linux的缓存可以像文件系统一样挂载怎么办?只是将文件保存在缓存中,永远不要删除它们,直到它们被删除或系统重新启动?Linus在缓存周围写了一个名为"ramfs"的小包装器,其他内核开发人员创建了一个名为"tmpfs"的改进版本(它可以将数据写入交换空间,并限制给定挂载点的大小,以便在消耗之前填满所有可用的内存).Initramfs是tmpfs的一个实例.
这些基于ram的文件系统会自动增长或缩小以适应它们包含的数据大小.将文件添加到ramfs(或扩展现有文件)会自动分配更多内存,删除或截断文件会释放该内存.块设备和缓存之间没有重复,因为没有块设备.缓存中的副本是数据的唯一副本.最重要的是,这不是新代码,而是现有Linux缓存代码的新应用程序,这意味着它几乎不增加任何大小,非常简单,并且基于经过严格测试的基础架构.
总之,ramfs只是文件打开并加载到内存中,不是吗?
二者initrd并ramfs在编译时拉链,但不同的是,initrd被分解到由在启动内核被安装,而块设备ramfs经由的cpio解压到存储器中.我对么?或者是ramfs一个非常小的文件系统?
最后,直到今天,initrd图像仍然显示在最新的内核中.然而,这initrd实际上是ramfs今天使用的,这个名字只是出于历史目的吗?
以下段错误消息的正确解释是什么?
segfault at 10 ip 00007f9bebcca90d sp 00007fffb62705f0 error 4 in libQtWebKit.so.4.5.2[7f9beb83a000+f6f000]
segfault at 10 ip 00007fa44d78890d sp 00007fff43f6b720 error 4 in libQtWebKit.so.4.5.2[7fa44d2f8000+f6f000]
segfault at 11 ip 00007f2b0022acee sp 00007fff368ea610 error 4 in libQtWebKit.so.4.5.2[7f2aff9f7000+f6f000]
segfault at 11 ip 00007f24b21adcee sp 00007fff7379ded0 error 4 in libQtWebKit.so.4.5.2[7f24b197a000+f6f000]
Run Code Online (Sandbox Code Playgroud) kernel ×10
linux ×7
linux-kernel ×4
c ×2
android ×1
boot ×1
cpu ×1
debugging ×1
filesystems ×1
macros ×1
preemption ×1
process ×1
qt ×1
scheduler ×1
states ×1
ubuntu-12.04 ×1
vdso ×1
webkit ×1