PMDK is popular nowadays. To practice, please start from http://pmem.io
.
在 src/examples/libpmem/ 目錄下有三個簡單的例子:full\_copy.c、manpage.c、simple\_copy.c。我們選擇 full\_copy.c 做測試,并在其基礎上修改為 copy\_mem.c。
在得到的測試資料中可以發現幾個明顯的拐點,例如:
- devdax 模式下,每次 flush 32 位元組比 64 位元組要慢很多。因為 cache line 的大小是 64 位元組。
-
devdax 模式下,每次 flush 128 位元組也比 256 位元組要慢很多。 推測是 PMEM\_MOVNT\_THRESHOLD 預設設定為 256 導緻的,256 位元組以上的資料将采用 Cache of Non-temporal Data 的寫 Cache 模式。
$ cat src/libpmem/x86_64/init.c
define MOVNT_THRESHOLD 256
size_t Movnt_threshold = MOVNT_THRESHOLD; - xfs 模式下,每次 flush 2048 位元組也比 4096 位元組要慢很多。因為 xfs 的塊大小(等同核心的頁面大小)是 4096 位元組。
- fsdax 模式下,每次 flush 128 位元組也比 256 位元組要慢很多。因為 fsdax 模式下,首次缺頁都會要先寫零并持久化。
- fsdax 模式比 devdax 模式大約會慢 2-3 倍。除了缺頁寫零之外還有哪些額外操作?
Perf 的輸出中可以明顯看到 fsdax 模式下有很多 memcpy\_flushcache 的調用。主要是走/不走 cache 的差别。
fsdax
43.25% copy_mem libpmem.so.1.0.0 [.] memmove_movnt_sse2_clwb
39.21% copy_mem [kernel.vmlinux] [k] memcpy_flushcache
devdax
86.16% copy_mem libpmem.so.1.0.0 [.] memmove_movnt_sse2_clwb
7.14% copy_mem libpmem.so.1.0.0 [.] memmove_nodrain_sse2_clwb
那麼為什麼 fsdax 會有很多 memcpy\_flushcache 的調用,而 devdax 沒有?從 perf 獲得的調用棧:
__libc_start_main
main
memmove_movnt_sse2_clwb
page_fault
do_page_fault
__do_page_fault
handle_mm_fault
__handle_mm_fault
__xfs_filemap_fault
dax_iomap_fault
xfs_file_iomap_begin
xfs_iomap_write_direct
xfs_bmapi_write
xfs_bmapi_convert_unwritten
blkdev_issue_zeroout
submit_bio_wait
submit_bio
generic_make_request
pmem_make_request
pmem_do_bvec
write_pmem
memcpy_flushcache
那麼 clwb 函數是怎麼定義的?查 libpmem 代碼即可。
[root@localhost libpmem]# grep -rwIn memmove_movnt_sse2_clwb /home/test/pmdk-sandbox/src
/home/test/pmdk-sandbox/src/libpmem/x86_64/memcpy/memcpy_nt_sse2_clwb.c:34:#define EXPORTED_SYMBOL memmove_movnt_sse2_clwb
/home/test/pmdk-sandbox/src/libpmem/x86_64/memcpy_memset.h:83:void memmove_movnt_sse2_clwb(char *dest, const char *src, size_t len);
注意上面那個 #define。找到對應的代碼:src/libpmem/x86\_64/memcpy/memcpy\_nt\_sse2.h
void
EXPORTED_SYMBOL(char *dest, const char *src, size_t len)
{
if ((uintptr_t)dest - (uintptr_t)src >= len)
memmove_movnt_sse_fw(dest, src, len);
else
memmove_movnt_sse_bw(dest, src, len);
maybe_barrier();
}
Since PMDK is in active development, the best practice is to read the code and follow the changes.
As for CLFLUSH、CLFLUSHOPT、CLWB's difference, read the code and refer to
http://research.cs.wisc.edu/sonar/tutorial/03-hardware.pdflinks to:
https://zedware.github.io