78
63 {
64
char buf[BUF_LEN];
65
int cc;
66
67
/ *
68
* Copy the file,
69
* saving the last flush & drain step to the end
70
* /
71
while ((cc = read(srcfd, buf, BUF_LEN)) > 0) {
72
pmem_memcpy_nodrain(pmemaddr, buf, cc);
73
pmemaddr += cc;
74
}
75
76
if (cc < 0) {
77
perror("read");
78
exit(1);
79
}
80
81
/ * Perform final flush step * /
82
pmem_drain();
83 }
In Listing 6-5, pmem_memcpy_nodrain() is specifically designed for persistent
memory. When using other libraries and standard functions like memcpy(), remember
they were written before persistent memory existed and do not perform any flushing
to persistence. In particular, the memcpy() provided by the C runtime environment
often chooses between regular stores (which require flushing) and non-temporal stores
(which do not require flushing). It is making that choice based on performance, not
persistence. Since you will not know which instructions it chooses, you will need to
perform the flush to persistence yourself using pmem_persist() or msync().
The choice of instructions used when copying ranges to persistent memory is fairly
important to the performance in many applications. The same is true when zeroing out
ranges of persistent memory. To meet these needs, libpmem provides pmem_memmove(),
pmem_memcpy(), and pmem_memset(), which all take a flags argument to give the
caller more control over which instructions they use. For example, passing the flag
Chapter 6 libpmem: low-level persistent memory support
63 {
64
char buf[BUF_LEN];
65
int cc;
66
67
/ *
68
* Copy the file,
69
* saving the last flush & drain step to the end
70
* /
71
while ((cc = read(srcfd, buf, BUF_LEN)) > 0) {
72
pmem_memcpy_nodrain(pmemaddr, buf, cc);
73
pmemaddr += cc;
74
}
75
76
if (cc < 0) {
77
perror("read");
78
exit(1);
79
}
80
81
/ * Perform final flush step * /
82
pmem_drain();
83 }
In Listing 6-5, pmem_memcpy_nodrain() is specifically designed for persistent
memory. When using other libraries and standard functions like memcpy(), remember
they were written before persistent memory existed and do not perform any flushing
to persistence. In particular, the memcpy() provided by the C runtime environment
often chooses between regular stores (which require flushing) and non-temporal stores
(which do not require flushing). It is making that choice based on performance, not
persistence. Since you will not know which instructions it chooses, you will need to
perform the flush to persistence yourself using pmem_persist() or msync().
The choice of instructions used when copying ranges to persistent memory is fairly
important to the performance in many applications. The same is true when zeroing out
ranges of persistent memory. To meet these needs, libpmem provides pmem_memmove(),
pmem_memcpy(), and pmem_memset(), which all take a flags argument to give the
caller more control over which instructions they use. For example, passing the flag
Chapter 6 libpmem: low-level persistent memory support
