PMEM_MEMCPY_PERSIST(3)

πŸ’– PMEM_MEMCPY πŸ’–

okay bestie, welcome to pmem_memcpy(3) β€” that's the manpage name, and it lives in the PMDK Programmer's Manual. we're doing optimized copying to persistent memory today and honestly? it's giving main character energy. πŸŽ€


✨ NAME ✨

pmem_memmove(), pmem_memcpy(), pmem_memset(), pmem_memmove_persist(), pmem_memcpy_persist(), pmem_memset_persist(), pmem_memmove_nodrain(), pmem_memcpy_nodrain(), pmem_memset_nodrain() β€” functions that provide optimized copying to persistent memory 🌸


πŸ¦‹ SYNOPSIS πŸ¦‹

#include <libpmem.h>

void *pmem_memmove(void *pmemdest, const void *src, size_t len, unsigned flags);
void *pmem_memcpy(void *pmemdest, const void *src, size_t len, unsigned flags);
void *pmem_memset(void *pmemdest, int c, size_t len, unsigned flags);
void *pmem_memmove_persist(void *pmemdest, const void *src, size_t len);
void *pmem_memcpy_persist(void *pmemdest, const void *src, size_t len);
void *pmem_memset_persist(void *pmemdest, int c, size_t len);
void *pmem_memmove_nodrain(void *pmemdest, const void *src, size_t len);
void *pmem_memcpy_nodrain(void *pmemdest, const void *src, size_t len);
void *pmem_memset_nodrain(void *pmemdest, int c, size_t len);

look at all those lil guys πŸ’… nine whole functions, all of them handing back a pointer to your destination buffer. iconic.


πŸ’œ DESCRIPTION πŸ’œ

so pmem_memmove(), pmem_memcpy() and pmem_memset() do the exact same memory copying as their namesakes memmove(3), memcpy(3) and memset(3) β€” except they also make sure the result is flushed to persistence before returning. yeah. they actually wait for it. (unless you passed the PMEM_F_MEM_NOFLUSH flag, in which case, no they don't 🫢)

for example, this next lil block is functionally equivalent to pmem_memmove() (with flags equal to 0):

memmove(dest, src, len);
pmem_persist(dest, len);

but here's the tea: calling pmem_memmove() may out-perform that code, because the libpmem(7) implementation may take advantage of the fact that pmemdest is persistent memory, and use instructions such as non-temporal stores to avoid needing to flush processor caches at all. ✨

WARNING: Using these functions where pmem_is_pmem(3) returns false may not do anything useful. Use libc functions in that case. 😭 fr fr, check first.

and unlike the libc implementation, these libpmem functions guarantee that if the destination buffer address and length are 8 byte aligned, then all stores will be performed using at least 8 byte store instructions. which means: a series of 8 byte stores followed by pmem_persist(3) can be safely replaced by a single call to one of the above functions. one call. that's it. slay. πŸ‘‘


🌈 the flags argument 🌈

the flags argument of all of the above functions has the same meaning, every time. it can be 0, or a bitwise OR of one or more of the following flags:

  • PMEM_F_MEM_NODRAIN β€” modifies the behavior to skip the final pmem_drain() step. this lets applications optimize cases where several ranges are being copied to persistent memory, followed by a single call to pmem_drain(). the following example illustrates how this flag might be used to avoid multiple calls to pmem_drain() when copying several ranges of memory to pmem:
/* ... write several ranges to pmem ... */
pmem_memcpy(pmemdest1, src1, len1, PMEM_F_MEM_NODRAIN);
pmem_memcpy(pmemdest2, src2, len2, PMEM_F_MEM_NODRAIN);

/* ... */

/* wait for any pmem stores to drain from HW buffers */
pmem_drain();
  • PMEM_F_MEM_NOFLUSH β€” Don’t flush anything. This implies PMEM_F_MEM_NODRAIN. Using this flag only makes sense when it’s followed by any function that flushes data. πŸ‘€

the remaining flags say how the operation should be done, and are merely hints:

  • PMEM_F_MEM_NONTEMPORAL β€” Use non-temporal instructions. This flag is mutually exclusive with PMEM_F_MEM_TEMPORAL. On x86_64 this flag is mutually exclusive with PMEM_F_MEM_NOFLUSH.
  • PMEM_F_MEM_TEMPORAL β€” Use temporal instructions. This flag is mutually exclusive with PMEM_F_MEM_NONTEMPORAL.
  • PMEM_F_MEM_WC β€” Use write combining mode. This flag is mutually exclusive with PMEM_F_MEM_WB. On x86_64 this flag is mutually exclusive with PMEM_F_MEM_NOFLUSH.
  • PMEM_F_MEM_WB β€” Use write back mode. This flag is mutually exclusive with PMEM_F_MEM_WC. On x86_64 this is an alias for PMEM_F_MEM_TEMPORAL.
Using an invalid combination of flags has undefined behavior. πŸ’€ do NOT mix the mutually exclusive ones, bestie, i am begging.

without any of the above flags, libpmem will try to guess the best strategy based on size. see PMEM_MOVNT_THRESHOLD description in libpmem(7) for details. πŸ”


🧚 the aliases (the shortcut girlies) 🧚

  • pmem_memmove_persist() is an alias for pmem_memmove() with flags equal to 0.
  • pmem_memcpy_persist() is an alias for pmem_memcpy() with flags equal to 0.
  • pmem_memset_persist() is an alias for pmem_memset() with flags equal to 0.
  • pmem_memmove_nodrain() is an alias for pmem_memmove() with flags equal to PMEM_F_MEM_NODRAIN.
  • pmem_memcpy_nodrain() is an alias for pmem_memcpy() with flags equal to PMEM_F_MEM_NODRAIN.
  • pmem_memset_nodrain() is an alias for pmem_memset() with flags equal to PMEM_F_MEM_NODRAIN.

⭐ RETURN VALUE ⭐

All of the above functions return the address of the destination buffer. every single one. same answer. πŸ’–


πŸ™ˆ CAVEATS πŸ™ˆ

after calling any of the functions with the PMEM_F_MEM_NODRAIN flag, you should not expect memory to be visible to other threads before calling pmem_drain(3) or any of the _persist functions. 😭 why? because on x86_64 those functions may use non-temporal store instructions, which are weakly ordered. see β€œIntel 64 and IA-32 Architectures Software Developer’s Manual”, Volume 1, β€œCaching of Temporal vs. Non-Temporal Data” section for details. iykyk πŸ“š


🌸 SEE ALSO 🌸


that's the whole page, babe πŸ’œ this was PMDK, dated 2025-07-24 β€” go forth and persist your data responsibly, no cap. 🫢✨

πŸ“¦ where this page comes from