libpmemblk
libpmemblk 是用于管理固定大小数据块阵列的 C 库。它提供故障安全接口,以通过基于缓冲区的函数更新数据块。libpmemblk 仅用于需要简单固定数据块阵列,且不需要直接字节级访问数据块的情况。所以libpmemblk的接口简单且非常直接。在我们的示例中,主要使用的接口包括:
1.pbp = pmemblk_create(filename, ELEMENT_SIZE, POOL_SIZE, 0666);
2.pbp = pmemblk_open(filename, ELEMENT_SIZE);
3.nelements = pmemblk_nblock(pbp);
4.pmemblk_write(pbp, content, req_id)
5.pmemblk_read(pbp, buf, req_id)
所以这个库非常适合我们全文讨论的使用持久内存作为页缓存的需求。其实现示例 3所示:
示例 3 libpmemblk实现持久化页缓存
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libpmemblk.h>
#include <iostream>
#include <chrono>
#include <cassert>
/* size of the pmemblk pool -- 100 GB */
#define POOL_SIZE ((uint64_t)((1<< 30)*100UL))
/* size of each element in the pmem pool */
#define ELEMENT_SIZE 4096
// pmem block pool
PMEMblkpool *pbp;
size_t nelements;
int cbs_init(const char * filename)
{
/* create the pmemblk pool or open it if it already exists */
pbp = pmemblk_create(filename, ELEMENT_SIZE, POOL_SIZE, 0666);
if (pbp == NULL)
pbp = pmemblk_open(filename, ELEMENT_SIZE);
if (pbp == NULL) {
perror(filename);
return -1;
}
/* how many elements fit into the file? */
nelements = pmemblk_nblock(pbp);
printf("file holds %zu elements", nelements);
return 0;
}
int write_req(uint64_t req_id, unsigned char * content) {
assert(req_id < nelements);
if (pmemblk_write(pbp, content, req_id) < 0) {
perror("pmemblk_write");
return -1;
}
return 0;
}
void * read_req(uint64_t req_id, unsigned char * buf) {
assert(req_id<nelements);
/* read the block at index 10 (reads as zeros initially) */
if (pmemblk_read(pbp, buf, req_id) < 0) {
perror("pmemblk_read");
return NULL;
}
return buf;
}
#define WRITE_COUNT 100000
#define OVERWRITE_COUNT 10000
int main()
{
// calculate the time
unsigned char * read_content;
unsigned char * page_content=(unsigned char *)malloc(4096);
uint64_t i=0;
auto start=std::chrono::steady_clock::now();
auto stop=std::chrono::steady_clock::now();
std::chrono::duration<double> diff=stop-start;
memset(page_content,0xab,4096);
start=std::chrono::steady_clock::now();
cbs_init("/mnt/pmem0/cbs_pmblk");
stop=std::chrono::steady_clock::now();
diff=stop-start;
std::cout<<"cbs_init time"<<diff.count()<<std::endl;
//std::cout<<"cached page count"<<get_cached_count()<<std::endl;
start = std::chrono::steady_clock::now();
for(i=0;i<WRITE_COUNT;i++) {
write_req(i,page_content);
}
stop=std::chrono::steady_clock::now();
diff=stop-start;
std::cout<<"write_req time"<<diff.count()/WRITE_COUNT<<std::endl;
memset(page_content,0xcd,4096);
start = std::chrono::steady_clock::now();
for(i=0;i<OVERWRITE_COUNT;i++) {
write_req(i,page_content);
}
stop=std::chrono::steady_clock::now();
diff=stop-start;
std::cout<<"overwrite write_req update take time "<< diff.count()/OVERWRITE_COUNT<<std::endl;
start = std::chrono::steady_clock::now();
for(i=0;i<OVERWRITE_COUNT;i++) {
read_content=( unsigned char *)read_req(i,page_content);
}
stop=std::chrono::steady_clock::now();
diff=stop-start;
std::cout<<"overwrite read_req take time "<<diff.count()/OVERWRITE_COUNT<<std::endl;
printf("the page should fill with paten 0xcd, 0x%x\n", read_content[0]);
start = std::chrono::steady_clock::now();
for(i=OVERWRITE_COUNT;i<WRITE_COUNT;i++) {
read_content=( unsigned char *)read_req(i,page_content);
}
stop=std::chrono::steady_clock::now();
diff=stop-start;
std::cout<<"overwrite->write count read_req take time "<<diff.count()/(WRITE_COUNT-OVERWRITE_COUNT)<<std::endl;
printf("the page should fill with patern 0xab, 0x%x\n", read_content[0]);
pmemblk_close(pbp);
return 0;
}
编译“g++ cbs_req_pmemblk.cpp -o cbs_req_pmemblk -lpmemblk -O2”, 然后跑“taskset -c 2 ./cbs_req_pmemblk” ,第一次写4k是4.2us,第二次写是3us,读是1.35us.
➜ ~ taskset -c 2 ./cbs_req_pmemblk
file holds 26188559 elementscbs_init time0.0573344
write_req time4.19133e-06
overwrite write_req update take time 2.99101e-06
overwrite read_req take time 1.2958e-06
the page should fill with paten 0xcd, 0xcd
overwrite->write count read_req take time 1.348e-06
the page should fill with patern 0xab, 0xab
➜ ~ taskset -c 2 ./cbs_req_pmemblk
file holds 26188559 elementscbs_init time0.00895083
write_req time2.99173e-06
overwrite write_req update take time 2.92603e-06
overwrite read_req take time 1.27759e-06
the page should fill with paten 0xcd, 0xcd
overwrite->write count read_req take time 1.34219e-06
the page should fill with patern 0xab, 0xab
关注英特尔边缘计算社区,表示您确认您已年满 18 岁,并同意向英特尔分享个人信息,以便通过电子邮件和电话随时了解最新英特尔技术和行业趋势。您可以随时取消订阅。英特尔网站和通信内容遵守我们的隐私声明和使用条款。