工作集大小 (WSS) 是应用程序保持工作所需的内存量。您的应用程序可能分配了 100 GB 的主内存并进行了页面映射,但它每秒只能接触 50 MB 来完成其工作。这就是工作集大小:经常使用的“热”内存。了解容量规划和可伸缩性分析非常有用。
您可能从未见过用任何工具测量的 wss(当我创建此页面时,我也没有)。操作系统通常会向您显示以下指标:
- 虚拟内存:不是真实内存。它是虚拟内存系统的工件。对于像 Linux 这样的按需内存系统,malloc() 会立即返回虚拟内存,该内存仅在以后使用时提升为真实内存(通过页面错误提升)。
- 驻留内存或驻留集大小 (RSS):主内存。当前映射的实际内存页。
- 比例集大小(PSS):RSS在用户之间分配共享内存。
内核在管理虚拟和主内存分配时很容易跟踪这些。但是,当您的应用程序处于用户模式时,在其 WSS 中加载和存储指令时,内核(通常)不参与。因此,内核没有明显的方法来提供 WSS 指标。
在本页上,我将总结适用于任何操作系统的 WSS 目标和不同的 WSS 估计方法。这包括我的Linux wss工具,它们通过使用引用和空闲页面标志进行基于页面的 WSS 估计,以及我的WSS 配置文件图表。
目录
- 估计
- 观察:分页/交换指标
- 实验:主内存收缩
- 观察:PMC
- 实验:CPU 缓存刷新
- 实验:PTE 访问位
- Linux 引用页面标志
- Linux 空闲页面标志
- 实验:MMU失效
- 窗口参考集
目标
您打算使用 WSS 的目的将指导您如何测量它。请考虑以下三种情况:
- A) 您正在调整应用程序的主内存大小,目的是防止其分页(交换)。WSS 将在较长的时间间隔内以字节为单位进行测量,例如一分钟。B) 您正在优化 CPU 缓存。WSS 将在短时间间隔(例如一秒或更短)内访问的唯一缓存行中进行测量。缓存行大小取决于体系结构,通常为 64 字节。C) 您正在优化 TLB 缓存(转换后备缓冲区:用于虚拟到物理转换的内存管理单元缓存)。WSS 将以在短时间间隔(例如一秒或更短)内访问的唯一页面进行测量。页面大小取决于体系结构和操作系统配置,通常使用 4 KB。
您可以使用CPUid 计算 Linux 上的缓存行大小,并使用pmap -XX 计算页面大小。
1. 估算
您可以尝试估计它:您的应用程序将触及多少内存来为请求提供服务,或者在短时间间隔内?如果您有权访问应用程序的开发人员,他们可能已经有一个合理的想法。根据您的目标,您需要询问将引用多少个唯一字节、缓存行或页面。
2. 观察:分页/交换指标
分页指标通常在不同的操作系统中可用。Linux,BSD和其他Unix在vmstat中打印它们,在vm_stat中打印OS X。通常还有扫描指标,显示系统内存不足,并且花费更多时间填充空闲列表。
这些指标的基本思想是:
- 持续分页/交换 == WSS 大于主内存。
- 没有分页/交换,但持续扫描 == WSS 接近主内存大小。
- 无分页/交换或扫描 == WSS 小于主内存大小。
与其他内存计数器(如驻留内存又名 RSS:驻留集大小、虚拟内存、Linux “活动”/“非活动”内存等)相比,持续分页的有趣之处在于,持续页输入告诉我们应用程序实际上正在使用该内存来完成其工作。使用驻留集大小 (RSS) 等计数器,您不知道应用程序每秒实际使用了多少。
在 Linux 上,这需要将交换设备配置为分页的目标,而在许多系统上并非如此。如果没有交换设备,Linux 内存不足 (OOM) 杀手可以杀死牺牲进程以释放空间,这并不能告诉我们很多关于 WSS 的信息。
2.1. 分页/交换
查找寻呼/交换计数器通常很容易。它们在 Linux 上(输出列与标题不对齐):
# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 1 0 64166788 36348 5396380 0 0 0 1 1 1 9 0 91 0 0
0 1 0 64166656 36348 5396388 0 0 0 18432 318 510 0 0 97 3 0
0 1 0 64167276 36348 5396356 0 0 0 21504 359 551 0 0 97 3 0
[...]
Linux 将分页称为“交换”(在其他 Unix 中,交换是指将整个线程移动到交换设备,而分页仅指页面)。上面的示例显示没有处于活动状态的交换。
2.2. 扫描
较旧的 Unix 使用页面扫描程序在所有内存中搜索最近未使用的页面以进行分页,并在 vmstat 中报告扫描速率。当系统内存不足时,扫描速率仅不为零,并根据需求增加。该扫描速率可以用作系统即将耗尽主内存的早期警告(如果它还没有分页),并将速率用作量级。请注意,需要持续扫描(例如,30秒)以指示WSS。应用程序可以分配和填充已扫描和分页但随后不再使用的内存,从而导致扫描和分页突发。那是冷记忆:它不是WSS。WSS 处于活动状态,如果分页,将很快再次分页,从而导致分页改动:持续扫描和分页。
Linux 维护“活动”和“非活动”内存列表,以便可以通过浏览非活动列表快速找到符合条件的页面。在不同的时间点,页面将从活动列表移动到非活动列表,在那里它们有机会被“回收”并移回活动状态,然后在需要时换出。活动/非活动内存大小在 /proc/meminfo 中可用。要检查系统是否接近交换点,可以使用 vmscan 跟踪点。例如:
# perf stat -e 'vmscan:*' -a
^C
Performance counter stats for 'system wide':
1 vmscan:mm_vmscan_kswapd_sleep
16 vmscan:mm_vmscan_kswapd_wake
8 vmscan:mm_vmscan_wakeup_kswapd
4 vmscan:mm_vmscan_direct_reclaim_begin
0 vmscan:mm_vmscan_memcg_reclaim_begin
0 vmscan:mm_vmscan_memcg_softlimit_reclaim_begin
4 vmscan:mm_vmscan_direct_reclaim_end
0 vmscan:mm_vmscan_memcg_reclaim_end
0 vmscan:mm_vmscan_memcg_softlimit_reclaim_end
1,407 vmscan:mm_shrink_slab_start
1,407 vmscan:mm_shrink_slab_end
10,280 vmscan:mm_vmscan_lru_isolate
0 vmscan:mm_vmscan_writepage
8,567 vmscan:mm_vmscan_lru_shrink_inactive
1,713 vmscan:mm_vmscan_lru_shrink_active
2,743 vmscan:mm_vmscan_inactive_list_is_low
您可以只选择 vmscan:mm_vmscan_kswapd_wake 跟踪点作为低开销(因为它是低频率)指示器。每秒测量:
# perf stat -e vmscan:mm_vmscan_kswapd_wake -I 1000 -a
# time counts unit events
1.003586606 0 vmscan:mm_vmscan_kswapd_wake
2.013601131 0 vmscan:mm_vmscan_kswapd_wake
3.023623081 0 vmscan:mm_vmscan_kswapd_wake
4.033634433 30 vmscan:mm_vmscan_kswapd_wake
5.043653518 24 vmscan:mm_vmscan_kswapd_wake
6.053670317 0 vmscan:mm_vmscan_kswapd_wake
7.063690060 0 vmscan:mm_vmscan_kswapd_wake
您可能还会看到 kswapd 显示在进程监视器中,消耗 %CPU。
3. 实验:主内存收缩
值得一提但不推荐:我多年前在Unix系统上看到这种方法,其中分页更常用的配置和使用,并且可以在观察分页的强度的同时实验性地减少正在运行的应用程序可用的内存。有一段时间,应用程序通常“满意”(低分页),然后不是(突然高分页)。这一点是WSS的度量。
4. 观察:PMC
性能监视计数器 (PMC) 可以为 WSS 提供一些线索,并且可以在 Linux 上使用perf 进行测量。以下是使用我的pmcarch工具从pmc-cloud-tools测量的几个工作负载:
workload_A# ./pmcarch
K_CYCLES K_INSTR IPC BR_RETIRED BR_MISPRED BMR% LLCREF LLCMISS LLC%
3062544 4218774 1.38 498585136 540218 0.11 455116420 680676 99.85
3053808 4217232 1.38 499144330 524938 0.11 454770567 667970 99.85
3132681 4259505 1.36 515882929 680336 0.13 457656727 980983 99.79
[...]
workload_B# ./pmcarch
K_CYCLES K_INSTR IPC BR_RETIRED BR_MISPRED BMR% LLCREF LLCMISS LLC%
3079239 2314148 0.75 273159770 512862 0.19 243202555 148518182 38.93
3079912 2308655 0.75 273788704 494820 0.18 245159935 149093401 39.19
3090707 2316591 0.75 274770578 523050 0.19 243819132 148390054 39.14
[...]
工作负载 A 的上一级缓存 (LLC,又名 L3) 命中率超过 99.8%。它的 WSS 可能小于 LLC 大小吗?可能。LLC 大小为 24 MB(CPU 为:英特尔(R) 至强(R) 铂金 8124M CPU @ 3.00GHz)。这是一个具有统一访问分布的综合工作负载,我知道 WSS 是 10 MB。
工作负载 B 的 LLC 命中率为 39%。一点也不合适。它也是合成和统一的,WSS为100 MB,比LLC大。所以这是有道理的。
怎么样?
workload_B# ./pmcarch
K_CYCLES K_INSTR IPC BR_RETIRED BR_MISPRED BMR% LLCREF LLCMISS LLC%
3076373 6509695 2.12 931282340 620013 0.07 8408422 3273774 61.07
3086379 6458025 2.09 926621170 616174 0.07 11152959 4388135 60.65
3094250 6487365 2.10 932153872 629623 0.07 8865611 3402170 61.63
对于 61% 的 LLC 命中率,您可能会猜测它介于工作负载 A (10 MB) 和 B (100 MB) 之间。但是不,这也是 100 MB。我通过使访问模式不统一来提高其 LLC 命中率。我们能做些什么呢?有很多 PMC:用于缓存、MMU 和 TLB 以及内存事件,所以我认为我们可以对 CPU 进行建模,插入所有这些数字,并让它不仅估计 WSS,还估计访问模式。我还没有看到有人尝试过这个(肯定有人尝试过),所以我没有任何参考资料。它在我的待办事项清单上已经尝试了一段时间。它还涉及真正了解每个PMC:它们通常有测量注意事项。
以下是 cpucache 的屏幕截图,这是我刚刚添加到 pmc-cloud-tools 中的一个新工具,它显示了其中一些额外的 PMC:
# ./cpucache
All counter columns are x 1000
CYCLES INSTR IPC L1DREF L1DMISS L1D% L2REF L2MISS L2% LLCREF LLCMISS LLC%
13652088 5959020 0.44 1552983 12993 99.16 19437 8512 56.20 10224 4306 57.88
7074768 5836783 0.83 1521268 12965 99.15 21182 10380 51.00 13081 4213 67.79
7065207 5826542 0.82 1520193 12905 99.15 19397 8612 55.60 10319 4118 60.09
[...]
请注意,CPU 缓存通常在缓存行(例如,64 字节)上运行,因此随机 1 字节读取的工作负载变为 64 字节读取,从而膨胀了 WSS。虽然,如果我正在分析 CPU 缓存可伸缩性,我无论如何都想知道 WSS 的缓存行,因为这就是将被缓存的内容。
至少,PMC 可以告诉您:
如果 L1、L2 或 LLC 具有 ~100% 的命中率和高引用计数,则基于单线程缓存行的 WSS 小于该缓存,并且可能比它之前的任何缓存都大。
如果 L2 为 8 MB,LLC 为 24 MB,LLC 具有 ~100% 的命中率和高引用计数,您可能会得出结论,WSS 介于 8 到 24 MB 之间。如果它小于 8 MB,那么它将适合 L2,并且 LLC 将不再具有高引用计数。我说“可能是”,因为较小的工作负载可能由于其他原因而无法在 L2 中缓存:例如,设置关联性。
我还必须将其限定为单线程。多线程有什么问题?考虑一个运行多线程应用程序的多核多套接字服务器,其中每个线程实际上都有自己的工作集。应用程序的组合工作集大小可由多个 CPU 缓存缓存:多个 L1、L2 和 LLC。它可能具有~100%的LLC命中率,但WSS比单个LLC大,因为它存在于多个LLC中。
5. 实验:CPU 缓存刷新
只是一个想法。我找不到任何人这样做的例子,但对于 CPU 缓存,我想缓存刷新与 PMC 相结合可用于 WSS 估计。刷新缓存,然后测量 LLC 填充并再次开始逐出所需的时间。速度越慢,WSS 就越小(可能)。通常有 CPU 指令来帮助缓存刷新,前提是它们已启用:
# cpuid -1 | grep -i flush
CLFLUSH line size = 0x8 (8)
CLFLUSH instruction = true
CLFLUSHOPT instruction = true
还可以应用此方法的其他缓存。MMU TLB 可以刷新(至少内核知道如何刷新)。Linux 文件系统缓存可以用 /proc/sys/vm/drop_caches 刷新,然后通过操作系统指标(例如,免费)随着时间的推移跟踪增长。
6. 实验:PTE 访问位
这些方法使用页表条目 (PTE) “访问”位,该位通常在访问内存页时由 CPU MMU 更新,并且可以由内核读取和清除。这可用于提供基于页的 WSS 估计,方法是清除进程所有页面上的访问位,等待间隔,然后检查该位返回到的页数。它的优点是在更新访问位时没有额外的开销,因为 MMU 无论如何都会这样做。
6.1. Linux 参考页标志
这使用了 Linux 2.6.22 中添加的内核功能:从用户空间设置和读取引用的页面标志的功能,为分析内存使用情况而添加。引用的页面标志实际上是 PTE 访问位(在 Linux 中_PAGE_BIT_ACCESSED)。我开发了wss.pl作为此功能的前端。以下内容在 MySQL 数据库服务器 (mysqld) PID 423 上使用它,并测量其工作集大小 0.1 秒(100 毫秒):
# ./wss.pl 423 0.1
Watching PID 423 page references during 0.1 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
0.107 403.66 400.59 28.02
在 100 毫秒内,mysqld 在其 404 MB 的总主内存中触及了 28 MB 的页面。为什么我使用了 100 毫秒的间隔?较短的持续时间对于了解 WSS 在 CPU 缓存(L1/L2/L3、TLB L1/L2 等)中的适应程度非常有用。在这种情况下,28 MB 比此 CPU 的 LLC 大一点,因此可能无法很好地缓存(无论如何,在单个 LLC 中)。
此处打印的列是:
- 估计:估计的 WSS 测量持续时间:这说明了设置和读取页面图数据的延迟。
- RSS(MB):驻留集大小(MB)。主内存大小。
- PSS(MB):成比例的集大小(MB)。共享页面的会计处理。
- 引用 (MB):在指定持续时间内引用(MB)。这是工作集大小指标。
我将在第 6.7 节中详细介绍估计持续时间。
6.1.1. 工作原理
它的工作原理是在内存页上重置引用的标志,然后稍后检查此标志返回到的页数。我想起了旧的 Unix 页面扫描器,它将使用类似的方法来查找最近未使用的页面,这些页面有资格分页到交换设备(也称为交换)。我的工具使用 /proc/PID/clear_refs 和 /proc/PID/smaps 中的引用值,该值由 David Rientjes 于 2007 年添加。他还在他的补丁中描述了内存占用估计。我只看过这个功能的另一个描述:我到底使用了多少内存?,作者是Jonathan Corbet(lwn.net编辑)。我将其归类为一种实验性方法,因为它修改了系统的状态:更改引用的页面标志。
我之前的 PMC 分析将 WSS 四舍五入到缓存行大小(例如,64 字节)。这种方法将其四舍五入到页面大小(例如,4 KB),因此可能会向您显示最坏情况的WSS。对于巨大的页面,2 MB的页面大小,它可能会使WSS膨胀得超出现实。但是,有时基于页面大小的 WSS 正是您想要的:了解存储页面映射的 TLB 命中率。
6.1.2. 警告
此工具使用 /proc/PID/clear_refs 和 /proc/PID/smaps,它们可以 导致内核遍历页面时应用程序延迟略高(例如,10%) 结构。对于大型进程 (> 100 GB),此持续时间 更高的延迟可能会持续 1 秒以上,在此期间此工具会消耗 系统 CPU 时间。考虑这些开销。这 还会重置引用的标志,这可能会使内核混淆哪个 要回收的页面,尤其是在交换处于活动状态时。这也激活了一些 以前可能未在您的环境中使用过的旧内核代码,以及 修改页面标志:我猜存在未被发现的风险 内核恐慌(Linux mm社区也许可以说这种风险有多真实 是)。在实验室环境中测试内核版本,并考虑这一点 实验性:使用风险自负。
有关在 Linux 4.3+ 上使用空闲页标志更安全的方法,请参阅第 7 节,该标志还跟踪未映射的文件 I/O 内存。
6.1.3. 累积增长
这是相同的过程,但测量 WSS 的时间为 1、10 和 60 秒(这不会产生额外的开销,因为该工具无论如何都会休眠):
# ./wss.pl `pgrep -n mysqld` 1
Watching PID 423 page references during 1 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
1.012 403.66 400.75 69.44
# ./wss.pl `pgrep -n mysqld` 10
Watching PID 423 page references during 10 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
10.019 403.66 400.75 80.79
# ./wss.pl `pgrep -n mysqld` 60
Watching PID 423 page references during 60 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
60.068 403.66 400.60 84.50
一秒钟后,此进程引用了 69 MB,十秒后引用了 81 MB,这表明在第一秒内已经引用了大部分 WSS。
此工具具有累积模式 (-C),它将在其中生成滚动输出,显示工作集如何增长。这的工作原理是仅在开始时重置引用的标志一次,然后为每个间隔打印当前引用的大小。显示滚动的一秒输出:
# ./wss `pgrep -n mysqld` 1
Watching PID 423 page references grow, output every 1 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
1.014 403.66 400.59 86.00
2.034 403.66 400.59 90.75
3.054 403.66 400.59 94.29
4.074 403.66 400.59 97.53
5.094 403.66 400.59 100.33
6.114 403.66 400.59 102.44
7.134 403.66 400.59 104.58
8.154 403.66 400.59 106.31
9.174 403.66 400.59 107.76
10.194 403.66 400.59 109.14
[...]
6.1.4. 与 PMC 的比较
作为测试,我在一些大小不断增加的MySQL系统支架OLTP工作负载上运行了它。下面是 –oltp-table-size=10000:
# ./wss.pl -C `pgrep -nx mysqld` 1
Watching PID 423 page references grow, output every 1 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
1.014 403.66 400.77 12.46
2.033 403.66 400.77 12.64
3.043 403.66 400.77 12.70
4.053 403.66 400.77 12.79
5.063 403.66 400.77 12.88
6.073 403.66 400.77 12.98
[...]
# ./pmcarch
K_CYCLES K_INSTR IPC BR_RETIRED BR_MISPRED BMR% LLCREF LLCMISS LLC%
3924948 4900967 1.25 983842564 8299056 0.84 49012994 423312 99.14
3741509 4946034 1.32 984712358 8397732 0.85 47532624 476105 99.00
3737663 4903352 1.31 987003949 8219215 0.83 48084819 469919 99.02
3772954 4898714 1.30 980373867 8259970 0.84 47347470 445533 99.06
3762491 4915739 1.31 983279742 8320859 0.85 48034764 398616 99.17
3764673 4912087 1.30 983237267 8308238 0.84 47989639 479042 99.00
[...]
wss工具显示一个12 MB的工作集,pmcarch显示99%的LLC命中率。此 CPU 上的 LLC 为 24 MB,因此这是有道理的。
现在 –oltp-table-size=10000000:
# ./wss.pl -C `pgrep -nx mysqld` 1
Watching PID 423 page references grow, output every 1 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
1.010 403.66 400.59 86.88
2.020 403.66 400.59 90.40
3.040 403.66 400.59 93.71
4.050 403.66 400.59 96.19
5.060 403.66 400.59 99.02
6.080 403.66 400.59 100.80
[...]
# ./pmcarch
K_CYCLES K_INSTR IPC BR_RETIRED BR_MISPRED BMR% LLCREF LLCMISS LLC%
3857663 4361549 1.13 875905306 8270478 0.94 57942970 4478859 92.27
3674356 4403851 1.20 869671764 8307450 0.96 57444045 4518955 92.13
3858828 4483705 1.16 893992312 8480271 0.95 57808518 4843476 91.62
3701744 4321834 1.17 861744002 8144426 0.95 56775802 4456817 92.15
4067889 4932042 1.21 994934844 12570830 1.26 63358558 5001302 92.11
3703030 4378543 1.18 874329407 8307769 0.95 58147001 4529388 92.21
[...]
现在WSS超过80MB,这应该会破坏LLC,但是,它的命中率仅下降到92%。这可能是因为访问模式是不均匀的,并且该工作集的较热区域从LLC冲击的次数比较冷的区域更大。
6.1.5. 工作集大小分析
我在 wss 工具中添加了一个配置文件模式,以阐明访问模式。它将采样持续时间提高 2 的幂。这是相同的MySQL工作负载:
# ./wss.pl -P 16 `pgrep -n mysqld` 0.001
Watching PID 423 page references grow, profile beginning with 0.001 seconds, 16 steps...
Est(s) RSS(MB) PSS(MB) Ref(MB)
0.008 403.66 400.76 8.79
0.018 403.66 400.76 13.98
0.027 403.66 400.76 17.69
0.038 403.66 400.76 21.70
0.058 403.66 400.76 27.83
0.088 403.66 400.76 35.51
0.128 403.66 400.76 43.43
0.209 403.66 400.76 55.08
0.349 403.66 400.76 69.95
0.620 403.66 400.76 84.18
1.150 403.66 400.76 86.18
2.190 403.66 400.76 89.43
4.250 403.66 400.76 94.41
8.360 403.66 400.76 101.38
16.570 403.66 400.76 107.49
32.980 403.66 400.76 113.05
下面是一个合成工作负载,它通过统一的访问分布达到 100 MB:
# ./wss.pl -P 16 `pgrep -n bench` 0.001
Watching PID 34274 page references grow, profile beginning with 0.001 seconds, 16 steps...
Est(s) RSS(MB) PSS(MB) Ref(MB)
0.008 201.11 200.11 46.29
0.017 201.11 200.11 100.03
0.027 201.11 200.11 100.03
0.037 201.11 200.11 100.03
0.048 201.11 200.11 100.03
0.067 201.11 200.11 100.03
0.107 201.11 200.11 100.03
0.177 201.11 200.11 100.03
0.318 201.11 200.11 100.03
0.577 201.11 200.11 100.03
1.098 201.11 200.11 100.03
2.128 201.11 200.11 100.03
4.188 201.11 200.11 100.03
8.298 201.11 200.11 100.03
16.508 201.11 200.11 100.03
32.918 201.11 200.11 100.03
这为 WSS 的不同用途提供了信息:研究 WSS CPU 缓存的持续时间较短,研究主内存驻留的持续时间较长。
由于工作负载可能会有所不同,请注意,这只是显示工具运行时的 WSS 增长。您可能需要多次收集此配置文件,以确定正常的 WSS 配置文件的外观。
6.1.6. WSS 配置文件图表
绘制前两个配置文件的图形:
请注意,我使用了对数 x 轴(这里是线性版本)。一个陡峭的斜率,然后是一个平坦的轮廓是我们对均匀分布的期望:初始测量尚未达到其WSS,因为间隔太小,并且没有足够的CPU周期来接触所有页面。至于mysqld:需要更长的时间才能稍微平衡一点,它在16毫秒后达到80 MB,然后在256毫秒时再次拾取并爬升更多。看起来 80 MB 比其他的更热。由于工作负载可以逐秒变化,因此我不会相信单个配置文件:我想将几个配置文件绘制在一起,以寻找趋势。
上面均匀分布的“尖锐斜率”只有一个数据点。这是一个 2 GB 的 WSS,也是一个均匀分布,程序引用需要更长的时间,为我们提供了更多的绘图点:
它向上弯曲,因为它是一个对数轴。这里是线性(缩放)。虽然看起来很有趣,但此曲线仅反映 WSS 样本持续时间,而不是访问分布。分布确实是均匀的,如大约 0.3 秒后的平线所示。此图中的拐点显示了我们可以识别此 WSS 和程序逻辑的统一访问分布的最小间隔。超出此点的配置文件反映了访问分布。超出此点的配置文件反映了访问分布,并且对于了解主内存使用情况很有意思。它前面的配置文件很有趣,原因不同:了解 CPU 缓存在短时间间隔内处理的工作负载。
6.1.7. 估计持续时间和准确性
以下是您可能想象此工具的工作方式:
- 重置进程的引用页面标志(瞬时)
- 睡眠时间
- 读取引用的页面标志(瞬时)
以下是实际发生的情况:
- 重置进程的第一页标志
- […重置下一页标志,然后是下一页,然后是下一页,依此类推。
- 页面标志重置完成
- 睡眠一段时间
- 阅读流程的第一页标志
- […阅读下一页标志,然后是下一页,然后是下一页,等等。
- 阅读完成
工作集只应在步骤 4(预期的持续时间)中测量。但是 在步骤 2 中设置标志之后,以及在步骤 4 中开始持续时间之前,应用程序可以触摸内存页。 步骤 6 中的读取也会发生同样的情况:在检查标志之前,应用程序可能会在此阶段触摸内存页。 因此,步骤 2 和 6 有效地增加了睡眠持续时间。 大型进程(>100 GB)的这些阶段可能需要 超过 500 毫秒的 CPU 时间,因此 10 毫秒的目标持续时间实际上可能是 反映 100 毫秒的内存变化。
为了通知最终用户此持续时间膨胀,此工具提供了一个 估计持续时间,从第 2 阶段的中点到阶段的中点 第 6 阶段。对于小型进程,此估计持续时间可能等于 预期持续时间。但是对于大型过程,它会显示膨胀的时间。
6.1.8. 精确的工作集大小持续时间
我已经尝试了一种获得精确持续时间的方法:发送目标过程 SIGSTOP 和 SIGCONT 信号,以便在设置和读取页面地图时暂停它,并且仅在预期的测量持续时间内运行。这很危险
6.2. 实验:Linux 空闲页面标志
这是 Vladimir Davydov 在Linux 4.3 中添加的一种较新的方法,它引入了 Idle 和 Young 页面标志,用于更可靠的工作集大小分析,并且没有缺点,例如使用引用的标志可能会混淆内核回收逻辑。Jonathan Corbet 再次写过这个主题:跟踪实际内存利用率。Vladimir 称之为空闲内存跟踪,不要与多年前的空闲页面跟踪补丁集混淆,后者在 /sys 中引入了用于页面扫描和摘要统计信息的 kstaled(未合并)。
这仍然是一种 PTE 访问位方法:这些额外的空闲和年轻标志仅在内核的扩展页表条目 (page_ext_flags) 中,用于帮助回收逻辑。
使用空闲内存跟踪需要更多。从内核文档vm/idle_page_tracking.txt:
That said, in order to estimate the amount of pages that are not used by a
workload one should:
1. Mark all the workload's pages as idle by setting corresponding bits in
/sys/kernel/mm/page_idle/bitmap. The pages can be found by reading
/proc/pid/pagemap if the workload is represented by a process, or by
filtering out alien pages using /proc/kpagecgroup in case the workload is
placed in a memory cgroup.
2. Wait until the workload accesses its working set.
3. Read /sys/kernel/mm/page_idle/bitmap and count the number of bits set. If
one wants to ignore certain types of pages, e.g. mlocked pages since they
are not reclaimable, he or she can filter them out using /proc/kpageflags.
我已经编写了两个使用它的概念验证工具,它们在wss集合中。
6.2.1. WSS-v1:小流程优化
此工具的此版本逐个遍历页面结构,仅适用于小型进程。在大型进程 (>100 GB) 上,此工具可能需要几分钟才能写入。请参阅 wss-v2.c,它使用页面数据快照,对于大型进程(50 倍)要快得多,以及 wss.pl,它甚至更快(尽管使用引用的页面标志)。
下面是一些示例输出,将此工具与前面 wss.pl 进行比较:
# ./wss-v1 33583 0.01
Watching PID 33583 page references during 0.01 seconds...
Est(s) Ref(MB)
0.055 10.00
# ./wss.pl 33583 0.01
Watching PID 33583 page references during 0.01 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
0.011 21.07 20.10 10.03
输出显示该进程引用了 10 MB 的数据(这是正确的:它是一个合成工作负载)。
列:
- 估计:估计的 WSS 测量持续时间:这说明了设置和读取页面图数据的延迟。
- 引用 (MB):在指定持续时间内引用(MB)。这是工作集大小指标。
6.2.2. WSS-v1 警告
此工具设置和读取流程页面标志,对于大型 进程(> 100 GB)可能需要几分钟时间(使用 WSS-v2 相反)。在此期间,此工具会消耗一个 CPU,并且应用程序 潜伏期可能略高(如5%)。考虑这些开销。 此外,这是激活 Linux 4.3 中添加的一些新内核代码,您 可能以前从未执行过。与任何此类代码一样,存在 未发现的内核恐慌的风险(我没有具体的理由担心, 只是偏执)。在实验室环境中测试内核版本, 并考虑这个实验性:使用风险自负。
6.2.3. WSS-v2:大型流程优化
此工具的此版本可拍摄系统空闲页面标志的快照,从而加快对大型进程的分析,但不能加快对小型进程的分析。请参阅 wss-v1.c,对于小型进程可能更快,以及 wss.pl,它甚至更快(尽管使用引用的页面标志)。
下面是一些示例输出,将此工具与 wss-v1(运行速度慢得多)以及较早的 wss.pl 进行比较:
# ./wss-v2 27357 0.01
Watching PID 27357 page references during 0.01 seconds...
Est(s) Ref(MB)
0.806 15.00
# ./wss-v1 27357 0.01
Watching PID 27357 page references during 0.01 seconds...
Est(s) Ref(MB)
44.571 16.00
# ./wss.pl 27357 0.01
Watching PID 27357 page references during 0.01 seconds...
Est(s) RSS(MB) PSS(MB) Ref(MB)
0.080 20001.12 20000.14 15.03
输出显示该进程引用了 15 MB 的数据(这是正确的:这是一个合成工作负载)。
列:
- 估计:估计的 WSS 测量持续时间:这说明了设置和读取页面图数据的延迟。
- 引用 (MB):在指定持续时间内引用(MB)。这是工作集大小指标。
6.2.4. WSS-v2 警告
此工具设置和读取系统和进程页面标志,这可以 占用超过一秒钟的 CPU 时间,在此期间应用程序可能会遇到 潜伏期稍高(如5%)。考虑这些开销。另外,这是 激活 Linux 4.3 中添加的一些您可能从未添加过的新内核代码 之前执行。与任何此类代码一样,存在以下风险: 未发现的内核恐慌(我没有具体的理由担心,只是 偏执狂)。在实验室环境中测试内核版本,并考虑 此实验性:使用风险自负。
7. 实验:MMU无效
此方法会使 MMU 中的内存页失效,以便 MMU 在下次访问时出现软故障。这会导致加载/存储操作将控制权交给内核以处理故障,此时内核只需重新映射页面并跟踪它被访问。它可以由内核或用于监视来宾 WSS 的虚拟机管理程序来完成。
7.2. 窗口参考集
微软有一个很棒的页面:参考集和系统范围对内存使用的影响。 一些术语差异:
- Linux 驻留内存 == Windows 工作集 Linux 工作集 == Windows 参考集
此方法使用 WPR 或 Xperf 来收集“引用集”,这是对访问页面的跟踪。我自己还没有做过这些,但它似乎使用 MMU 失效方法,然后是页面错误的事件跟踪。该文档记录了开销:
警告:“记录引用集的跟踪可能会对系统性能产生重大影响,因为所有进程都必须在其工作集清空后将大量页面错误地返回到其工作集中。
一旦我使用它,我将更新此页面以提供更多详细信息。到目前为止,这些是我见过的唯一工具(除了我写的工具)来进行 WSS 估计。
其他
WSS 估计的其他技术包括:
- 应用程序指标:这取决于应用程序,但有些可能已经跟踪正在使用的内存作为 WSS 近似值。
- 应用程序修改:我已经看到过这方面的研究,其中修改了应用程序代码以跟踪正在使用的内存对象。这可能会增加大量开销,并且需要更改代码。
- CPU 模拟:跟踪负载/存储。应用在此类模拟器中的运行速度可以慢 10 倍或更多。
- 内存断点:例如调试器可以配置的断点。我预计会有巨大的开销。
- 内存观察点:可以构建一种方法来使用这些;观察点最近得到了BPFtrace的支持。
- MMU页面失效:强制页面在访问时出错,揭示正在使用的页面。这可以由内核或用于监视来宾 WSS 的虚拟机监控程序来完成。
- 处理器跟踪:以及可以记录加载/存储的类似处理器级功能。处理日志的预期开销很高。
- 内存总线侦听:使用物理连接到内存总线的自定义硬件和软件来汇总观察到的访问。
我没有看到的是用于进行WSS估计的现成通用工具。这就是促使我基于 Linux 引用和空闲页面标志编写 wss 工具的原因,尽管每个工具都有自己的警告(尽管不像其他方法那么糟糕)。
地址:https://www.brendangregg.com/wss.html
创业项目群,学习操作 18个小项目,添加 微信:790838556 备注:小项目!
如若转载,请注明出处:https://www.zoodoho.com/76751.html