├── .gitignore ├── FAQ.txt ├── LICENSE ├── LINUX_PMEM_API.txt ├── Makefile ├── Makefile.inc ├── README ├── basic ├── .gitignore ├── Makefile ├── README ├── basic.c ├── basictest └── basictest.pass ├── binarytree ├── .gitignore ├── Makefile ├── README ├── freqtest ├── freqtest.pass ├── tree.c ├── tree.h ├── tree_free.c ├── tree_insert.c ├── tree_walk.c └── tree_wordfreq.c ├── icount ├── .gitignore ├── Makefile ├── README ├── allcounts ├── icount.c ├── icount.h ├── icount_test.c └── icount_test.pass ├── libpmem ├── .gitignore ├── LIBPMEM_API.txt ├── Makefile ├── README ├── pmem.c ├── pmem.h ├── pmem.map ├── pmem_cl.c ├── pmem_fit.c ├── pmem_inline.h └── pmem_msync.c ├── libpmemalloc ├── .gitignore ├── Makefile ├── PMEMALLOC_API.txt ├── README ├── design.txt ├── pmemalloc.c ├── pmemalloc.h ├── pmemalloc.map ├── pmemalloc_check.c ├── pmemalloc_test1.c ├── pmemalloc_test2.c ├── pmemalloctest └── pmemalloctest.pass ├── trivial ├── .gitignore ├── Makefile ├── README ├── trivial.c ├── trivialtest └── trivialtest.pass └── util ├── Makefile ├── README ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.o 3 | tags 4 | testfile* 5 | *.out 6 | -------------------------------------------------------------------------------- /FAQ.txt: -------------------------------------------------------------------------------- 1 | Why are these examples here? 2 | 3 | These examples are here for educational purposes, to illustrate 4 | some of the interesting issues around Persistent Memory programming. 5 | Start by reading the top-level README, then read the API document 6 | LINUX_PMEM_API.txt. Then start examining source code. First, 7 | trivial/trivial.c, then basic/basic.c, then take a look through 8 | the libpmemalloc example to see how one might approach the issues 9 | of Persistent Memory allocation and crash resiliency. 10 | 11 | These are just examples, meant to be simple, self-contained, 12 | simple C based files. See the REFERENCES section in the README 13 | for links to other more complex Persistent Memory work going on. 14 | 15 | For more information, questions or comments, contact: 16 | 17 | andy.rudoff@intel.com 18 | 19 | What is Persistent Memory? 20 | 21 | See the PERSISTENT MEMORY section in the top-level README. 22 | 23 | Where I can purchase Persistent Memory? 24 | 25 | Start by search for NVDIMM products, many of which meet the 26 | definition of Persistent Memory described in the README and 27 | should work fine with PMFS and the examples contained here. 28 | The press is frequently reporting more emerging Persistent 29 | Memory technologies as well. 30 | 31 | Can Persistent Memory be used transparently to applications? 32 | 33 | Certainly. One can easily imagine hardware completely managing 34 | Persistent Memory so that the Operating System and applications 35 | have no idea it is even installed in the system. Alternatively, 36 | one can imagine the OS using Persistent Memory itself but not 37 | exposing it to applications, so again it is transparent at the 38 | application level. 39 | 40 | The examples and APIs discussed here are for the non-transparent 41 | case, where an application wants to fully take advantage of 42 | Persistent Memory by deciding what data structures to store in it, 43 | when to access it, when to copy data into volatile memory and back, 44 | etc. Transparent use of Persistent Memory is also very interesting, 45 | but is beyond the scope of the examples in this repository. 46 | 47 | How do kernel modules use Persistent Memory? 48 | 49 | File systems like PMFS and other kernel modules that want to 50 | leverage Persistent Memory access it by calling into the device 51 | driver for the Persistent Memory. The PMFS team is working on 52 | getting their "NVM Volume" interfaces into the Linux kernel. 53 | But the in-kernel interfaces are beyond the scope of these 54 | examples -- they are for application-level programming. 55 | 56 | How do these examples compare with the Mnemosyne or NV Heaps work? 57 | 58 | If you are interesting in Persistent Memory programming, looking 59 | at the Mnemosyne and NV Heaps work is highly recommended. The 60 | examples here are meant to be very simple, working with existing 61 | compilers, and self-contained. So these examples do not build on 62 | those other works. It is our hope that these examples help 63 | stimulate even more examples and more PM-related research. 64 | 65 | What exactly do I need to do in order to make stores persistent? 66 | 67 | It depends on the Persistent Memory product, and on the platform 68 | it is installed in. Check with the manufacturer of the Persistent 69 | Memory you are using. For some examples, see the REFERENCES section 70 | of the top-level README. The idea is that the gory details on how 71 | you flush stores to the point of durability in Persistent Memory 72 | is contained in libraries like libpmem. See the Linux API document 73 | for a description of how your code can depend on libpmem for 74 | making stores persistent. 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Intel Corporation 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | * Neither the name of Intel Corporation nor the names of its 16 | contributors may be used to endorse or promote products derived 17 | from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /LINUX_PMEM_API.txt: -------------------------------------------------------------------------------- 1 | 2 | This is version 0.8 of LINUX_PMEM_API.txt. 3 | 4 | NAME 5 | Linux Persistent Memory Application Programming Interface 6 | 7 | SYNOPSIS 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | cc ... -lpmem 14 | 15 | /* open a Persistent Memory file */ 16 | fd = open("/path/to/pm-aware-filesystem/file", O_RDWR); 17 | 18 | /* map it */ 19 | base = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 20 | 21 | /* optional, instead of mmap line above: */ 22 | base = pmem_map(fd, len); 23 | 24 | /* ... use loads and stores to access PM at *base ... */ 25 | 26 | /* make changes persistent */ 27 | msync(addr, nbytes, MS_SYNC); 28 | 29 | /* optional, instead of msync line above: */ 30 | pmem_persist(addr, nbytes, 0); 31 | 32 | /* other interfaces described in this document... */ 33 | pmem_flush_cache(addr, len, flags); 34 | pmem_fence(); 35 | pmem_drain_pm_stores(); 36 | 37 | /* and many other POSIX file APIs... */ 38 | 39 | NOTE: If libpmem has not been installed on this system, you'll 40 | want to arrange for "pmem.h" to be included via a non-system 41 | path, and you'll want to arrange to either find libpmem to be 42 | using LD_LIBRARY_PATH or use the static version, libpmem.a. 43 | 44 | DESCRIPTION 45 | 46 | This document describes the Linux API for accessing Persistent 47 | Memory (PM). The Linux Persistent Memory API follows the 48 | "NVM.PM.FILE" programming model as described in the NVM Programming 49 | Model Specification published by the SNIA NVM Programming Technical 50 | Work Group (except as noted in the TODO section below). See 51 | http://www.snia.org/ for more information. 52 | 53 | The prerequisites to using this API are to install some Persistent 54 | Memory in your system and then expose that Persistent Memory using 55 | the appropriate device driver and a PM-aware file system such as PMFS 56 | (for more information on PMFS, see https://github.com/linux-pmfs). 57 | Of course, it is possible to develop code using these APIs without 58 | having actual Persistent Memory hardware available, for example by 59 | using volatile DRAM as "pretend" Persistent Memory. All the APIs 60 | below will work, but things like power failure testing will not be 61 | available during development. 62 | 63 | POSIX file APIs 64 | 65 | The PM-aware file system exposes Persistent Memory as 66 | files, so POSIX file APIs work as expected. This includes 67 | the obvious basic operations, such as: 68 | 69 | open(2) 70 | close(2) 71 | read(2) 72 | write(2) 73 | fsync(2) 74 | mmap(2) 75 | msync(2) 76 | 77 | and typically includes the most common operations for 78 | managing files, such as: 79 | 80 | chmod(2) 81 | chown(2) 82 | closedir(3) 83 | creat(2) 84 | lseek(2) 85 | madvise(2) 86 | mkdir(2) 87 | mprotect(2) 88 | opendir(3) 89 | readdir(3) 90 | readlink(2) 91 | rename(2) 92 | rmdir(2) 93 | symlink(2) 94 | utimes(2) 95 | ... and many more ... 96 | 97 | In fact, most C library calls designed to operate on files 98 | will work with Persistent Memory just like they work with 99 | other file systems. Like any file system, a PM-aware file 100 | system may or may not implement all possible interfaces, 101 | returning "Not supported" for some of them. 102 | 103 | Another aspect of a PM-aware file system is that Persistent 104 | Memory files can be managed using common command-line 105 | utilities like cp, mv, ls, and tar. 106 | 107 | int open(const char *pathname, int flags, mode_t mode); 108 | 109 | To begin accessing Persistent Memory, open(2) is used 110 | just as it would be for any other file. The open mode 111 | specifies whether the file is opened read-only (O_RDONLY), 112 | for read/write (O_RDWR), etc. See the open(2) man page 113 | for details. 114 | 115 | void *mmap(void *addr, size_t length, int prot, int flags, 116 | int fd, off_t offset); 117 | 118 | The next step to using Persistent Memory is to map it 119 | into the address space of the process using mmap(2). 120 | For Persistent Memory, the flag MAP_SHARED is most 121 | commonly used, providing the application with direct 122 | access to the Persistent Memory. For traditional files, 123 | using mmap this way will "demand-page" data in and out 124 | of the system page cache as it is accessed. This results 125 | in unpredictable latencies, much longer when page faults 126 | happen to occur. But with Persistent Memory, the page cache 127 | is avoided, providing direct, uniform access to the memory 128 | itself. 129 | 130 | The flag MAP_PRIVATE may be used, in which case reads will 131 | come directly from Persistent Memory until a page is written 132 | for the first time. At that point, a copy-on-write will 133 | happen and the modified page will be located in volatile DRAM. 134 | MAP_PRIVATE pages are never written back to Persistent Memory 135 | and are discarded when the process calls munmap(2) or it 136 | exits. 137 | 138 | See the man page mmap(2) for details on this interface. 139 | 140 | void *pmem_map(int fd, size_t len); 141 | 142 | This function is just a convenience function that calls 143 | mmap(2) with the appropriate arguments. It is entirely 144 | programmer preference on whether you use this function or 145 | call mmap directly. Returns NULL with errno set on failure. 146 | 147 | int msync(void *addr, size_t length, int flags); 148 | 149 | Force any changes in the range [addr, addr+len) to be stored 150 | durably in Persistent Memory. POSIX specifies (and Linux 151 | enforces) that addr must be page-aligned, which may force 152 | the call to flush more data than required. See pmem_persist() 153 | below for an alternate solution. Note that the traditional 154 | definition of msync is to search the "page cache" for dirty 155 | pages. But for Persistent Memory, the page cache is not 156 | involved and msync's effect is more related to flushing dirty 157 | data from the processor's cache and other HW buffers to make 158 | sure it is fully persistent. 159 | 160 | WARNING: The semantics of msync(2) have always been to 161 | check for unwritten changes and write them out. 162 | Nothing prevents changes from being written out 163 | before msync is called and no atomic or transactional 164 | behavior is implied by the msync call. It is a 165 | "flush" operation to catch anything that hasn't 166 | been flushed already. 167 | 168 | See the man page msync(2), and the related pages mprotect(2) 169 | and madvise(2) for more information. 170 | 171 | void pmem_persist(void *addr, size_t len, int flags); 172 | 173 | Force any changes in the range [addr, addr+len) to be stored 174 | durably in Persistent Memory. This is equivalent to calling 175 | msync(2) as described above, but may be more optimal and will 176 | avoid calling into the kernel if possible. 177 | 178 | No flags have been defined for this call yet. 179 | 180 | WARNING: Like msync(2) described above, there is nothing 181 | atomic or transactional about this call. Any 182 | unwritten stores in the given range will be written, 183 | but some stores may have already been written by 184 | virtue of normal cache eviction/replacement policies. 185 | Correctly written code must not depend on stores 186 | waiting until pmem_persist() is called to become 187 | persistent -- they can become persistent at any time 188 | before pmem_persist() is called. 189 | 190 | void pmem_flush_cache(void *addr, size_t len, int flags); 191 | void pmem_fence(void); 192 | void pmem_drain_pm_stores(void); 193 | 194 | These three functions provide partial versions of the 195 | pmem_persist() function described above. pmem_persist() 196 | can be thought of as this: 197 | 198 | void pmem_persist(void *addr, size_t len, int flags) 199 | { 200 | /* flush the processor caches */ 201 | pmem_flush_cache(addr, len, flags); 202 | 203 | /* Persistent Memory store barrier */ 204 | pmem_fence(); 205 | 206 | /* wait for any PM stores to drain from HW buffers */ 207 | pmem_drain_pm_stores(); 208 | } 209 | 210 | These functions allow advanced programs to create their 211 | own variations of pmem_persist(). For example, a program 212 | that needs to flush several discontiguous ranges can call 213 | pmem_flush_cache() for each range and then follow up by 214 | calling the pmem_fence() and pmem_drain_pm_stores() once. 215 | 216 | SEE ALSO 217 | open(2), mmap(2), msync(2), mprotect(2), madvise(2) 218 | 219 | TODO 220 | 221 | - Add support for the get/set attributes actions defined by the SNIA 222 | NVM.PM.FILE programming model. 223 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile -- top-level Makefile for Persistent Memory examples 33 | # 34 | # Use "make all" to build all examples. 35 | # 36 | # Use "make clean" to delete all intermediate files (*.o, etc). 37 | # 38 | # Use "make clobber" to delete everything re-buildable (binaries, etc.). 39 | # 40 | SUBDIRS = basic\ 41 | binarytree\ 42 | icount\ 43 | libpmem\ 44 | libpmemalloc\ 45 | trivial\ 46 | util 47 | 48 | all : TARGET = all 49 | clean : TARGET = clean 50 | clobber : TARGET = clobber 51 | test : TARGET = test 52 | 53 | all clean clobber test: $(SUBDIRS) 54 | 55 | $(SUBDIRS): 56 | $(MAKE) -C $@ $(TARGET) 57 | 58 | .PHONY: all clean clobber test $(SUBDIRS) 59 | -------------------------------------------------------------------------------- /Makefile.inc: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile.inc -- common Makefile definitions for PM examples 33 | # 34 | # Some of the examples use this file to simplify their Makefiles. 35 | # Examples that build as shared libraries or self-comtained files 36 | # don't benefit from this include file and just use stand-alone 37 | # Makefiles. 38 | # 39 | INCS = -I.. 40 | CFLAGS = -ggdb -Wall -Werror 41 | 42 | all: $(TARGETS) 43 | 44 | $(TARGETS): $(OBJS) $(LIBFILES) 45 | $(CC) -o $@ $(CFLAGS) $^ $(LIBFILES) $(LIBS) 46 | 47 | .c.o: 48 | $(CC) -c $(CFLAGS) $(INCS) $< -o $@ 49 | 50 | util.o: ../util/util.c ../util/util.h 51 | $(CC) -c -o $@ $(CFLAGS) $(INCS) $< 52 | 53 | icount.o: ../icount/icount.c ../icount/icount.h 54 | $(CC) -c -o $@ $(CFLAGS) $(INCS) $< 55 | 56 | ../libpmem/libpmem.a: force 57 | $(MAKE) -C ../libpmem 58 | 59 | ../libpmemalloc/libpmemalloc.a: force 60 | $(MAKE) -C ../libpmemalloc 61 | 62 | clean: 63 | $(RM) *.o core a.out testfile* 64 | 65 | clobber: clean 66 | $(RM) $(TARGETS) $(CLOBBERFILES) 67 | 68 | force: 69 | 70 | .PHONY: all clean clobber force allcounts test 71 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | LINUX EXAMPLES for PERSISTENT MEMORY PROGRAMMING 2 | 3 | This is the top-level README for the linux-examples repository. 4 | 5 | PLEASE NOTE: THIS REPOSITORY IS PROBABLY NOT WHAT YOU WANT! 6 | 7 | These examples were created as a way to explore the programming 8 | issues that come up with persistent memory. Since these examples 9 | were first written, the NVM Library has been developed as a tested 10 | and documented way to support persistent memory. You want NVML instead 11 | of the files here (this repo is just here for historical interest). 12 | 13 | GO HERE: https://github.com/pmem/nvml 14 | 15 | OR READ MORE ABOUT PMEM PROGRAMMING HERE: http://pmem.io 16 | 17 | 18 | 19 | This repository contains some exploratory ideas, used to 20 | illustrate the challenges of Persistent Memory programming. 21 | 22 | The goal is to build up a collection of simple examples to help people 23 | understand how Persistent Memory is exposed to applications. These are 24 | NOT PRODUCTION-QUALITY examples. They are educational snippets of code 25 | to illustrate some basic concepts. See the REFERENCES section below for 26 | more mature frameworks. 27 | 28 | These examples are built on the Linux Persistent Memory API described in: 29 | 30 | LINUX_PMEM_API.txt 31 | 32 | 33 | PERSISTENT MEMORY 34 | 35 | Persistent Memory is an emerging technology providing a new tier between 36 | traditional storage and volatile memory with attributes from both. The 37 | two main qualities of Persistent Memory are that it appears byte-addressable 38 | to applications (allowing direct load/store access rather than the block-based 39 | access of traditional storage) and that it is persistent. The term 40 | Persistent Memory (PM), and the related term Storage Class Memory (SCM), 41 | may not have formal definitions that everyone agrees on, but these terms 42 | usually refer to memory that an application can access directly, without 43 | demand-paging blocks in and out of a storage device. The performance of 44 | PM is typically such that a processor load instruction can reasonably wait 45 | for data from PM (instead of context switching while a page fault is 46 | serviced). Therefore technologies like hard disks and NAND Flash are not 47 | considered fast enough by themselves. A PM product built on those 48 | technologies would have some additional hardware built in to maintain the 49 | performance expected by the processor during direct access. 50 | 51 | A number of Non-Volatile Memory (NVM) technologies emerging, like Phase 52 | Change Memory, Memristor, Spin-Toque, and others, may bring us into an 53 | era of very large PM capacities with performance more like DRAM than 54 | traditional storage. This is appealing for applications requiring access 55 | to large data sets, without the huge DRAM footprint and non-deterministic 56 | access times seen when demand-paging is used. Once you imagine applications 57 | storing information in PM, you quickly realize the need for a way to name 58 | regions of PM so that applications can re-connect to their data on start-up. 59 | Next, the need for a permission model and an administrative model for 60 | managing PM comes up (creating, deleting, backing it up, etc.). The 61 | industry direction for exposing PM to applications is for PM regions to 62 | be exposed via the native file APIs on an OS, or something very similar 63 | (see the SNIA information in the REFERENCES section below). That's the 64 | approach taken with the examples found here. An example of a 65 | Persistent-Memory-Aware file system that provides PM via native Linux file 66 | APIs is PMFS, available at: 67 | 68 | https://github.com/linux-pmfs 69 | 70 | So when PM is accessed by memory mapping files, how is that different 71 | from traditional memory mapped files that have been a feature of many 72 | operating systems for decades? If one writes a program that memory-maps 73 | a normal file using the Linux mmap(2) system call, accesses it with loads 74 | and stores, and makes changes durable using the Linux msync(2) system 75 | call, will that program work without modification on a PM file? Yes. 76 | But with a traditional file system, access to the memory-mapped file is 77 | actually paging data in and out of DRAM; mapping a file and changing 78 | a single byte involves a page fault (including a context switch or two), 79 | where a 4k block is read from storage into memory and a subsequent write 80 | of that 4k block to make the change durable. With PM, it is possible to 81 | change that byte directly from the program, without waiting for page faults 82 | or using any DRAM buffers. On PM the impact of changing a byte of data 83 | is likely much less than a page (probably more like a cache-line read 84 | so the change can happen in the processor cache, followed by a cache-line 85 | flush to make the change durable). 86 | 87 | 88 | EXAMPLES 89 | 90 | Each example occupies a sub-directory here and the README in each 91 | sub-directory tells you why the example was written. The README also 92 | described how to run the example and what unit tests are available. At 93 | this top level, "make all" builds every example, "make clean" clears out 94 | intermediate files for all examples, and "make clobber" removes anything 95 | that is recreatable for all examples. 96 | 97 | Since these are for educational use, no attempt has been made to optimize 98 | them for performance, or even make then run on anything but Linux x86_64 99 | (they were all tested on a 64-bit Debian-based distro running the 3.2 kernel 100 | and gcc 4.7.2 initially). Most of the examples are not MT-safe (unless 101 | making something MT-safe was part of the example). All the examples are 102 | written in C and depend on nothing but libc and the code in this repo. 103 | This is to keep things simple and illustrate the low-level primitives for 104 | Persistent Memory. Hopefully over time some higher-level language support 105 | will become commonplace and we'll add additional examples as they become 106 | available. See the TODO section below for some ideas if you're looking to 107 | contribute. 108 | 109 | As mentioned in the previous section, calling msync(2) to make stores 110 | to PM durable will work but since PM is directly-accessible, there may 111 | be more optimal ways available with some PM products. For the purposes 112 | of these examples, a library, libpmem, has been provided and it includes 113 | this function which can be used instead of msync: 114 | 115 | pmem_persist(addr, len, flags) 116 | 117 | See libpmem/README for more details on the methods available and the 118 | assumptions each method makes about the platform. 119 | 120 | What you'll find here: 121 | 122 | LICENSE The BSD license under which this code is available. 123 | 124 | LINUX_PMEM_API.txt The Linux Persistent Memory API, which is 125 | primarily the decades-old memory-mapped file 126 | API (part of POSIX) with a few optional 127 | things added to it. 128 | 129 | FAQ.txt Frequently asked questions about Persistent Memory 130 | and about these examples. 131 | 132 | trivial A simple, self-contained, trivial example. If you 133 | don't know how to use mmap(2)/msync(2) or if you need 134 | a reminder how they are used, start here. It is 135 | only a small step above just typing "man mmap" but 136 | the example is explained, runnable, and includes 137 | a trivial test you can play with. 138 | 139 | basic A very basic example. It can store a few strings 140 | to PM and it can read the strings already stored 141 | there. This is the simplest example based on libpmem, 142 | so it is a good place to start to understand how that 143 | library is used. 144 | 145 | See basic/README for details on how to run & test 146 | this example, and how to use it with the "icount" 147 | fault injection test mechanism. 148 | 149 | libpmem This library provides an optional part of the 150 | Linux Persistent Memory API. It is "optional" 151 | because it is perfectly possible to use PM without 152 | this library (as shown by the "trivial" example 153 | described above). But with this library, PM 154 | programming is more convenient and some operations 155 | are optimized. If you're looking for examples of 156 | PM programming, reading this code won't help you -- 157 | look at examples like trivial, basic, and binarytree. 158 | 159 | libpmemalloc A simple PM malloc-like library. If you're 160 | looking for some basic ideas to get you going 161 | managing data structures in PM in a way that keeps 162 | them consistent across crashes, this might be 163 | a good place to start. libpmemalloc/README explains 164 | how the malloc-like library is used and tested, 165 | and the file libpmemalloc/design.txt explains the 166 | simple design that went into making it resilient 167 | against crashes. Don't forget to read about much 168 | more complete PM memory allocation solutions in the 169 | REFERENCES section below. 170 | 171 | binarytree Building on the libpmemalloc example, this is a 172 | small example of a binary tree used to count the 173 | frequency of variable length strings. 174 | 175 | util Some common routines for error reporting and 176 | debug prints. These have nothing to do with 177 | Persistent Memory. 178 | 179 | icount Routines to count instructions and simulate crashes. 180 | These are used for the fault injection runs where 181 | we run a test, count the instructions executed by 182 | the code snippet under test, and then re-run the test 183 | again and again, simulating a crash between every pair 184 | of instructions in the code snippet. See 185 | icount/README for details or you can see this is 186 | action by running "make allcounts" in the basic 187 | sub-directory. 188 | 189 | 190 | CODING CONVENTIONS 191 | 192 | Some of the examples store relative pointers in PM data structures 193 | so that those pointers remain valid even if the PM gets mapped into 194 | a different virtual address on subsequent runs (which is almost always 195 | the case). There are multiple discussions on how to deal with this in 196 | papers mentioned in REFERENCES below. For these examples, we take a very 197 | basic approach, making it the programmer's responsibility to keep track 198 | of which pointers are relative and which are absolute. In the examples, 199 | you often see pointers with a trailing underscore, like this: 200 | 201 | sp->root_ 202 | 203 | the convention is that the trailing underscore is a reminder to the 204 | programmer that you cannot dereference that pointer without first adding 205 | the "base" of the PM to it. The libpmemalloc example creates a macro 206 | to do this called PMEM(). Compilers like the Microsoft C++ compiler have a 207 | nifty "based pointer" mechanism so that the compiler largely takes care of 208 | this for the programmer. But gcc has no such feature, so we're forced to 209 | do it by hand. At least until languages begin to grow more mature PM 210 | programming features. 211 | 212 | Another small convention is that global variables have their first 213 | letter capitalized. Beyond that, the code is basically K&R-style. 214 | 215 | 216 | TESTING 217 | 218 | For many years, file system implementers have carefully designed their 219 | data structures to recover from unexpected system crashes (power failures, 220 | kernel crashes, hardware failures). This means designing in enough 221 | persistent information so that recovery after a crash can return the on-disk 222 | format to a consistent state. The emergence of Persistent Memory brings 223 | all that logic into application space. A traditional program might allocate 224 | memory like this: 225 | 226 | struct node *np; 227 | 228 | np = malloc(sizeof(*np)); 229 | /* ... fill in *np ... */ 230 | parent->next = np; 231 | 232 | With Persistent Memory, using a malloc-style interface as shown above 233 | would lead to a memory leak of the Persistent Memory between the point 234 | when malloc() removes the chunk from the free pool and the point where 235 | a persistent pointer is set to point at the newly-allocated memory. Many 236 | strategies for handling this issue are available, including logging and 237 | reference counting. But these algorithms can be difficult to test because 238 | it is difficult to simulate failures at the most vulnerable points in the 239 | algorithms. 240 | 241 | Most of the examples include test programs. To validate that PM-resident 242 | data structures are managed in a way that is resilient to crashes, the 243 | icount code is used. icount (described more in icount/README) provides a 244 | way to count the instructions executed in a test snippet of code, and then 245 | re-run that code again and again, simulating a crash between every possible 246 | pair of instructions in the test snippet. Run "make allcounts" in the 247 | basic sub-directory for a demo. Using the icount mechanism can be very, 248 | very time consuming. 249 | 250 | Note the difference between a "make allcounts" run for the basic example 251 | and a "make allcounts" run for the tree example. In the basic example, 252 | the program just stores to PM and the simulated crashes leave the PM in 253 | random states, showing partial strings and other garbage. Compare that 254 | to the tree example, which uses libpmemalloc to make sure things stay 255 | consistent across crashes. In that example, when a tree_insert() is 256 | interrupted by a crash, the string being inserted either makes it completely 257 | into the tree or it doesn't. And in the case where it doesn't, no Persistent 258 | Memory is leaked. That's because the tree example is built on the atomic 259 | mechanisms in libpmemalloc, and that's the point of these examples. 260 | 261 | 262 | CONTACTS 263 | 264 | If you'd like to contribute more Persistent Memory programming examples 265 | (and we really hope you will!), please fork this project on github, add 266 | your example, and send a pull request. 267 | 268 | For more information, questions or comments, contact: 269 | 270 | andy.rudoff@intel.com 271 | 272 | 273 | REFERENCES 274 | 275 | Some very interesting research has been happening in the area of 276 | Persistent Memory and more is emerging. While the examples provided 277 | here are meant as introductory and simple, some publications cover 278 | the topic in much more depth and include complete transaction systems, 279 | compiler/language enhancements, etc. Here are some of the most 280 | important publications in this space (please send links to more and 281 | I'll include them). 282 | 283 | - A Persistent Memory aware file system for Linux. Under development at: 284 | 285 | https://github.com/linux-pmfs 286 | 287 | - One of the most impressive bodies of work in this area is Mnemosyne. 288 | Read the paper: 289 | 290 | Haris Volos, Andres Jaan Tack, Michael M. Swift: Mnemosyne: 291 | Lightweight Persistent Memory, The 16th ACM Conference on 292 | Architectural Support for Programming Languages and Operating 293 | Systems (ASPLOS 2011), March 2011, Newport Beach, California. 294 | 295 | and explore the website, which includes full source and documentation: 296 | 297 | http://research.cs.wisc.edu/sonar/projects/mnemosyne/ 298 | 299 | - Another very relevant project is NV-Heaps. Read the paper: 300 | 301 | J. Coburn, et al.:NV-Heaps: Making Persistent Objects Fast and Safe 302 | with Next Generation, Non-Volatile Memories, The 16th ACM Conference 303 | on Architectural Support for Programming Languages and Operating 304 | Systems (ASPLOS 2011), March 2011, Newport Beach, Ca. 305 | 306 | - The June 2013 issue of USENIX ;login: contains an article that discusses 307 | the NVM Programming Model, including a discussion of Persistent Memory. 308 | 309 | https://www.usenix.org/publications/login/june-2013-volume-38-number-3 310 | 311 | - The NVM Programming Technical Work Group (TWG) in SNIA has over 35 312 | companies working together on NVM programming models, including 313 | Persistent Memory. You can read more about the TWG here: 314 | 315 | http://www.snia.org/tech_activities/work/twgs 316 | 317 | and see a draft of their specification here: 318 | 319 | http://www.snia.org/tech_activities/publicreview 320 | 321 | - Viking Technology has an excellent FAQ on their NVDIMMs, providing an 322 | excellent overview of the platform requirements including a description 323 | of the ADR feature assumed by some of these example programs: 324 | 325 | http://www.vikingtechnology.com/nvdimm-faq 326 | 327 | - The basics of NVDIMM at Wikipedia, with lots of additional links: 328 | 329 | http://en.wikipedia.org/wiki/NVDIMM 330 | 331 | TODO 332 | 333 | Here are some ideas of examples we'd like to add to this collection next: 334 | 335 | - A transaction-based example, using an undo or redo log for consistency 336 | - An example using many files, perhaps with pointers between them 337 | - MT-safe versions of some the examples 338 | - Shared memory examples (multi-process sharing in addition to multi-thread) 339 | - An example of a Persistent cache built on PM 340 | - Bindings for other languages like Java, Python, etc. 341 | - Abstractions that fit into other languages (like Java Persistence API) 342 | -------------------------------------------------------------------------------- /basic/.gitignore: -------------------------------------------------------------------------------- 1 | basic 2 | -------------------------------------------------------------------------------- /basic/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile for basic example 33 | # 34 | TARGETS = basic 35 | OBJS = basic.o util.o icount.o 36 | LIBFILES = ../libpmem/libpmem.a 37 | 38 | include ../Makefile.inc 39 | 40 | # 41 | # The allcounts entry point runs basic via the allcounts 42 | # script, which will simulate a crash between every two adjacent 43 | # instructions in the test code snippet in basic.c. 44 | # The allcount script will then summarize the results of all the runs. 45 | # 46 | # This takes a while to run. 47 | # 48 | CMD = rm -f testfile%C; ./basic -i %C testfile%C short1 "this string is designed to be longer than can fit in a 64-byte cacheline" short2; ./basic testfile%C 49 | CMDF = rm -f testfile%C; ./basic -F -i %C testfile%C short1 "this string is designed to be longer than can fit in a 64-byte cacheline" short2; ./basic testfile%C 50 | CMDM = rm -f testfile%C; ./basic -M -i %C testfile%C short1 "this string is designed to be longer than can fit in a 64-byte cacheline" short2; ./basic testfile%C 51 | 52 | allcounts: basic 53 | @../icount/allcounts -j 200 '$(CMD)' 54 | @rm -f testfile* 55 | 56 | allcountsF: basic 57 | @../icount/allcounts -j 200 '$(CMDF)' 58 | @rm -f testfile* 59 | 60 | allcountsM: basic 61 | @../icount/allcounts -j 200 '$(CMDM)' 62 | @rm -f testfile* 63 | 64 | test: basic basictest 65 | @./basictest 2>&1 | tee basictest.out 66 | @cmp -s basictest.out basictest.pass || (echo FAIL: basictest.out does not match basictest.pass; false) 67 | @echo PASS 68 | 69 | .PHONY: allcounts allcountsF allcountsM test 70 | -------------------------------------------------------------------------------- /basic/README: -------------------------------------------------------------------------------- 1 | This is basic/README. 2 | 3 | This is a very basic example of a program storing some data to 4 | Persistent Memory and then reading it back later. This example 5 | also illustrates how to use libpmem to make sure stores are durable. 6 | 7 | usage: basic [-FMd] [-i icount] path [strings...] 8 | 9 | Where is a file on a Persistent Memory aware file system 10 | like PMFS. If path doesn't exist, this program will create it 11 | with size DEFAULT_SIZE (defined below). 12 | 13 | Any strings provided will be written to the Persistent Memory, 14 | each terminated by a '\0' character. If no strings are 15 | provided, the Persistent Memory is dumped out in a manner similar 16 | to strings(1). 17 | 18 | The -F flag enables the fault injection testing version of libpmem. 19 | This for more meaningful icount-based runs (see the -i flag below). 20 | 21 | The -M flag enables the msync-based version of libpmem. 22 | Use this when you don't have a PM-aware file system and you're 23 | running on traditional memory-mapped files instead. 24 | 25 | The -d flag turns on debugging prints. 26 | 27 | The -i flag, if given, turns on instruction counting for the 28 | code snippet under test (the code between icount_start() and 29 | icount_stop() below). Use "-i 0" to print the count, "-i N" 30 | to simulate a crash after N instructions. For more accurate 31 | fault injection testing, use this with the -F flag described above. 32 | 33 | Here are examples of how to run the basic code: 34 | 35 | basic testfile one two three 36 | basic testfile 37 | 38 | Also, you can run the fault injection test using: 39 | 40 | make allcounts 41 | 42 | This takes a while to run. Notice how the fault injection tests show you 43 | only parts of strings getting stored in some crash scenarios. This example 44 | illustrates how your Persistent Memory data structures can be in unexpected 45 | states due to system interruptions or program crashes. Compare this example 46 | with something like the linked-list test in ../libpmemalloc, where extra 47 | work is done to prevent half-done entries into the PM data structure. 48 | -------------------------------------------------------------------------------- /basic/basic.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * basic.c -- illustrate basic load/store operations on PM 35 | * 36 | * usage: basic [-FMd] [-i icount] path [strings...] 37 | * 38 | * Where is a file on a Persistent Memory aware file system 39 | * like PMFS. If path doesn't exist, this program will create it 40 | * with size DEFAULT_SIZE (defined below). 41 | * 42 | * Any strings provided will be written to the Persistent Memory, 43 | * each terminated by a '\0' character. If no strings are 44 | * provided, the Persistent Memory is dumped out in a manner similar 45 | * to strings(1). 46 | * 47 | * The -F flag enables the fault injection testing version of libpmem. 48 | * This for more meaningful icount-based runs (see the -i flag below). 49 | * 50 | * The -M flag enables the msync-based version of libpmem. 51 | * Use this when you don't have a PM-aware file system and you're 52 | * running on traditional memory-mapped files instead. 53 | * 54 | * The -d flag turns on debugging prints. 55 | * 56 | * The -i flag, if given, turns on instruction counting for the 57 | * code snippet under test (the code between icount_start() and 58 | * icount_stop() below). Use "-i 0" to print the count, "-i N" 59 | * to simulate a crash after N instructions. For more accurate 60 | * fault injection testing, use this with the -F flag described above. 61 | */ 62 | 63 | #define DEFAULT_SIZE 8192 64 | 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | 75 | #include "util/util.h" 76 | #include "icount/icount.h" 77 | #include "libpmem/pmem.h" 78 | 79 | char Usage[] = "[-FMd] [-i icount] path [strings...]"; /* for USAGE() */ 80 | 81 | int 82 | main(int argc, char *argv[]) 83 | { 84 | int opt; 85 | int iflag = 0; 86 | unsigned long icount; 87 | const char *path; 88 | struct stat stbuf; 89 | size_t size; 90 | int fd; 91 | char *pmaddr; 92 | 93 | Myname = argv[0]; 94 | while ((opt = getopt(argc, argv, "FMdi:")) != -1) { 95 | switch (opt) { 96 | case 'F': 97 | pmem_fit_mode(); 98 | break; 99 | 100 | case 'M': 101 | pmem_msync_mode(); 102 | break; 103 | 104 | case 'd': 105 | Debug++; 106 | break; 107 | 108 | case 'i': 109 | iflag++; 110 | icount = strtoul(optarg, NULL, 10); 111 | break; 112 | 113 | default: 114 | USAGE(NULL); 115 | } 116 | } 117 | 118 | if (optind >= argc) 119 | USAGE("No path given"); 120 | path = argv[optind++]; 121 | 122 | if (stat(path, &stbuf) < 0) { 123 | /* 124 | * file didn't exist, create it with DEFAULT_SIZE 125 | */ 126 | if ((fd = open(path, O_CREAT|O_RDWR, 0666)) < 0) 127 | FATALSYS("can't create %s", path); 128 | 129 | if ((errno = posix_fallocate(fd, 0, DEFAULT_SIZE)) != 0) 130 | FATALSYS("posix_fallocate"); 131 | 132 | size = DEFAULT_SIZE; 133 | } else { 134 | /* 135 | * file exists, just open it 136 | */ 137 | if ((fd = open(path, O_RDWR)) < 0) 138 | FATALSYS("open %s", path); 139 | 140 | size = stbuf.st_size; 141 | } 142 | 143 | /* 144 | * map the file into our address space. 145 | */ 146 | if ((pmaddr = pmem_map(fd, size)) == NULL) 147 | FATALSYS("pmem_map"); 148 | 149 | if (optind < argc) { /* strings supplied as arguments? */ 150 | int i; 151 | char *ptr = pmaddr; 152 | 153 | if (iflag) 154 | icount_start(icount); /* start instruction count */ 155 | 156 | for (i = optind; i < argc; i++) { 157 | size_t len = strlen(argv[i]) + 1; /* includes '\0' */ 158 | 159 | if (len > size) 160 | FATAL("no more room for %d-byte string", len); 161 | 162 | /* store to Persistent Memory */ 163 | strcpy(ptr, argv[i]); 164 | 165 | /* make that change durable */ 166 | pmem_persist(ptr, len, 0); 167 | 168 | ptr += len; 169 | size -= len; 170 | } 171 | 172 | if (iflag) { 173 | icount_stop(); /* end instruction count */ 174 | 175 | printf("Total instruction count: %lu\n", 176 | icount_total()); 177 | } 178 | } else { 179 | char *ptr = pmaddr; 180 | char *sep = ""; 181 | 182 | /* 183 | * dump out all the strings we find in Persistent Memory 184 | */ 185 | while (ptr < &pmaddr[size]) { 186 | 187 | /* load from Persistent Memory */ 188 | if (isprint(*ptr)) { 189 | putc(*ptr, stdout); 190 | sep = "\n"; 191 | } else if (*ptr == '\0') { 192 | fputs(sep, stdout); 193 | sep = ""; 194 | } 195 | 196 | ptr++; 197 | } 198 | } 199 | 200 | exit(0); 201 | } 202 | -------------------------------------------------------------------------------- /basic/basictest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2013, Intel Corporation 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # 17 | # * Neither the name of Intel Corporation nor the names of its 18 | # contributors may be used to endorse or promote products derived 19 | # from this software without specific prior written permission. 20 | # 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | # 34 | # basictest -- unit test for basic example code 35 | # 36 | # basictest.pass contains the output this script generates if the test passes. 37 | # 38 | 39 | nflag= 40 | while getopts '' opt 41 | do 42 | case $opt in 43 | n) 44 | nflag=1 45 | ;; 46 | ?) 47 | echo "Usage: $0" >&2 48 | exit 1 49 | ;; 50 | esac 51 | done 52 | 53 | set -e 54 | 55 | echo Running test... 56 | echo rm -f testfile 57 | rm -f testfile 58 | echo ./basic testfile one two three four 59 | ./basic testfile one two three four 60 | echo ./basic testfile 61 | ./basic testfile 62 | 63 | od -c testfile 64 | 65 | echo Done. 66 | 67 | exit 0 68 | 69 | -------------------------------------------------------------------------------- /basic/basictest.pass: -------------------------------------------------------------------------------- 1 | Running test... 2 | rm -f testfile 3 | ./basic testfile one two three four 4 | ./basic testfile 5 | one 6 | two 7 | three 8 | four 9 | 0000000 o n e \0 t w o \0 t h r e e \0 f o 10 | 0000020 u r \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 11 | 0000040 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 12 | * 13 | 0020000 14 | Done. 15 | -------------------------------------------------------------------------------- /binarytree/.gitignore: -------------------------------------------------------------------------------- 1 | tree_insert 2 | tree_walk 3 | tree_free 4 | tree_wordfreq 5 | 4000.txt 6 | 4300.txt 7 | 4302.txt 8 | 4309.txt 9 | 4500.txt 10 | 4000.zip 11 | 4300.zip 12 | 4302.zip 13 | 4309.zip 14 | 4500.zip 15 | -------------------------------------------------------------------------------- /binarytree/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile for binarytree example 33 | # 34 | TARGETS = tree_insert tree_walk tree_free tree_wordfreq 35 | OBJS = tree.o util.o icount.o 36 | LIBFILES = ../libpmemalloc/libpmemalloc.a ../libpmem/libpmem.a 37 | CLOBBERFILES = 4000.txt 4300.txt 4302.txt 4309.txt 4500.txt\ 38 | 4000.zip 4300.zip 4302.zip 4309.zip 4500.zip 39 | 40 | include ../Makefile.inc 41 | 42 | tree_insert: tree_insert.o 43 | tree_walk: tree_walk.o 44 | tree_free : tree_free.o 45 | tree_wordfreq : tree_wordfreq.o 46 | 47 | tree.c: tree.h 48 | 49 | # 50 | # The allcounts entry point runs pmem_basic_icount via the allcounts 51 | # script, which will simulate a crash between every two adjacent 52 | # instructions in the test code snippet in pmem_basic_icount.c. 53 | # The allcount script will then summarize the results of all the runs. 54 | # 55 | # This takes a while to run. 56 | # 57 | CMD = rm -f testfile%C; ./tree_insert -F -i %C testfile%C one two three four; ../libpmemalloc/pmemalloc_check testfile%C; ./tree_walk testfile%C; ../libpmemalloc/pmemalloc_check testfile%C; rm -f testfile%C 58 | 59 | allcounts: tree_insert ../libpmemalloc/pmemalloc_check tree_walk 60 | @../icount/allcounts -j 200 '$(CMD)' 61 | @rm -f testfile* 62 | 63 | ../libpmemalloc/pmemalloc_check: 64 | $(MAKE) -C ../libpmemalloc 65 | 66 | test: tree_walk tree_wordfreq freqtest 67 | @./freqtest -n 68 | @./freqtest 2>&1 | tee freqtest.out 69 | @cmp -s freqtest.out freqtest.pass || (echo FAIL: freqtest.out does not match freqtest.pass; false) 70 | @echo PASS 71 | 72 | .PHONY: allcounts test 73 | -------------------------------------------------------------------------------- /binarytree/README: -------------------------------------------------------------------------------- 1 | This is binarytree/README. 2 | 3 | This is a simple binary tree for Persistent Memory, implemented 4 | on top of the libpmemalloc example. All the example code is in: 5 | 6 | tree.c 7 | 8 | The interfaces provided by this example are very simple -- you can 9 | see the list of the in: 10 | 11 | tree.h 12 | 13 | The other source files here are nothing but CLIs that gather arguments 14 | and call functions in tree.c for testing. Some examples of tests you 15 | can run to play with the tree implementation: 16 | 17 | tree_insert testfile string_one string_two string_one string_three 18 | tree_walk testfile 19 | tree_free testfile 20 | 21 | Like most examples, use -M to turn on the msync mode in libpmem, -F to turn 22 | on the fault injection test mode in libpmem, and -d to enable debug output. 23 | 24 | The command: 25 | 26 | make test 27 | 28 | will pull a bunch of text files from gutenberg.com and run them through 29 | the word frequency counting program "tree_wordfreq". The Makefile does 30 | this using the freqtest script and then checks the output against expected 31 | output in "freqtest.pass". The make succeeds if the test passes. 32 | 33 | The command: 34 | 35 | make allcounts 36 | 37 | will perform a fault injection test run (takes a while to run). 38 | -------------------------------------------------------------------------------- /binarytree/freqtest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2013, Intel Corporation 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # 17 | # * Neither the name of Intel Corporation nor the names of its 18 | # contributors may be used to endorse or promote products derived 19 | # from this software without specific prior written permission. 20 | # 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | # 34 | # freqtest -- unit test for binarytree example code 35 | # 36 | # -n Don't run tests, just make sure we have all 37 | # the files we need. 38 | # 39 | # freqtest.pass contains the output this script generates if the test passes. 40 | # 41 | 42 | nflag= 43 | while getopts 'n' opt 44 | do 45 | case $opt in 46 | n) 47 | nflag=1 48 | ;; 49 | ?) 50 | echo "Usage: $0 [-n]" >&2 51 | exit 1 52 | ;; 53 | esac 54 | done 55 | 56 | set -e 57 | files="4000.txt 4300.txt 4302.txt 4309.txt 4500.txt" 58 | 59 | for i in $files 60 | do 61 | base=${i%.txt} 62 | [ -f $i ] && continue 63 | echo wget http://www.gutenberg.org/files/$base/$base.zip 64 | wget http://www.gutenberg.org/files/$base/$base.zip 65 | unzip $base.zip 66 | done 67 | 68 | if [[ -z "$nflag" ]] 69 | then 70 | 71 | echo Running test... 72 | echo rm -f testfile 73 | rm -f testfile 74 | echo ./tree_wordfreq testfile $files 75 | ./tree_wordfreq testfile $files 76 | echo Checking results... 77 | 78 | ../libpmemalloc/pmemalloc_check testfile 79 | echo Lines in tree: `./tree_walk testfile | wc -l` 80 | fi 81 | 82 | echo Done. 83 | 84 | exit 0 85 | -------------------------------------------------------------------------------- /binarytree/freqtest.pass: -------------------------------------------------------------------------------- 1 | Running test... 2 | rm -f testfile 3 | ./tree_wordfreq testfile 4000.txt 4300.txt 4302.txt 4309.txt 4500.txt 4 | Checking results... 5 | Summary of pmem pool: 6 | File size: 10485760, 10469312 allocatable bytes in pool 7 | 8 | State Bytes Clumps Largest Smallest 9 | Free 543744 1 543744 543744 10 | Reserved 0 0 0 0 11 | Activating 0 0 0 0 12 | Active 9925568 77543 192 128 13 | Freeing 0 0 0 0 14 | TOTAL 10469312 77544 543744 128 15 | Lines in tree: 77543 16 | Done. 17 | -------------------------------------------------------------------------------- /binarytree/tree.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * tree.c -- implement a binary tree on Persistent Memory 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "util/util.h" 45 | #include "libpmem/pmem.h" 46 | #include "libpmemalloc/pmemalloc.h" 47 | #include "tree.h" 48 | 49 | /* 50 | * the Persistent Memory pool, as returned by pmemalloc_init() 51 | */ 52 | static void *Pmp; 53 | 54 | /* 55 | * the nodes of this tree contain a count and a string 56 | */ 57 | struct tnode { 58 | struct tnode *left_; 59 | struct tnode *right_; 60 | unsigned count; 61 | char s[]; 62 | }; 63 | 64 | /* 65 | * we use the static area to persistently store to root of the tree 66 | */ 67 | struct static_info { 68 | struct tnode *root_; 69 | }; 70 | 71 | /* 72 | * tree_init -- initialize the binary tree 73 | * 74 | * Inputs: 75 | * path -- Persistent Memory file where we will store the tree 76 | * 77 | * size -- size of the PM file if it doesn't exist already 78 | */ 79 | void 80 | tree_init(const char *path, size_t size) 81 | { 82 | DEBUG("path \"%s\" size %lu", path, size); 83 | 84 | if ((Pmp = pmemalloc_init(path, size)) == NULL) 85 | FATALSYS("pmemalloc_init on %s", path); 86 | } 87 | 88 | /* 89 | * tree_insert_subtree -- insert a string or bump count if found 90 | * 91 | * This is the internal, recursive function that does all the work. 92 | */ 93 | static void 94 | tree_insert_subtree(struct tnode **rootp_, const char *s) 95 | { 96 | int diff; 97 | 98 | DEBUG("*rootp_ = %lx", (uintptr_t)*rootp_); 99 | 100 | if (*rootp_ == NULL) { 101 | /* insert a new node here */ 102 | struct tnode *tnp_; 103 | size_t slen = strlen(s) + 1; /* include '\0' */ 104 | 105 | if ((tnp_ = pmemalloc_reserve(Pmp, sizeof(*tnp_) + 106 | slen)) == NULL) 107 | FATALSYS("pmem_alloc"); 108 | 109 | PMEM(Pmp, tnp_)->left_ = 110 | PMEM(Pmp, tnp_)->right_ = NULL; 111 | PMEM(Pmp, tnp_)->count = 1; 112 | strcpy(PMEM(Pmp, tnp_)->s, s); 113 | 114 | pmemalloc_onactive(Pmp, tnp_, (void **)rootp_, tnp_); 115 | pmemalloc_activate(Pmp, tnp_); 116 | 117 | DEBUG("new node inserted, count=1"); 118 | } else if ((diff = strcmp(s, PMEM(Pmp, *rootp_)->s)) == 0) { 119 | /* already in tree, increase count */ 120 | PMEM(Pmp, *rootp_)->count++; 121 | pmem_persist(&PMEM(Pmp, *rootp_)->count, sizeof(unsigned), 0); 122 | 123 | DEBUG("new count=%u", PMEM(Pmp, *rootp_)->count); 124 | } else if (diff < 0) { 125 | /* recurse left */ 126 | tree_insert_subtree(&PMEM(Pmp, *rootp_)->left_, s); 127 | } else { 128 | /* recurse right */ 129 | tree_insert_subtree(&PMEM(Pmp, *rootp_)->right_, s); 130 | } 131 | } 132 | 133 | /* 134 | * tree_insert -- insert a string or bump count if found 135 | */ 136 | void 137 | tree_insert(const char *s) 138 | { 139 | struct static_info *sp = pmemalloc_static_area(Pmp); 140 | 141 | tree_insert_subtree(&sp->root_, s); 142 | } 143 | 144 | /* 145 | * tree_walk_subtree -- walk the tree, printing the contents 146 | * 147 | * This is the internal, recursive function that does all the work. 148 | */ 149 | static void 150 | tree_walk_subtree(struct tnode *root_) 151 | { 152 | DEBUG("root_ = %lx", (uintptr_t)root_); 153 | 154 | if (root_) { 155 | /* recurse left */ 156 | tree_walk_subtree(PMEM(Pmp, root_)->left_); 157 | 158 | /* print this node */ 159 | printf("%5d %s\n", 160 | PMEM(Pmp, root_)->count, 161 | PMEM(Pmp, root_)->s); 162 | 163 | /* recurse right */ 164 | tree_walk_subtree(PMEM(Pmp, root_)->right_); 165 | } 166 | } 167 | 168 | /* 169 | * tree_walk -- walk the tree, printing the contents 170 | */ 171 | void 172 | tree_walk(void) 173 | { 174 | struct static_info *sp = pmemalloc_static_area(Pmp); 175 | 176 | tree_walk_subtree(sp->root_); 177 | } 178 | 179 | /* 180 | * tree_free_subtree -- free the tree 181 | * 182 | * This is the internal, recursive function that does all the work. 183 | */ 184 | static void 185 | tree_free_subtree(struct tnode **rootp_) 186 | { 187 | DEBUG("*rootp_ = %lx", (uintptr_t)*rootp_); 188 | 189 | if (*rootp_ != NULL) { 190 | /* recurse left */ 191 | tree_free_subtree(&PMEM(Pmp, *rootp_)->left_); 192 | 193 | /* recurse right */ 194 | tree_free_subtree(&PMEM(Pmp, *rootp_)->right_); 195 | 196 | /* free this node */ 197 | pmemalloc_onfree(Pmp, (void *)*rootp_, (void **)rootp_, NULL); 198 | pmemalloc_free(Pmp, (void *)*rootp_); 199 | } 200 | } 201 | 202 | /* 203 | * tree_free -- free the tree 204 | */ 205 | void 206 | tree_free(void) 207 | { 208 | struct static_info *sp = pmemalloc_static_area(Pmp); 209 | 210 | tree_free_subtree(&sp->root_); 211 | } 212 | -------------------------------------------------------------------------------- /binarytree/tree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * tree.h -- definitions for the binary tree example 35 | */ 36 | 37 | void tree_init(const char *path, size_t size); 38 | void tree_insert(const char *s); 39 | void tree_walk(void); 40 | void tree_free(void); 41 | -------------------------------------------------------------------------------- /binarytree/tree_free.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * tree_free.c -- free the tree in Persistent Memory 35 | * 36 | * Usage: tree_free [-FMd] [-i icount] path 37 | * 38 | * This is just a simple CLI for calling tree_free(). 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "util/util.h" 49 | #include "icount/icount.h" 50 | #include "libpmem/pmem.h" 51 | #include "tree.h" 52 | 53 | char Usage[] = "[-FMd] [-i icount] path"; /* for USAGE() */ 54 | 55 | int 56 | main(int argc, char *argv[]) 57 | { 58 | int opt; 59 | int iflag = 0; 60 | unsigned long icount; 61 | const char *path; 62 | 63 | Myname = argv[0]; 64 | while ((opt = getopt(argc, argv, "FMdi:")) != -1) { 65 | switch (opt) { 66 | case 'F': 67 | pmem_fit_mode(); 68 | break; 69 | 70 | case 'M': 71 | pmem_msync_mode(); 72 | break; 73 | 74 | case 'd': 75 | Debug++; 76 | break; 77 | 78 | case 'i': 79 | iflag++; 80 | icount = strtoul(optarg, NULL, 10); 81 | break; 82 | 83 | default: 84 | USAGE(NULL); 85 | } 86 | } 87 | 88 | if (optind >= argc) 89 | USAGE("No path given"); 90 | path = argv[optind++]; 91 | 92 | if (optind < argc) 93 | USAGE(NULL); 94 | 95 | tree_init(path, 0); 96 | 97 | if (iflag) 98 | icount_start(icount); 99 | 100 | tree_free(); 101 | 102 | if (iflag) { 103 | icount_stop(); 104 | printf("Total instruction count: %lu\n", icount_total()); 105 | } 106 | 107 | exit(0); 108 | } 109 | -------------------------------------------------------------------------------- /binarytree/tree_insert.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * tree_insert.c -- add to the tree in Persistent Memory 35 | * 36 | * Usage: tree_insert [-FMd] [-i icount] path strings... 37 | * 38 | * This is just a simple CLI for calling tree_insert(). 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "util/util.h" 49 | #include "icount/icount.h" 50 | #include "libpmem/pmem.h" 51 | #include "tree.h" 52 | 53 | #define DEFAULT_POOL_SIZE (10 * 1024 * 1024) 54 | 55 | char Usage[] = "[-FMd] [-i icount] path strings..."; /* for USAGE() */ 56 | 57 | int 58 | main(int argc, char *argv[]) 59 | { 60 | int opt; 61 | int iflag = 0; 62 | unsigned long icount; 63 | const char *path; 64 | int i; 65 | 66 | Myname = argv[0]; 67 | while ((opt = getopt(argc, argv, "FMdi:")) != -1) { 68 | switch (opt) { 69 | case 'F': 70 | pmem_fit_mode(); 71 | break; 72 | 73 | case 'M': 74 | pmem_msync_mode(); 75 | break; 76 | 77 | case 'd': 78 | Debug++; 79 | break; 80 | 81 | case 'i': 82 | iflag++; 83 | icount = strtoul(optarg, NULL, 10); 84 | break; 85 | 86 | default: 87 | USAGE(NULL); 88 | } 89 | } 90 | 91 | if (optind >= argc) 92 | USAGE("No path given"); 93 | path = argv[optind++]; 94 | 95 | if (optind >= argc) 96 | USAGE("No strings given"); 97 | 98 | tree_init(path, DEFAULT_POOL_SIZE); 99 | 100 | if (iflag) 101 | icount_start(icount); 102 | 103 | for (i = optind; i < argc; i++) 104 | tree_insert(argv[i]); 105 | 106 | if (iflag) { 107 | icount_stop(); 108 | printf("Total instruction count: %lu\n", icount_total()); 109 | } 110 | 111 | exit(0); 112 | } 113 | -------------------------------------------------------------------------------- /binarytree/tree_walk.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * tree_walk.c -- print the tree in Persistent Memory 35 | * 36 | * Usage: tree_walk [-FMd] path 37 | * 38 | * This is just a simple CLI for calling tree_walk(). 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "util/util.h" 49 | #include "libpmem/pmem.h" 50 | #include "tree.h" 51 | 52 | char Usage[] = "[-FMd] path"; /* for USAGE() */ 53 | 54 | int 55 | main(int argc, char *argv[]) 56 | { 57 | const char *path; 58 | int opt; 59 | 60 | Myname = argv[0]; 61 | while ((opt = getopt(argc, argv, "FMd")) != -1) { 62 | switch (opt) { 63 | case 'F': 64 | pmem_fit_mode(); 65 | break; 66 | 67 | case 'M': 68 | pmem_msync_mode(); 69 | break; 70 | 71 | case 'd': 72 | Debug++; 73 | break; 74 | 75 | default: 76 | USAGE(NULL); 77 | } 78 | } 79 | 80 | if (optind >= argc) 81 | USAGE("No path given"); 82 | path = argv[optind++]; 83 | 84 | if (optind < argc) 85 | USAGE(NULL); 86 | 87 | tree_init(path, 0); 88 | 89 | tree_walk(); 90 | 91 | exit(0); 92 | } 93 | -------------------------------------------------------------------------------- /binarytree/tree_wordfreq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * tree_wordfreq.c -- construct a frequency count from a text file 35 | * 36 | * Usage: tree_wordfreq [-FMd] path files... 37 | */ 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "util/util.h" 48 | #include "icount/icount.h" 49 | #include "libpmem/pmem.h" 50 | #include "tree.h" 51 | 52 | #define DEFAULT_POOL_SIZE (10 * 1024 * 1024) 53 | #define MAXWORD 8192 54 | 55 | char Usage[] = "[-FMd] path files..."; /* for USAGE() */ 56 | 57 | /* 58 | * tree_insert_words -- insert all words from a file into the tree 59 | */ 60 | void 61 | tree_insert_words(const char *fname) 62 | { 63 | FILE *fp; 64 | int c; 65 | char word[MAXWORD]; 66 | char *ptr; 67 | 68 | DEBUG("fname=\"%s\"", fname); 69 | 70 | if ((fp = fopen(fname, "r")) == NULL) 71 | FATALSYS(fname); 72 | 73 | ptr = NULL; 74 | while ((c = getc(fp)) != EOF) 75 | if (isalpha(c)) { 76 | if (ptr == NULL) { 77 | /* starting a new word */ 78 | ptr = word; 79 | *ptr++ = c; 80 | } else if (ptr < &word[MAXWORD - 1]) 81 | /* add character to current word */ 82 | *ptr++ = c; 83 | else { 84 | /* word too long, truncate it */ 85 | *ptr++ = '\0'; 86 | tree_insert(word); 87 | ptr = NULL; 88 | } 89 | } else if (ptr != NULL) { 90 | /* word ended, store it */ 91 | *ptr++ = '\0'; 92 | tree_insert(word); 93 | ptr = NULL; 94 | } 95 | 96 | /* handle the last word */ 97 | if (ptr != NULL) { 98 | /* word ended, store it */ 99 | *ptr++ = '\0'; 100 | tree_insert(word); 101 | } 102 | 103 | fclose(fp); 104 | } 105 | 106 | int 107 | main(int argc, char *argv[]) 108 | { 109 | int opt; 110 | const char *path; 111 | int i; 112 | 113 | Myname = argv[0]; 114 | while ((opt = getopt(argc, argv, "FMd")) != -1) { 115 | switch (opt) { 116 | case 'F': 117 | pmem_fit_mode(); 118 | break; 119 | 120 | case 'M': 121 | pmem_msync_mode(); 122 | break; 123 | 124 | case 'd': 125 | Debug++; 126 | break; 127 | 128 | default: 129 | USAGE(NULL); 130 | } 131 | } 132 | 133 | if (optind >= argc) 134 | USAGE("No path given"); 135 | path = argv[optind++]; 136 | 137 | if (optind >= argc) 138 | USAGE("No files given"); 139 | 140 | tree_init(path, DEFAULT_POOL_SIZE); 141 | 142 | for (i = optind; i < argc; i++) 143 | tree_insert_words(argv[i]); 144 | 145 | exit(0); 146 | } 147 | -------------------------------------------------------------------------------- /icount/.gitignore: -------------------------------------------------------------------------------- 1 | icount_test 2 | -------------------------------------------------------------------------------- /icount/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile for icount module 33 | # 34 | TARGETS = icount_test 35 | OBJS = icount_test.o icount.o util.o 36 | 37 | include ../Makefile.inc 38 | 39 | # 40 | # The allcounts entry point runs icount_test via the allcounts 41 | # script, which will simulate a crash between every two adjacent 42 | # instructions in the test code snippet in icount_test.c. 43 | # The allcount script will then summarize the results of all the runs. 44 | # 45 | CMD = ./icount_test %C 46 | 47 | allcounts: icount_test 48 | @./allcounts -j 100 '$(CMD)' 49 | 50 | test: icount_test 51 | @./icount_test 4 2>&1 | tee icount_test.out 52 | @cmp -s icount_test.out icount_test.pass || (echo FAIL: icount_test.out does not match icount_test.pass; false) 53 | @echo PASS 54 | 55 | .PHONY: allcounts test 56 | -------------------------------------------------------------------------------- /icount/README: -------------------------------------------------------------------------------- 1 | This is icount/README. 2 | 3 | These are not the examples you're looking for. 4 | 5 | This directory contains the icount code, which is a small set of 6 | routines allowing a program to count instructions executed between 7 | two points. We use these routines to perform fault injection testing 8 | (FIT) on many of the examples to see how well they recover after a 9 | simulated system crash. See ../README for the directories that contain 10 | the examples. 11 | 12 | You're still here? You should be off reading the examples, but if 13 | you're really interested in the icount module, you can read all about it: 14 | 15 | icount.c contains a few routines that can be compiled into a program 16 | allowing it to count instructions between two points in the program 17 | execution. In addition, the program can be terminated after a given 18 | number of instructions have passed. This can be used for some fault 19 | injection testing where crashes are simulated by terminating the program 20 | at various points. 21 | 22 | This implementation is very quick & dirty -- no attempt has been made 23 | to do any performance work. While counting instructions, the program 24 | is single-stepped. Expect it to be slow. Also, using single-stepping 25 | counts up who-knows-what when signals are involved -- probably best not 26 | to try counting any code using signals. Or multi-threaded programs for 27 | that matter. Syscalls are not counted (just the code leading up to them 28 | and the code following them). Calling fork or exec while counting 29 | instructions almost certainly won't do what you want. In fact, best 30 | to not use these routines at all without talking to Andy first. 31 | 32 | Also, this hasn't been tested on anything but Linux x86_64. 33 | 34 | To use these routines, include "icount.h" in your program. 35 | 36 | To start counting instructions, call: 37 | 38 | icount_start(0); 39 | 40 | to stop counting, call: 41 | 42 | icount_stop(); 43 | 44 | calling icount_start() resets the count to zero before starting to 45 | count. If you pass something other than zero to icount_start(), it 46 | will execute that number of instructions and then terminate the program. 47 | 48 | The current count (between the last pair of icount_start/icount_stop calls) 49 | is accessed by calling: 50 | 51 | icount_total(); 52 | 53 | There's a trivial example which is used to unit test the icount code 54 | in icount_test.c. To run the unit test, do: 55 | 56 | make 57 | ./icount_test 58 | 59 | to simulate a crash three instructions into the code snippet under test: 60 | 61 | ./icount_test 3 62 | 63 | This directory also contains a Perl script call "allcounts". This script 64 | runs your test program over and over again, simulating a crash at a different 65 | position in your snippet code under test. The script then collates the 66 | output of all the runs into a summary so you can see how the program reacted 67 | to each crash. The "allcounts" entry point in the Makefile shows you 68 | an example of how to use this script. 69 | 70 | Just a note on persistence: even if you crash a program between a store 71 | instruction and the calls that make sure the change is persistent, the 72 | store might still look like it was made persistent because it ends up 73 | flushed from a cache or accessed from that cache by some other program. 74 | So to really make this fault injection test worthwhile, you should use it 75 | with the "fit" mode in the libpmem library. The fit mode is designed to 76 | more closely simulate how stores to Persistent Memory, still sitting in the 77 | processor cache at crash time, get dropped. 78 | 79 | 80 | TODO 81 | 82 | Here are some potential future enhancements: 83 | 84 | - Performance work. Using machine code analysis and breakpoints 85 | this could be made much faster. 86 | 87 | - Simulated cache eviction. We're good at dropping non-flushed 88 | stores, but we should also simulate stores that reach persistence 89 | early due to cache pressure or other system activity. 90 | 91 | - Ability to run against programs without recompiling them. Not 92 | that hard since we already "attach" to the program from another 93 | process. The trick is finding the most convenient way to 94 | specify the start/stop points. 95 | -------------------------------------------------------------------------------- /icount/allcounts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Copyright (c) 2013, Intel Corporation 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # 17 | # * Neither the name of Intel Corporation nor the names of its 18 | # contributors may be used to endorse or promote products derived 19 | # from this software without specific prior written permission. 20 | # 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | # 34 | # allcounts -- script to run through all possible crash scenarios 35 | # 36 | # Usage: allcounts [-j nproc] [-n] [-v] cmd 37 | # 38 | # -j nprocs Run up to nprocs processes concurrently. This 39 | # greatly improves the run-time of this script, 40 | # especially on machines with lots of CPUs. Try 41 | # setting nprocs to be twice the number of CPUs 42 | # in the system for starters. 43 | # -n Dry run -- only does full run and prints what it 44 | # would do next instead of actually doing it. 45 | # -v Verbose -- lots of extra info printed. 46 | # 47 | # Given a program that contains a (hopefully small) snippet of test 48 | # code surrounded by icount_start() and icount_stop() calls, this 49 | # script runs the program once to find the total instruction count 50 | # (expected to be printed as "Total instruction count: N") and then 51 | # it re-runs the same test over and over, passing it the number of 52 | # instructions to run before simulating a crash as a command line 53 | # argument. See icount_test.c for a full example of a program written 54 | # to be tested by this script. 55 | # 56 | # This script captures all the output from all the runs and collates 57 | # the result, dumping a list of run numbers followed by the output 58 | # produced by those runs. Since stopping a program between each possible 59 | # instruction often produces the same output again and again, the collated 60 | # output is much shorter and much easier to read that looking at the 61 | # full raw output from every single run. 62 | # 63 | 64 | use strict; 65 | use warnings; 66 | use Getopt::Std; 67 | 68 | my $Me = $0; 69 | $Me =~ s,.*/,,; 70 | 71 | # options we accept 72 | our ($opt_j, $opt_n, $opt_v); 73 | 74 | $ENV{PATH} = "/bin:/usr/bin"; 75 | umask 077; 76 | 77 | my $tmpdir = "/tmp/allcounts$$"; 78 | 79 | $SIG{HUP} = $SIG{INT} = $SIG{TERM} = $SIG{__DIE__} = sub { 80 | die @_ if $^S; 81 | 82 | my $errstr = shift; 83 | 84 | cleanup(); 85 | 86 | die "========== ERROR: $errstr"; 87 | }; 88 | 89 | # 90 | # out -- like "print" but with equals before it so allcounts output sticks out 91 | # 92 | sub out (@) { 93 | print "========== ", @_, "\n"; 94 | } 95 | 96 | # 97 | # verbose -- like "print" but only in verbose mode 98 | # 99 | sub verbose (@) { 100 | return unless $opt_v; 101 | 102 | out @_; 103 | } 104 | 105 | # 106 | # usage -- print usage message and exit 107 | # 108 | sub usage { 109 | my $msg = shift; 110 | 111 | warn "$Me: $msg\n" if $msg; 112 | warn "Usage: $Me [-j nproc] [-n] [-v] pre-cmd cmd post-cmd\n"; 113 | exit 1; 114 | } 115 | 116 | # 117 | # argument processing... 118 | # 119 | getopts('j:nv') or usage; 120 | 121 | usage unless @ARGV; 122 | 123 | my $cmd = join(' ', @ARGV); 124 | 125 | # 126 | # main program starts here... 127 | # 128 | verbose("Dry run.") if $opt_n; 129 | verbose("Running up to $opt_j jobs concurrently.") if $opt_j; 130 | $opt_j = 1 unless $opt_j; 131 | out "Command: \"$cmd\""; 132 | 133 | my $fullcmd = subC($cmd, 0); 134 | my $total = `($cmd) 2>\&1`; 135 | 136 | out "Full output:"; 137 | print $total; 138 | 139 | $total =~ s/.*Total instruction count: (\d+).*/$1/s or 140 | die "Instruction count not found\n"; 141 | 142 | mkdir $tmpdir or die "mkdir: $tmpdir: $!\n"; 143 | 144 | runjobs($cmd, $total, $tmpdir); 145 | collate($tmpdir); 146 | cleanup(); 147 | 148 | exit 0; 149 | 150 | # 151 | # runjobs -- perform all the runs, in parallel if possible 152 | # 153 | sub runjobs { 154 | my ($cmd, $total, $tmpdir) = @_; 155 | my $outstanding = 0; 156 | my $completed = 0; 157 | 158 | # don't need to try zero, and don't need to try all 159 | # just each number in-between 160 | for (my $i = 1; $i < $total; $i++) { 161 | if ($outstanding >= $opt_j) { 162 | verbose "Waiting for a job to finish"; 163 | wait or die "wait: $!\n"; 164 | $outstanding--; 165 | $completed++; 166 | if ($completed % 100 == 0) { 167 | out "Iterations completed: $completed"; 168 | } 169 | } 170 | verbose "Running iteration $i"; 171 | if ($opt_n) { 172 | my $fullcmd = subC($cmd, $i); 173 | out $fullcmd; 174 | next; 175 | } 176 | defined (my $pid = fork) or die "fork: $!\n"; 177 | if ($pid == 0) { 178 | # 179 | # child 180 | # 181 | my $fullcmd = subC($cmd, $i); 182 | open STDOUT, ">$tmpdir/$i" or die "$tmpdir/$i: $!\n"; 183 | open STDERR, '>&STDOUT'; 184 | system($fullcmd); 185 | exit 0; 186 | } 187 | $outstanding++; 188 | } 189 | verbose "No more iterations to run"; 190 | while ($outstanding > 0) { 191 | wait or die "wait: $!\n"; 192 | $outstanding--; 193 | $completed++; 194 | if ($completed % 100 == 0) { 195 | out "Iterations completed: $completed"; 196 | } 197 | } 198 | out "All iterations completed."; 199 | } 200 | 201 | # 202 | # collate -- summarize outputs from all runs 203 | # 204 | sub collate { 205 | my ($dir) = @_; 206 | my %output; 207 | 208 | opendir(my $dh, $dir) || die "$dir: $!\n"; 209 | my @files = grep { /^\d+$/ } readdir($dh); 210 | closedir($dh); 211 | 212 | foreach my $file (sort {$a <=> $b} @files) { 213 | open(my $fh, "$dir/$file") or die "$dir/$file: $!\n"; 214 | local $/; 215 | my $contents = <$fh>; 216 | $contents =~ s/Program terminated after \d+ instructions\n//; 217 | push(@{$output{$contents}}, $file); 218 | close($fh); 219 | unlink "$dir/$file" or die "unlink: $dir/$file: $!\n"; 220 | } 221 | 222 | # 223 | # show results in line number order 224 | # 225 | foreach (sort {$output{$a}[0] <=> $output{$b}[0]} keys %output) { 226 | 227 | # compress "number,number,number,..." to "low-high" 228 | my $iters = shift @{$output{$_}}; 229 | my $rhs = $iters; 230 | my $foundrange = 0; 231 | while (@{$output{$_}}) { 232 | my $val = shift @{$output{$_}}; 233 | if ($val == $rhs + 1) { 234 | $rhs++; 235 | $foundrange = 1; 236 | } else { 237 | $iters .= "-$rhs" if $foundrange; 238 | $iters .= ",$val"; 239 | $rhs = $val; 240 | $foundrange = 0; 241 | } 242 | } 243 | $iters .= "-$rhs" if $foundrange; 244 | 245 | out "Output for iterations: $iters"; 246 | print $_, "\n"; 247 | } 248 | } 249 | 250 | # 251 | # subC -- replace the string %C with a given value 252 | # 253 | sub subC { 254 | my ($cmd, $c) = @_; 255 | my $retval = $cmd; 256 | 257 | $retval =~ s/%C/$c/g; 258 | return $retval; 259 | } 260 | 261 | # 262 | # cleanup -- delete temporary files 263 | # 264 | sub cleanup { 265 | if (-d $tmpdir && opendir(my $dh, $tmpdir)) { 266 | foreach (readdir($dh)) { 267 | unlink "$tmpdir/$_" if /^\d+$/; 268 | } 269 | closedir($dh); 270 | rmdir $tmpdir; 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /icount/icount.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * icount.c -- quick & dirty instruction count 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #include "util/util.h" 55 | #include "icount/icount.h" 56 | 57 | static pid_t Tracer_pid; /* PID of tracer process */ 58 | static int Tracerpipe[2]; /* pipe from tracer to parent */ 59 | static unsigned long Total; /* instruction count */ 60 | static unsigned long Nothing; 61 | static jmp_buf Trigjmp; 62 | 63 | /* 64 | * handler -- catch SIGRTMIN+15 in tracee once tracer is established 65 | */ 66 | static void 67 | handler() 68 | { 69 | longjmp(Trigjmp, 1); 70 | } 71 | 72 | /* 73 | * pretrigger -- internal function used to detect start of tracing 74 | * 75 | * This function must immediately precede trigger() in this file. 76 | */ 77 | static void 78 | pretrigger(void) 79 | { 80 | int x = getpid(); 81 | 82 | /* 83 | * this is just a few instructions to make sure 84 | * this function doesn't get optimized away into 85 | * nothing. the tracer will find us here and send 86 | * us a signal, causing us to longjmp out. 87 | */ 88 | while (1) { 89 | x++; /* wait for tracer to attach */ 90 | Nothing += x; 91 | } 92 | } 93 | 94 | /* 95 | * trigger -- internal function used to detect start of tracing 96 | */ 97 | static void 98 | trigger(void) 99 | { 100 | Nothing = 0; /* avoid totally empty function */ 101 | } 102 | 103 | /* 104 | * tracer -- internal function used in child process to trace parent 105 | */ 106 | static void 107 | tracer(unsigned long ttl) 108 | { 109 | pid_t ppid = getppid(); 110 | int status; 111 | int triggered = 0; 112 | int signaled = 0; 113 | 114 | if (ptrace(PTRACE_ATTACH, ppid, 0, 0) < 0) 115 | FATALSYS("PTRACE_ATTACH"); 116 | 117 | while (1) { 118 | if (waitpid(ppid, &status, 0) < 0) 119 | FATALSYS("waitpid(pid=%d)", ppid); 120 | 121 | if (WIFSTOPPED(status)) { 122 | struct user_regs_struct regs; 123 | 124 | if (triggered) 125 | Total++; 126 | 127 | if (ttl && Total >= ttl) { 128 | if (kill(ppid, SIGKILL) < 0) 129 | FATAL("SIGKILL %d", ppid); 130 | printf("Program terminated after %lu " 131 | "instructions\n", 132 | Total); 133 | fflush(stdout); 134 | _exit(0); 135 | } 136 | 137 | if (ptrace(PTRACE_GETREGS, ppid, 0, ®s) < 0) 138 | FATALSYS("PTRACE_GETREGS"); 139 | 140 | if ((unsigned long)regs.rip >= 141 | (unsigned long)pretrigger && 142 | (unsigned long)regs.rip < 143 | (unsigned long)trigger) { 144 | if (!signaled) { 145 | if (ptrace(PTRACE_SYSCALL, ppid, 0, 146 | SIGRTMIN+15) < 0) 147 | FATALSYS("PTRACE_SYSCALL"); 148 | signaled = 1; 149 | continue; 150 | } 151 | } else if ((unsigned long) regs.rip == 152 | (unsigned long) trigger) { 153 | triggered = 1; 154 | } else if ((unsigned long) regs.rip == 155 | (unsigned long) icount_stop) { 156 | if (ptrace(PTRACE_DETACH, ppid, 0, 0) < 0) 157 | FATALSYS("PTRACE_DETACH"); 158 | break; 159 | } 160 | 161 | if (ptrace(PTRACE_SINGLESTEP, ppid, 0, 0) < 0) 162 | FATALSYS("PTRACE_SINGLESTEP"); 163 | } else if (WIFEXITED(status)) 164 | FATAL("tracee: exit %d", WEXITSTATUS(status)); 165 | else if (WIFSIGNALED(status)) 166 | FATAL("tracee: %s", strsignal(WTERMSIG(status))); 167 | else 168 | FATAL("unexpected wait status: 0x%x", status); 169 | } 170 | 171 | /* 172 | * our counting is done, send the count back to the tracee 173 | * via the pipe and exit. 174 | */ 175 | if (write(Tracerpipe[1], &Total, sizeof(Total)) < 0) 176 | FATALSYS("write to pipe"); 177 | close(Tracerpipe[1]); 178 | _exit(0); 179 | } 180 | 181 | /* 182 | * icount_start -- begin instruction counting 183 | * 184 | * Inputs: 185 | * life_remaining -- simulate a crash after counting this many 186 | * instructions. pass in 0ull to disable this 187 | * feature. 188 | * 189 | * There is some variability on how far the parent can get before the child 190 | * attaches to it for tracing, especially when the system is loaded down 191 | * (e.g. due to zillions of parallel icount traces happening at once). 192 | * To coordinate this, we use a multi-step procedure where the tracee 193 | * runs until it gets to the function pretrigger() and the tracer() detects 194 | * that and raises a signal (SIGRTMIN+15) in the tracee, who then catches 195 | * it and longjmps out of signal handler, back here, and then calls trigger(). 196 | * 197 | * The multi-step coordination sounds complex, but it handles the 198 | * surprisingly common cases where the tracer attached to the tracee 199 | * before it even finished executing the libc fork() wrapper, and the 200 | * other end of the spectrum where the tracee ran way too far ahead 201 | * before the tracer attached and the tracer missed the call to trigger(). 202 | */ 203 | void 204 | icount_start(unsigned long life_remaining) 205 | { 206 | if (Tracer_pid) { 207 | /* nested call not allowed */ 208 | icount_stop(); 209 | FATAL("icount_start called while counting already active"); 210 | } 211 | 212 | Total = 0ull; 213 | 214 | if (pipe(Tracerpipe) < 0) 215 | FATALSYS("pipe"); 216 | 217 | if (signal(SIGRTMIN+15, handler) == SIG_ERR) 218 | FATALSYS("signal: SIGRTMIN+15"); 219 | 220 | if ((Tracer_pid = fork()) < 0) 221 | FATALSYS("fork"); 222 | else if (Tracer_pid) { 223 | /* parent */ 224 | close(Tracerpipe[1]); 225 | if (!setjmp(Trigjmp)) 226 | pretrigger(); 227 | close(-1); /* harmless syscall for tracer */ 228 | trigger(); 229 | return; 230 | } else { 231 | /* child */ 232 | close(Tracerpipe[0]); 233 | tracer(life_remaining); 234 | } 235 | } 236 | 237 | /* 238 | * icount_stop -- stop counting instructions 239 | */ 240 | void 241 | icount_stop(void) 242 | { 243 | int status; 244 | 245 | if (read(Tracerpipe[0], &Total, sizeof(Total)) < 0) 246 | FATALSYS("read from pipe"); 247 | close(Tracerpipe[0]); 248 | 249 | /* wait for child */ 250 | if (waitpid(Tracer_pid, &status, 0) < 0) 251 | FATALSYS("waitpid(pid=%d)", Tracer_pid); 252 | Tracer_pid = 0; 253 | } 254 | 255 | /* 256 | * icount_total -- return total from last count exercise 257 | * 258 | * Outputs: 259 | * The return value is the total count of instructions 260 | * executed between the last calls to icount_start() 261 | * and icount_stop(). 262 | * 263 | * This function only returns valid counts when counting is not 264 | * active and when a count has previously been started and stopped. 265 | */ 266 | unsigned long 267 | icount_total(void) 268 | { 269 | return Total; 270 | } 271 | -------------------------------------------------------------------------------- /icount/icount.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * icount.h -- interfaces for the icount module 35 | */ 36 | 37 | void icount_start(unsigned long life_remaining); 38 | void icount_stop(void); 39 | unsigned long icount_total(void); 40 | -------------------------------------------------------------------------------- /icount/icount_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * icount_test.c -- test for icount module 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include "util/util.h" 54 | #include "icount/icount.h" 55 | 56 | int Debug = 1; 57 | 58 | int 59 | main(int argc, char *argv[]) 60 | { 61 | int i; 62 | int sum; 63 | unsigned long ttl = 0ul; 64 | 65 | if (argc == 2) 66 | ttl = strtoul(argv[1], NULL, 10); 67 | 68 | /* 69 | * the code snippet under test (bracketed by calls 70 | * to icount_start/icount_stop). 71 | */ 72 | icount_start(ttl); 73 | for (i = 0; i < 1; i++) 74 | sum += i; 75 | icount_stop(); 76 | 77 | printf("Total instruction count: %lu\n", icount_total()); 78 | 79 | exit(0); 80 | } 81 | -------------------------------------------------------------------------------- /icount/icount_test.pass: -------------------------------------------------------------------------------- 1 | Program terminated after 4 instructions 2 | -------------------------------------------------------------------------------- /libpmem/.gitignore: -------------------------------------------------------------------------------- 1 | libpmem.a 2 | libpmem.so 3 | -------------------------------------------------------------------------------- /libpmem/LIBPMEM_API.txt: -------------------------------------------------------------------------------- 1 | NAME 2 | libpmem -- Persistent Memory programming helper library 3 | 4 | SYNOPSIS 5 | #include 6 | cc ... -lpmem 7 | 8 | void pmem_msync_mode(void); 9 | void pmem_fit_mode(void); 10 | 11 | void *pmem_map(int fd, size_t len); 12 | void pmem_persist(void *addr, size_t len, int flags); 13 | 14 | void pmem_flush_cache(void *addr, size_t len, int flags); 15 | void pmem_fence(void); 16 | void pmem_drain_pm_stores(void); 17 | 18 | NOTE: If libpmem has not been installed on this system, you'll 19 | want to arrange for "pmem.h" to be included via a non-system 20 | path, and you'll want to arrange to either find libpmem to be 21 | using LD_LIBRARY_PATH or use the static version, libpmem.a. 22 | 23 | DESCRIPTION 24 | 25 | libpmem provides some optional helper functions for using 26 | Persistent Memory ("optional" because you can use Persistent 27 | Memory without using libpmem if you so desire). Some of the things 28 | described here are experimental features provided as part of the 29 | example code tree. If you're just looking for the Linux API for 30 | Persistent Memory programming, read ../LINUX_PMEM_API.txt instead. 31 | 32 | void pmem_msync_mode(void) 33 | 34 | To use libpmem in "msync mode" call pmem_msync_mode() in 35 | your program before any other calls to libpmem. msync mode 36 | tells libpmem to use msync(2) for flushing changes to 37 | Persistent Memory. This is useful when developing on a 38 | non-PM-aware file system (using normal memory-mapped files). 39 | msync mode will work anywhere, PM-aware file system or 40 | non-PM-aware file system, so if you're unsure, this is the 41 | mode to use. The default mode (what you get without calling 42 | pmem_msync_mode() is to assume stores can be made durable 43 | by flushing caches without calling into the kernel. 44 | 45 | Of course, if you're just developing without actual Persistent 46 | Memory hardware (using volatile memory as pretend-PM), it 47 | doesn't matter much which mode you use since a surprise 48 | power failure will lose anything you stored anyway. 49 | 50 | void pmem_fit_mode(void); 51 | 52 | To use libpmem in "fault injection test mode", call 53 | pmem_fit_mode() in your program before any other calls to 54 | libpmem. This mode is meant for use with the experimental 55 | "icount" routines which simulate crashes at various points 56 | in your program. This mode makes libpmem less forgiving 57 | if you're missing calls to pmem_persist(). See icount/README 58 | for details on how to use this mode. 59 | 60 | void *pmem_map(int fd, size_t len); 61 | 62 | This function is just a convenience function that calls 63 | mmap(2) with the appropriate arguments. The only time 64 | you must use this function instead of mmap is when you're 65 | using the experimental "fit mode" described above. Otherwise 66 | it is entirely programmer preference on whether you use 67 | this function or call mmap directly. 68 | 69 | void pmem_persist(void *addr, size_t len, int flags); 70 | 71 | Force any changes in the len bytes at addr to be stored 72 | durably in Persistent Memory. This is equivalent to 73 | calling msync(2) but may be more optimal and will avoid 74 | calling into the kernel if possible. 75 | 76 | No flags have been defined for this call yet. 77 | 78 | void pmem_flush_cache(void *addr, size_t len, int flags); 79 | void pmem_fence(void); 80 | void pmem_drain_pm_stores(void); 81 | 82 | These three functions provide partial versions of the 83 | pmem_persist() function described above. pmem_persist() 84 | can be thought up as this: 85 | 86 | void pmem_persist(void *addr, size_t len, int flags) 87 | { 88 | /* flush the processor caches */ 89 | pmem_flush_cache(addr, len, flags); 90 | 91 | /* Persistent Memory store barrier */ 92 | pmem_fence(); 93 | 94 | /* wait for any PM stores to drain from HW buffers */ 95 | pmem_drain_pm_stores(); 96 | } 97 | 98 | These functions allow advanced programs to create their 99 | own variations on pmem_persist(). For example, a program 100 | that needs to flush several discontiguous ranges can call 101 | pmem_flush_cache() for each range and then follow up by 102 | calling the pmem_fence() and pmem_drain_pm_stores() once. 103 | 104 | SEE ALSO 105 | LINUX_PMEM_API.txt, mmap(2), msync(2) 106 | -------------------------------------------------------------------------------- /libpmem/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile -- Makefile for libpmem 33 | # 34 | 35 | TARGETS = libpmem.a libpmem.so 36 | INCS = -I.. 37 | OBJS = pmem.o pmem_cl.o pmem_fit.o pmem_msync.o util.o 38 | MAPFILE = pmem.map 39 | SOVERSION = 1 40 | CFLAGS = -ggdb 41 | 42 | all: $(TARGETS) 43 | 44 | libpmem.a: $(OBJS) 45 | $(AR) rv $@ $(OBJS) 46 | 47 | libpmem.so: $(OBJS) 48 | $(CC) $(CFLAGS) -shared -Wl,--version-script=$(MAPFILE),-soname,$(SONAME).$(SOVERSION) -o $@ $(OBJS) 49 | 50 | .c.o: 51 | $(CC) -c -o $@ $(CFLAGS) $(INCS) -fPIC $< 52 | 53 | util.o: ../util/util.c ../util/util.h 54 | $(CC) -c -o $@ $(CFLAGS) $(INCS) -fPIC $< 55 | 56 | clean: 57 | $(RM) *.o core a.out 58 | 59 | clobber: clean 60 | $(RM) $(TARGETS) 61 | 62 | test: 63 | # no libpmem unit test 64 | @echo PASS 65 | 66 | .PHONY: all clean clobber test 67 | -------------------------------------------------------------------------------- /libpmem/README: -------------------------------------------------------------------------------- 1 | This is libpmem/README. 2 | 3 | libpmem contains some helper functions for using Persistent Memory. 4 | Using libpmem on Linux is optional, since the POSIX APIs for accessing 5 | memory-mapped files will work just fine. But using libpmem allows you 6 | to optimize things like flushing changes to persistent memory (using 7 | the POSIX msync() works fine, but is page-based, where pmem_persist() 8 | can take byte-ranges and do whatever work is necessary, avoiding calling 9 | into the kernel if possible). 10 | 11 | See ../LINUX_PMEM_API.txt for a detailed description of the Linux API 12 | for Persistent Memory programming. 13 | 14 | To support debugging and testing, libpmem contains a few other things 15 | not required by the LINUX_PMEM_API.txt document. To see the full 16 | list of libpmem features, see LIBPMEM_API.txt in this directory. 17 | 18 | As this is just a sample implementation, libpmem has not been benchmarked 19 | and optimized for performance. The following platform assumptions have 20 | been made for this version: 21 | 22 | - x86_64 Linux is assumed. 23 | 24 | - As part of the x86 architecture assumption mentioned above, this 25 | code assumes cache lines are 64 bytes and the base page size is 4k. 26 | 27 | - By default, libpmem assumes you have Persistent Memory exposed to you 28 | by a PM-aware file system that doesn't use the page cache like PMFS 29 | (see https://github.com/linux-pmfs). If you are playing with these 30 | examples on a non-PM-aware file system (basically just using traditional 31 | memory-mapped files), use the libpmem call pmem_msync_mode() to tell 32 | the library to use msync() to make changes durable. When in doubt, use 33 | msync mode since it will work everywhere, real PM or not real PM. Most 34 | of the example programs take an option, -M, to switch to this mode. 35 | 36 | - It is assumed the Persistent Memory and the platform both support making 37 | changes durable to Persistent Memory by flushing the processor caches 38 | alone. The libpmem function pmem_drain_pm_stores() is empty in this 39 | implementation. Platforms with Intel's ADR feature will flush any stores 40 | that are still sitting in HW buffers when power loss occurs, and this may 41 | be sufficient for some PM products and use cases. But for real applications 42 | you must check with the PM manufacturer to understand what is required 43 | to make changes durable. 44 | 45 | None of this matters when you are just playing with these examples 46 | as long as you don't try testing the power failure case. For development, 47 | see the fault injection mechanisms described in ../icount/README which 48 | help you test code for resilience in the face of random crashes, without 49 | actually having to crash the physical machine. 50 | 51 | If you are interested in using libpmem on a PM-aware file system and doing 52 | very latency-sensitive performance analysis, consider using the inline version 53 | available in pmem_inline.h. 54 | 55 | TODO 56 | 57 | Here's a list of potential enhancements for this libpmem: 58 | 59 | - Provide get/set attribute functions in accordance with the 60 | SNIA NVM Programming model. Use these interfaces to expose 61 | details about what a specific PM product provides such as 62 | atomicity sizes, ECC block sizes, etc. 63 | 64 | - Add logic to pmem_persist() to call msync(2) if the PM requires it. 65 | 66 | - Remove dependence on 64-bit by validating this on 32-bit Linux. 67 | 68 | - Check CPU_ID to confirm CLFLUSH is available before using it. 69 | 70 | - Consider a more portable version that doesn't depend on x86. 71 | 72 | - Consider adding some general-purpose helper routines for larger 73 | atomics, memory allocation, transactions, etc. 74 | 75 | - Benchmark & tune. 76 | -------------------------------------------------------------------------------- /libpmem/pmem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmem.c -- entry points for libpmem 35 | */ 36 | 37 | #include 38 | 39 | #include "pmem.h" 40 | 41 | /* dispatch tables for the various versions of libpmem */ 42 | void *pmem_map_cl(int fd, size_t len); 43 | void pmem_persist_cl(void *addr, size_t len, int flags); 44 | void pmem_flush_cache_cl(void *addr, size_t len, int flags); 45 | void pmem_drain_pm_stores_cl(void); 46 | void *pmem_map_msync(int fd, size_t len); 47 | void pmem_persist_msync(void *addr, size_t len, int flags); 48 | void pmem_flush_cache_msync(void *addr, size_t len, int flags); 49 | void pmem_drain_pm_stores_msync(void); 50 | void *pmem_map_fit(int fd, size_t len); 51 | void pmem_persist_fit(void *addr, size_t len, int flags); 52 | void pmem_flush_cache_fit(void *addr, size_t len, int flags); 53 | void pmem_drain_pm_stores_fit(void); 54 | #define PMEM_CL_INDEX 0 55 | #define PMEM_MSYNC_INDEX 1 56 | #define PMEM_FIT_INDEX 2 57 | static void *(*Map[])(int fd, size_t len) = 58 | { pmem_map_cl, pmem_map_msync, pmem_map_fit }; 59 | static void (*Persist[])(void *addr, size_t len, int flags) = 60 | { pmem_persist_cl, pmem_persist_msync, pmem_persist_fit }; 61 | static void (*Flush[])(void *addr, size_t len, int flags) = 62 | { pmem_flush_cache_cl, pmem_flush_cache_msync, 63 | pmem_flush_cache_fit }; 64 | static void (*Drain_pm_stores[])(void) = 65 | { pmem_drain_pm_stores_cl, pmem_drain_pm_stores_msync, 66 | pmem_drain_pm_stores_fit }; 67 | static int Mode = PMEM_CL_INDEX; /* current libpmem mode */ 68 | 69 | /* 70 | * pmem_msync_mode -- switch libpmem to msync mode 71 | * 72 | * Must be called before any other libpmem routines. 73 | */ 74 | void 75 | pmem_msync_mode(void) 76 | { 77 | Mode = PMEM_MSYNC_INDEX; 78 | } 79 | 80 | /* 81 | * pmem_fit_mode -- switch libpmem to fault injection test mode 82 | * 83 | * Must be called before any other libpmem routines. 84 | */ 85 | void 86 | pmem_fit_mode(void) 87 | { 88 | Mode = PMEM_FIT_INDEX; 89 | } 90 | 91 | /* 92 | * pmem_map -- map the Persistent Memory 93 | */ 94 | void * 95 | pmem_map(int fd, size_t len) 96 | { 97 | return (*Map[Mode])(fd, len); 98 | } 99 | 100 | /* 101 | * pmem_persist -- make any cached changes to a range of PM persistent 102 | */ 103 | void 104 | pmem_persist(void *addr, size_t len, int flags) 105 | { 106 | (*Persist[Mode])(addr, len, flags); 107 | } 108 | 109 | /* 110 | * pmem_flush_cache -- flush processor cache for the given range 111 | */ 112 | void 113 | pmem_flush_cache(void *addr, size_t len, int flags) 114 | { 115 | (*Flush[Mode])(addr, len, flags); 116 | } 117 | 118 | /* 119 | * pmem_fence -- fence/store barrier for Peristent Memory 120 | */ 121 | void 122 | pmem_fence(void) 123 | { 124 | __builtin_ia32_sfence(); 125 | } 126 | 127 | /* 128 | * pmem_drain_pm_stores -- wait for any PM stores to drain from HW buffers 129 | */ 130 | void 131 | pmem_drain_pm_stores(void) 132 | { 133 | (*Drain_pm_stores[Mode])(); 134 | } 135 | -------------------------------------------------------------------------------- /libpmem/pmem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmem.h -- definitions of libpmem entry points 35 | */ 36 | 37 | void pmem_msync_mode(void); /* for testing on non-PM memory-mapped files */ 38 | void pmem_fit_mode(void); /* for fault injection testing */ 39 | 40 | /* commonly-used functions for Persistent Memory */ 41 | void *pmem_map(int fd, size_t len); 42 | void pmem_persist(void *addr, size_t len, int flags); 43 | 44 | /* for advanced users -- functions that do portions of pmem_persist() */ 45 | void pmem_flush_cache(void *addr, size_t len, int flags); 46 | void pmem_fence(void); 47 | void pmem_drain_pm_stores(void); 48 | -------------------------------------------------------------------------------- /libpmem/pmem.map: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # pmem.map -- linker map file for libpmem 33 | # 34 | libpmem.so { 35 | global: 36 | pmem_map; 37 | pmem_flush; 38 | pmem_drain_pm_stores; 39 | pmem_msync_mode; 40 | pmem_fit_mode; 41 | local: 42 | *; 43 | }; 44 | -------------------------------------------------------------------------------- /libpmem/pmem_cl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmem_cl.c -- cache-line-based implementation of libpmem 35 | * 36 | * WARNING: This is for use with Persistent Memory -- if you use this 37 | * with a traditional page-cache-based memory mapped file, your changes 38 | * will not be durable. 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #define ALIGN 64 /* assumes 64B cache line size */ 47 | 48 | /* 49 | * pmem_map -- map the Persistent Memory 50 | * 51 | * This is just a convenience function that calls mmap() with the 52 | * appropriate arguments. 53 | * 54 | * This is the cache-line-based version. 55 | */ 56 | void * 57 | pmem_map_cl(int fd, size_t len) 58 | { 59 | void *base; 60 | 61 | if ((base = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, 62 | fd, 0)) == MAP_FAILED) 63 | return NULL; 64 | 65 | return base; 66 | } 67 | 68 | /* 69 | * pmem_drain_pm_stores -- wait for any PM stores to drain from HW buffers 70 | * 71 | * This is the cache-line-based version. 72 | */ 73 | void 74 | pmem_drain_pm_stores_cl(void) 75 | { 76 | /* 77 | * Nothing to do here -- this implementation assumes the platform 78 | * has something like Intel's ADR feature, which flushes HW buffers 79 | * automatically on power loss. This implementation further assumes 80 | * the Persistent Memory hardware itself doesn't need to be alerted 81 | * when something needs to be persistent. Of course these assumptions 82 | * may be wrong for different combinations of Persistent Memory 83 | * products and platforms, but this is just example code. 84 | * 85 | * TODO: update this to work on other types of platforms. 86 | */ 87 | } 88 | 89 | /* 90 | * pmem_flush_cache -- flush processor cache for the given range 91 | * 92 | * This is the cache-line-based version. 93 | */ 94 | void 95 | pmem_flush_cache_cl(void *addr, size_t len, int flags) 96 | { 97 | uintptr_t uptr; 98 | 99 | /* loop through 64B-aligned chunks covering the given range */ 100 | for (uptr = (uintptr_t)addr & ~(ALIGN - 1); 101 | uptr < (uintptr_t)addr + len; uptr += 64) 102 | __builtin_ia32_clflush((void *)uptr); 103 | } 104 | 105 | /* 106 | * pmem_persist -- make any cached changes to a range of PM persistent 107 | * 108 | * This is the cache-line-based version. 109 | */ 110 | void 111 | pmem_persist_cl(void *addr, size_t len, int flags) 112 | { 113 | pmem_flush_cache_cl(addr, len, flags); 114 | __builtin_ia32_sfence(); 115 | pmem_drain_pm_stores_cl(); 116 | } 117 | -------------------------------------------------------------------------------- /libpmem/pmem_fit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmem_fit.h -- implementation of libpmem for fault injection testing 35 | * 36 | * WARNING: This is a special implementation of libpmem designed for 37 | * fault injection testing. Performance will be very slow with this 38 | * implementation and main memory usage will balloon as the copy-on-writes 39 | * happen. Don't use this unless you read the README and know what you're 40 | * doing. 41 | */ 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "util/util.h" 49 | 50 | #define ALIGN 64 /* assumes 64B cache line size */ 51 | 52 | static int PM_fd; 53 | static uintptr_t PM_base; 54 | 55 | /* 56 | * pmem_map -- map the Persistent Memory 57 | * 58 | * This is the fit version (fault injection test) that uses copy-on-write. 59 | */ 60 | void * 61 | pmem_map_fit(int fd, size_t len) 62 | { 63 | void *base; 64 | 65 | if ((base = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, 66 | fd, 0)) == MAP_FAILED) 67 | return NULL; 68 | 69 | PM_base = (uintptr_t)base; 70 | PM_fd = dup(fd); 71 | 72 | return base; 73 | } 74 | 75 | /* 76 | * pmem_drain_pm_stores -- wait for any PM stores to drain from HW buffers 77 | * 78 | * This is the fit version (fault injection test) that uses copy-on-write. 79 | */ 80 | void 81 | pmem_drain_pm_stores_fit(void) 82 | { 83 | /* 84 | * Nothing to do here for the fit version. 85 | */ 86 | } 87 | 88 | /* 89 | * pmem_flush_cache -- flush processor cache for the given range 90 | * 91 | * This is the fit version (fault injection test) that uses copy-on-write. 92 | */ 93 | void 94 | pmem_flush_cache_fit(void *addr, size_t len, int flags) 95 | { 96 | uintptr_t uptr; 97 | 98 | if (!PM_base) 99 | FATAL("pmem_map hasn't been called"); 100 | 101 | /* 102 | * even though pwrite() can take any random byte addresses and 103 | * lengths, we simulate cache flushing by writing the full 64B 104 | * chunks that cover the given range. 105 | */ 106 | for (uptr = (uintptr_t)addr & ~(ALIGN - 1); 107 | uptr < (uintptr_t)addr + len; uptr += ALIGN) 108 | if (pwrite(PM_fd, (void *)uptr, ALIGN, uptr - PM_base) < 0) 109 | FATALSYS("pwrite len %d offset %lu", len, 110 | addr - PM_base); 111 | } 112 | 113 | /* 114 | * pmem_persist_fit -- make any cached changes to a range of PM persistent 115 | * 116 | * This is the fit version (fault injection test) that uses copy-on-write. 117 | */ 118 | void 119 | pmem_persist_fit(void *addr, size_t len, int flags) 120 | { 121 | pmem_flush_cache_fit(addr, len, flags); 122 | __builtin_ia32_sfence(); 123 | pmem_drain_pm_stores_fit(); 124 | } 125 | -------------------------------------------------------------------------------- /libpmem/pmem_inline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmem_inline.h -- inline versions of pmem for performance 35 | * 36 | * If your program is so latency sensitive that the overhead of 37 | * function calls need to be optimized out, include this file 38 | * instead of pmem.h. Of course, the downside is that the pmem 39 | * library functions will then be compiled into your program so 40 | * if the pmem library gets updated, your program will have to be 41 | * recompiled to use the updates. 42 | * 43 | * This inlined version only contains the cache-line version of 44 | * the pmem interfaces (not the "msync mode" or "fault injection 45 | * test mode" interfaces available with the full libpmem. 46 | */ 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #define ALIGN 64 /* assumes 64B cache line size */ 54 | 55 | static inline void * 56 | pmem_map(int fd, size_t len) 57 | { 58 | void *base; 59 | 60 | if ((base = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, 61 | fd, 0)) == MAP_FAILED) 62 | return NULL; 63 | 64 | return base; 65 | } 66 | 67 | static inline void 68 | pmem_drain_pm_stores(void) 69 | { 70 | /* 71 | * Nothing to do here -- this implementation assumes the platform 72 | * has something like Intel's ADR feature, which flushes HW buffers 73 | * automatically on power loss. This implementation further assumes 74 | * the Persistent Memory hardware itself doesn't need to be alerted 75 | * when something needs to be persistent. Of course these assumptions 76 | * may be wrong for different combinations of Persistent Memory 77 | * products and platforms, but this is just example code. 78 | * 79 | * TODO: update this to work on other types of platforms. 80 | */ 81 | } 82 | 83 | static inline void 84 | pmem_flush_cache(void *addr, size_t len, int flags) 85 | { 86 | uintptr_t uptr; 87 | 88 | /* loop through 64B-aligned chunks covering the given range */ 89 | for (uptr = (uintptr_t)addr & ~(ALIGN - 1); 90 | uptr < (uintptr_t)addr + len; uptr += 64) 91 | __builtin_ia32_clflush((void *)uptr); 92 | } 93 | 94 | static inline void 95 | pmem_persist(void *addr, size_t len, int flags) 96 | { 97 | pmem_flush_cache(addr, len, flags); 98 | __builtin_ia32_sfence(); 99 | pmem_drain_pm_stores(); 100 | } 101 | -------------------------------------------------------------------------------- /libpmem/pmem_msync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmem_msync.c -- msync-based implementation of libpmem 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "util/util.h" 44 | 45 | #define ALIGN 4096 /* assumes 4k page size for use with msync() */ 46 | 47 | /* 48 | * pmem_map -- map the Persistent Memory 49 | * 50 | * This is just a convenience function that calls mmap() with the 51 | * appropriate arguments. 52 | * 53 | * This is the msync-based version. 54 | */ 55 | void * 56 | pmem_map_msync(int fd, size_t len) 57 | { 58 | void *base; 59 | 60 | if ((base = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, 61 | fd, 0)) == MAP_FAILED) 62 | return NULL; 63 | 64 | return base; 65 | } 66 | 67 | /* 68 | * pmem_drain_pm_stores -- wait for any PM stores to drain from HW buffers 69 | * 70 | * This is the msync-based version. 71 | */ 72 | void 73 | pmem_drain_pm_stores_msync(void) 74 | { 75 | /* 76 | * Nothing to do here for the msync-based version. 77 | */ 78 | } 79 | 80 | /* 81 | * pmem_flush_cache -- flush processor cache for the given range 82 | * 83 | * This is the msync-based version. 84 | */ 85 | void 86 | pmem_flush_cache_msync(void *addr, size_t len, int flags) 87 | { 88 | uintptr_t uptr; 89 | 90 | /* 91 | * msync requires len to be a multiple of pagesize, so 92 | * adjust addr and len to represent the full 4k chunks 93 | * covering the given range. 94 | */ 95 | 96 | /* increase len by the amount we gain when we round addr down */ 97 | len += (uintptr_t)addr & (ALIGN - 1); 98 | 99 | /* round addr down to page boundary */ 100 | uptr = (uintptr_t)addr & ~(ALIGN - 1); 101 | 102 | /* round len up to multiple of page size */ 103 | len = (len + (ALIGN - 1)) & ~(ALIGN - 1); 104 | 105 | if (msync((void *)uptr, len, MS_SYNC) < 0) 106 | FATALSYS("msync"); 107 | } 108 | 109 | /* 110 | * pmem_persist_msync -- make any cached changes to a range of PM persistent 111 | * 112 | * This is the msync-based version. 113 | */ 114 | void 115 | pmem_persist_msync(void *addr, size_t len, int flags) 116 | { 117 | pmem_flush_cache_msync(addr, len, flags); 118 | __builtin_ia32_sfence(); 119 | pmem_drain_pm_stores_msync(); 120 | } 121 | -------------------------------------------------------------------------------- /libpmemalloc/.gitignore: -------------------------------------------------------------------------------- 1 | libpmemalloc.a 2 | libpmemalloc.so 3 | pmemalloc_test1 4 | pmemalloc_test2 5 | pmemalloc_check 6 | -------------------------------------------------------------------------------- /libpmemalloc/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile -- Makefile for libpmemalloc 33 | # 34 | 35 | TARGETS = libpmemalloc.a libpmemalloc.so pmemalloc_test1 pmemalloc_test2\ 36 | pmemalloc_check 37 | INCS = -I.. 38 | OBJS = pmemalloc.o util.o icount.o 39 | LIBFILES = ../libpmem/libpmem.a libpmemalloc.a 40 | MAPFILE = pmemalloc.map 41 | SOVERSION = 1 42 | CFLAGS = -ggdb 43 | 44 | all: $(TARGETS) 45 | 46 | libpmemalloc.a: $(OBJS) 47 | $(AR) rv $@ $(OBJS) 48 | 49 | libpmemalloc.so: $(OBJS) 50 | $(CC) $(CFLAGS) -shared -Wl,--version-script=$(MAPFILE),-soname,$(SONAME).$(SOVERSION) -o $@ $(OBJS) 51 | 52 | .c.o: 53 | $(CC) -c -o $@ $(CFLAGS) $(INCS) $< 54 | 55 | libpmemalloc.a libpmemalloc.so: CFLAGS += -fPIC 56 | 57 | pmemalloc_test1: pmemalloc_test1.o pmemalloc.h $(LIBFILES) 58 | $(CC) -o $@ $(CFLAGS) $(INCS) pmemalloc_test1.c $(LIBFILES) 59 | 60 | pmemalloc_test2: pmemalloc_test2.o pmemalloc.h $(LIBFILES) 61 | $(CC) -o $@ $(CFLAGS) $(INCS) pmemalloc_test2.c $(LIBFILES) 62 | 63 | pmemalloc_check: pmemalloc_check.o pmemalloc.h $(LIBFILES) 64 | $(CC) -o $@ $(CFLAGS) $(INCS) pmemalloc_check.c $(LIBFILES) 65 | 66 | util.o: ../util/util.c ../util/util.h 67 | $(CC) -c -o $@ $(CFLAGS) $(INCS) -fPIC $< 68 | 69 | icount.o: ../icount/icount.c ../icount/icount.h 70 | $(CC) -c -o $@ $(CFLAGS) $(INCS) -fPIC $< 71 | 72 | ../libpmem/libpmem.a: force 73 | $(MAKE) -C ../libpmem 74 | 75 | clean: 76 | $(RM) *.o core a.out 77 | 78 | clobber: clean 79 | $(RM) $(TARGETS) 80 | 81 | force: 82 | 83 | test: pmemalloc_test1 pmemalloc_check 84 | $(RM) testfile 85 | ./pmemalloc_test1 $(TESTARGS) -M testfile 2 3 4 86 | ./pmemalloc_check $(TESTARGS) testfile 87 | ./pmemalloc_test1 $(TESTARGS) testfile 88 | ./pmemalloc_test1 $(TESTARGS) -M -f testfile 89 | ./pmemalloc_check $(TESTARGS) testfile 90 | ./pmemalloc_test1 $(TESTARGS) testfile 91 | ./pmemalloc_test1 $(TESTARGS) -M -f testfile 92 | ./pmemalloc_check $(TESTARGS) testfile 93 | ./pmemalloc_test1 $(TESTARGS) testfile 94 | ./pmemalloc_test1 $(TESTARGS) -M -f testfile 95 | ./pmemalloc_check $(TESTARGS) testfile 96 | ./pmemalloc_test1 $(TESTARGS) testfile 97 | 98 | # 99 | # "make allcounts" takes a while to run. 100 | # 101 | CMD = rm -f testfile%C; ./pmemalloc_test1 -F -i %C testfile%C 3 2 1; ./pmemalloc_test1 testfile%C; ./pmemalloc_check testfile%C 102 | 103 | allcounts: pmemalloc_test1 pmemalloc_check 104 | @../icount/allcounts -j 200 '$(CMD)' 105 | @rm -f testfile* 106 | 107 | test: pmemalloc_test1 pmemalloc_check pmemalloctest 108 | @./pmemalloctest 2>&1 | tee pmemalloctest.out 109 | @cmp -s pmemalloctest.out pmemalloctest.pass || (echo FAIL: pmemalloctest.out does not match pmemalloctest.pass; false) 110 | @echo PASS 111 | 112 | .PHONY: all clean clobber force allcounts test 113 | -------------------------------------------------------------------------------- /libpmemalloc/PMEMALLOC_API.txt: -------------------------------------------------------------------------------- 1 | NAME 2 | libpmemalloc -- Persistent Memory malloc-like library 3 | 4 | SYNOPSIS 5 | #include 6 | cc ... -lpmemalloc 7 | 8 | void *pmemalloc_init(const char *path, size_t size); 9 | void *pmemalloc_static_area(void *pmp); 10 | void *pmemalloc_reserve(void *pmp, size_t size); 11 | void pmemalloc_persist(void *pmp, void **parentp_, void *ptr_); 12 | void pmemalloc_onactive(void *pmp, void *ptr_, 13 | void **parentp_, void *nptr_); 14 | void pmemalloc_onfree(void *pmp, void *ptr_, 15 | void **parentp_, void *nptr_); 16 | void pmemalloc_activate(void *pmp, void *ptr_); 17 | void pmemalloc_free(void *pmp, void *ptr_); 18 | void pmemalloc_check(const char *path); 19 | 20 | PMEM(pmp, ptr_) 21 | 22 | 23 | NOTE: If libpmemalloc has not been installed on this system, you'll 24 | want to arrange for "pmemalloc.h" to be included via a 25 | non-system path, and you'll want to arrange to either find 26 | libpmemalloc to be using LD_LIBRARY_PATH or use the static 27 | version, libpmemalloc.a. 28 | 29 | DESCRIPTION 30 | 31 | libpmemalloc provides a malloc-like library for use with 32 | Persistent Memory. The interfaces are not identical to 33 | malloc(), since they are designed to allow the application 34 | to manage data structures that must remain consistent across 35 | crashes and other interruptions. 36 | 37 | void *pmemalloc_init(const char *path, size_t size); 38 | 39 | Initialize libpmemalloc to use the given file as a 40 | pmem pool with the given default size. The return 41 | value is an opaque handle that must be passed to 42 | most of the other entry points. 43 | 44 | void *pmemalloc_static_area(void *pmp); 45 | 46 | Return a pointer to the 4k "static area" that applications 47 | may use to store pointers to their PM data structures (or 48 | whatever else they want to store in it). This function 49 | returns an absolute pointer (no need to pass it to the 50 | PMEM() macro before using it). 51 | 52 | void *pmemalloc_reserve(void *pmp, size_t size); 53 | 54 | This is malloc(), but for Persistent Memory. The 55 | application starts by using pmemalloc_reserve() to 56 | "reserve" the block of PM desired. We say "reserve" 57 | instead of "allocate" because if there's a crash 58 | before the application links to the new memory, it 59 | will be automatically returned to the free pool on 60 | restart, avoiding PM memory leaks due to crashes. 61 | 62 | After acquiring memory with pmemalloc_reserve(), the 63 | application typically initializes it with whatever 64 | values it needs, calls pmemalloc_onactive() to set 65 | up atomic pointer manipulation, and when ready, the 66 | application then calls pmemalloc_persist(). 67 | 68 | void pmemalloc_onactive(void *pmp, void *ptr_, 69 | void **parentp_, void *nptr_); 70 | 71 | Arrange for the pointer at *parentp_ to be assigned 72 | the value nptr_ atomically when the reserved memory at 73 | *ptr_ is activated by the next call to pmemalloc_activate(). 74 | Up to three pointers can be atomically set this way (which 75 | is typically enough to install newly allocated memory into 76 | a tree or linked list). 77 | 78 | void pmemalloc_onfree(void *pmp, void *ptr_, 79 | void **parentp_, void *nptr_); 80 | 81 | Arrange for the pointer at *parentp_ to be assigned 82 | the value nptr_ atomically when the reserved memory at 83 | *ptr_ is freed by the next call to pmemalloc_free(). 84 | Up to three pointers can be atomically set this way. 85 | 86 | void pmemalloc_activate(void *pmp, void *ptr_); 87 | 88 | Activate a reserved chunk of memory (as returned by a 89 | previous call to pmemalloc_reserve()). Once this call 90 | completes, the memory will no longer return to the free 91 | list automatically on crash recovery. In addition to 92 | marking the memory as active, this call also persists 93 | the memory at *ptr_ and executes all the pointer assignments 94 | supplied by earlier calls to pmemalloc_onactive(). 95 | 96 | void pmemalloc_free(void *pmp, void *ptr_); 97 | 98 | Free the chunk of memory given by ptr_. The memory may 99 | either be reserved or active on entry. When this call 100 | completes, the memory will be free and available for use. 101 | In addition to marking the memory as free, this call also 102 | executes all the pointer assignments supplied by earlier 103 | calls to pmemalloc_onfree(). 104 | 105 | void pmemalloc_check(const char *path); 106 | 107 | This routine performs a consistency check of the pmem 108 | memory pool and prints out a summary. This is mainly 109 | used for testing & debugging, to detect corruption in 110 | the Persistent Memory file. 111 | 112 | SEE ALSO 113 | LINUX_PMEM_API.txt, LIBPMEM_API.txt, mmap(2), msync(2) 114 | -------------------------------------------------------------------------------- /libpmemalloc/README: -------------------------------------------------------------------------------- 1 | This is libpmemalloc/README. 2 | 3 | This is an example of a simple Persistent Memory malloc-like library. 4 | 5 | WARNING: This example library is not suitable for production use in any 6 | real-world environment. It is intended to provide a "complete enough" 7 | example of how to use Persistent Memory. It deals with issues like making 8 | sure the memory pool is consistent and usable after a crash. No attention 9 | was paid to making it an efficient general-purpose memory allocation library. 10 | This example is not MT safe or shared memory safe -- it assumes a single 11 | process using a memory-mapped file with maximum one thread executing code in 12 | this file at any given time. 13 | 14 | What you'll find here: 15 | 16 | pmemalloc.c This is the example itself, the malloc-like 17 | pmemalloc.h library. Take a look at this code to see 18 | how some common Persistent Memory problems 19 | are solved. 20 | 21 | PMEMALLOC_API.txt This document describes how to write a 22 | program that uses this example library. 23 | 24 | design.txt This is a (brief) design document that 25 | describes the strategy used to make this 26 | library resilient to crashes. 27 | 28 | pmemalloc_test*.c These are unit tests, but may also provide 29 | useful examples for how to use this library. 30 | 31 | The point of this example is to provide code that people can look at 32 | to get ideas about how to use Persistent Memory. But if you just want 33 | to run a unit test and see things working, try this: 34 | 35 | make test1 36 | 37 | Also see the example in ../binarytree, which uses this library to build 38 | a binary tree data structure in Persistent Memory. 39 | 40 | 41 | TODO 42 | 43 | - pmemalloc_check() can do much more extensive checking. 44 | 45 | - There's some code replication that can be cleaned up. Like the code 46 | handling the ACTIVATING and FREEING states is similar and is also 47 | replicated in the recovery code. 48 | 49 | - Get rid of the full recovery scan in pmemalloc_init() by keeping a list 50 | of clumps that are potentially in transition in the pmem_pool_header and 51 | just scanning those for work. 52 | 53 | - Handle larger transactions (instead of a limit of 3 "onactive" actions). 54 | 55 | - Handle pointers between different pmem pools -- right now all PM pointers 56 | must be to something in the same pool. 57 | 58 | - Improve allocation performance (which currently degrades as more memory 59 | is in-use, and degrades even worse on fragmentation). Maintaining a 60 | few extra pointers to optimize scans through the pool would go a long way. 61 | -------------------------------------------------------------------------------- /libpmemalloc/design.txt: -------------------------------------------------------------------------------- 1 | the memory pool: 2 | 3 | the memory pool begins with 4 pages, 4k each: 4 | offset 0: this page is invalidated (via mprotect) 5 | (this is so dereferencing a NULL pointer faults) 6 | offset 4096: this page is the "static" 4k area 7 | offset 8192: another invalid page (red zone after static area) 8 | offset 12288: memory pool header, fields are: 9 | signature: "*PMEMALLOC_POOL\0" 10 | totalsize: total file size 11 | (rest of 4k area padded with zeroes) 12 | 13 | the remainder of memory pool starts at offset 16384 and 14 | is managed as an array of 64-byte chunks, divided up into 15 | memory "clumps". each clump is has a 64-byte preamble 16 | and the associated memory. the 64-byte header contains: 17 | nbytes: number of bytes in this clump (includes header bytes) 18 | state: zero means free, non-zero means not free 19 | the possible states are: 20 | FREE, RESERVED, ACTIVATING, ACTIVE, FREEING 21 | on: the list of pointer assignments to do onactive or onfree. 22 | 23 | when a memory pool is initially created, there would be a single 24 | clump at offset 16384 whose size represent all the memory in the 25 | file from 16384-EOF. 26 | 27 | each time a new allocation happens via pmemalloc_reserve(), the clump 28 | that is chosen for the allocation is divided into two (if the clump 29 | size is at least 128 bytes larger than the allocation request, 30 | otherwise the entire clump is used without dividing it). 31 | 32 | example, an allocation request for 1000 bytes in this memory pool: 33 | 34 | |256 ACTIVE|2048 FREE|256 ACTIVE| 35 | 36 | would start by rounding the request up to a multiple of 64 (1024) 37 | and would then scan the pool, starting from the first entry, looking 38 | for the first fit. each time it doesn't find a match, it adds 39 | the clump size find the next clump. in this example, it finds 40 | the second clump of size 2048. since 2048 - 1024 = 1024, and that's 41 | bigger than 128, the allocator divides the clump in two, leaving this: 42 | 43 | |256 ACTIVE|1024 RESERVED|1024 FREE|256 ACTIVE| 44 | 45 | when freed via pmemalloc_free(), an allocation is marked FREE and is 46 | coalesced with adjent FREE clumps. crash recovery automatically 47 | scans the memory pool for RESERVED allocations and frees them. 48 | 49 | states and transitions: 50 | 51 | the above algorithms are made crash-safe by careful ordering of 52 | any operation done to the memory pool. on recovery from a crash, 53 | it must be possible to determine the state of each clump and 54 | for any clumps that are not FREE or ACTIVE, the state must either 55 | be advanced to the ACTIVE state, or reverted to the FREE state 56 | (finishing state transitions or undoing state transitions as 57 | appropriate). the most common recovery is to take a RESERVED clump 58 | and return it to the FREE state, but the recovery algorithm must 59 | handle a crash between any two instructions from the first instruction 60 | of pmemalloc_reserve() to the last instruction of pmemalloc_activate(). 61 | 62 | states: 63 | 64 | A clump of memory in the pmem pool can be thought of as moving 65 | between these states: 66 | 67 | 0. FREE 68 | 1. RESERVED 69 | 2. ACTIVATING 70 | 3. ACTIVE 71 | 4. FREEING 72 | 0. FREE 73 | 74 | recovery: 75 | 76 | for each RESERVED clump: 77 | return the clump to the FREE state 78 | 79 | for each ACTIVATING clump: 80 | progress the clump on to the ACTIVE state 81 | 82 | for each FREEING clump: 83 | progress the clump on to the FREE state 84 | 85 | coalesce any adjacent free clumps 86 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmemalloc.h -- example malloc library for Persistent Memory 35 | */ 36 | 37 | #include 38 | 39 | /* 40 | * size of the static area returned by pmem_static_area() 41 | */ 42 | #define PMEM_STATIC_SIZE 4096 43 | 44 | /* 45 | * number of onactive/onfree values allowed 46 | */ 47 | #define PMEM_NUM_ON 3 48 | 49 | /* 50 | * given a relative pointer, add in the base associated 51 | * with the given Persistent Memory Pool (pmp). 52 | */ 53 | #define PMEM(pmp, ptr_) ((typeof(ptr_))(pmp + (uintptr_t)ptr_)) 54 | 55 | void *pmemalloc_init(const char *path, size_t size); 56 | void *pmemalloc_static_area(void *pmp); 57 | void *pmemalloc_reserve(void *pmp, size_t size); 58 | void pmemalloc_onactive(void *pmp, void *ptr_, void **parentp_, void *nptr_); 59 | void pmemalloc_onfree(void *pmp, void *ptr_, void **parentp_, void *nptr_); 60 | void pmemalloc_activate(void *pmp, void *ptr_); 61 | void pmemalloc_free(void *pmp, void *ptr_); 62 | void pmemalloc_check(const char *path); 63 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloc.map: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # pmemalloc.map -- linker map file for libpmemalloc 33 | # 34 | libpmemalloc.so { 35 | global: 36 | pmemalloc_init; 37 | pmemalloc_static_area; 38 | pmemalloc_reserve; 39 | pmemalloc_unreserve; 40 | pmemalloc_persist; 41 | pmemalloc_free; 42 | 43 | local: 44 | *; 45 | }; 46 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloc_check.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmemalloc_check.c -- check the health of a pmem pool 35 | * 36 | * Usage: pmemalloc_check [-FMd] path 37 | * 38 | * This is just a simple CLI for calling pmemalloc_check(). 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include "util/util.h" 49 | #include "libpmem/pmem.h" 50 | #include "pmemalloc.h" 51 | 52 | char Usage[] = "[-FMd] path"; /* for USAGE() */ 53 | 54 | int 55 | main(int argc, char *argv[]) 56 | { 57 | const char *path; 58 | int opt; 59 | 60 | Myname = argv[0]; 61 | while ((opt = getopt(argc, argv, "FMd")) != -1) { 62 | switch (opt) { 63 | case 'F': 64 | pmem_fit_mode(); 65 | break; 66 | 67 | case 'M': 68 | pmem_msync_mode(); 69 | break; 70 | 71 | case 'd': 72 | Debug++; 73 | break; 74 | 75 | default: 76 | USAGE(NULL); 77 | } 78 | } 79 | 80 | if (optind >= argc) 81 | USAGE("No path given"); 82 | path = argv[optind++]; 83 | 84 | if (optind < argc) 85 | USAGE(NULL); 86 | 87 | pmemalloc_check(path); 88 | 89 | exit(0); 90 | } 91 | 92 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloc_test1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmemalloc_test1.c -- unit test 1 for libpmemalloc 35 | * 36 | * Usage: pmemalloc_test1 [-FMd] path [numbers...] 37 | * 38 | * Prepends any numbers given to a pmemalloc-based linked list. 39 | * If no numbers given, prints the list. 40 | */ 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "util/util.h" 50 | #include "icount/icount.h" 51 | #include "libpmem/pmem.h" 52 | #include "pmemalloc.h" 53 | 54 | #define MY_POOL_SIZE (10 * 1024 * 1024) 55 | 56 | /* 57 | * define the nodes of the linked list used by the test code below 58 | */ 59 | struct node { 60 | struct node *next_; 61 | int value; 62 | }; 63 | 64 | /* 65 | * define the static info we keep for the pmem pool we create 66 | */ 67 | struct static_info { 68 | struct node *rootnp_; /* first node of the linked list */ 69 | }; 70 | 71 | char Usage[] = "[-FMd] path [strings...]"; /* for USAGE() */ 72 | 73 | int 74 | main(int argc, char *argv[]) 75 | { 76 | const char *path; 77 | int opt; 78 | int fflag = 0; 79 | int iflag = 0; 80 | unsigned long icount; 81 | void *pmp; 82 | struct static_info *sp; 83 | struct node *parent_; 84 | struct node *np_; 85 | 86 | Myname = argv[0]; 87 | while ((opt = getopt(argc, argv, "FMdfi:")) != -1) { 88 | switch (opt) { 89 | case 'F': 90 | pmem_fit_mode(); 91 | break; 92 | 93 | case 'M': 94 | pmem_msync_mode(); 95 | break; 96 | 97 | case 'd': 98 | Debug++; 99 | break; 100 | 101 | case 'f': 102 | fflag++; 103 | break; 104 | 105 | case 'i': 106 | iflag++; 107 | icount = strtoul(optarg, NULL, 10); 108 | break; 109 | 110 | default: 111 | USAGE(NULL); 112 | } 113 | } 114 | 115 | if (optind >= argc) 116 | USAGE("No path given"); 117 | path = argv[optind++]; 118 | 119 | if ((pmp = pmemalloc_init(path, MY_POOL_SIZE)) == NULL) 120 | FATALSYS("pmemalloc_init on %s", path); 121 | 122 | /* fetch our static info */ 123 | sp = (struct static_info *)pmemalloc_static_area(pmp); 124 | 125 | if (optind < argc) { /* numbers supplied as arguments? */ 126 | int i; 127 | 128 | if (fflag) 129 | USAGE("unexpected extra arguments given with -f flag"); 130 | 131 | if (iflag) 132 | icount_start(icount); /* start instruction count */ 133 | 134 | for (i = optind; i < argc; i++) { 135 | int value = atoi(argv[i]); 136 | 137 | if ((np_ = pmemalloc_reserve(pmp, 138 | sizeof(*np_))) == NULL) 139 | FATALSYS("pmemalloc_reserve"); 140 | 141 | /* link it in at the beginning of the list */ 142 | PMEM(pmp, np_)->next_ = sp->rootnp_; 143 | PMEM(pmp, np_)->value = value; 144 | pmemalloc_onactive(pmp, np_, 145 | (void **)&sp->rootnp_, np_); 146 | pmemalloc_activate(pmp, np_); 147 | } 148 | 149 | if (iflag) { 150 | icount_stop(); /* end instruction count */ 151 | 152 | printf("Total instruction count: %lu\n", 153 | icount_total()); 154 | } 155 | } else if (fflag) { 156 | /* 157 | * remove first item from list 158 | */ 159 | if (sp->rootnp_ == NULL) 160 | FATAL("the list is empty"); 161 | 162 | if (iflag) 163 | icount_start(icount); /* start instruction count */ 164 | 165 | np_ = sp->rootnp_; 166 | pmemalloc_onfree(pmp, np_, (void **)&sp->rootnp_, 167 | PMEM(pmp, np_)->next_); 168 | pmemalloc_free(pmp, np_); 169 | 170 | if (iflag) { 171 | icount_stop(); /* end instruction count */ 172 | 173 | printf("Total instruction count: %lu\n", 174 | icount_total()); 175 | } 176 | } else { 177 | char *sep = ""; 178 | 179 | /* 180 | * traverse the list, printing the numbers found 181 | */ 182 | np_ = sp->rootnp_; 183 | while (np_) { 184 | printf("%s%d", sep, PMEM(pmp, np_)->value); 185 | sep = " "; 186 | np_ = PMEM(pmp, np_)->next_; 187 | } 188 | printf("\n"); 189 | } 190 | 191 | DEBUG("Done."); 192 | exit(0); 193 | } 194 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloc_test2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * pmemalloc_test2.c -- unit test 2 for libpmemalloc 35 | * 36 | * Usage: pmemalloc_test2 [-FMd] path 37 | */ 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "util/util.h" 47 | #include "icount/icount.h" 48 | #include "libpmem/pmem.h" 49 | #include "pmemalloc.h" 50 | 51 | #define MY_POOL_SIZE (10 * 1024 * 1024) 52 | #define NPTRS 4096 53 | 54 | char Usage[] = "[-FMd] path"; /* for USAGE() */ 55 | 56 | int 57 | main(int argc, char *argv[]) 58 | { 59 | const char *path; 60 | int opt; 61 | void *pmp; 62 | int i; 63 | void *ptrs[NPTRS]; 64 | 65 | Myname = argv[0]; 66 | while ((opt = getopt(argc, argv, "FMdfi:")) != -1) { 67 | switch (opt) { 68 | case 'F': 69 | pmem_fit_mode(); 70 | break; 71 | 72 | case 'M': 73 | pmem_msync_mode(); 74 | break; 75 | 76 | case 'd': 77 | Debug++; 78 | break; 79 | 80 | default: 81 | USAGE(NULL); 82 | } 83 | } 84 | 85 | if (optind >= argc) 86 | USAGE("No path given"); 87 | path = argv[optind++]; 88 | 89 | if (optind < argc) 90 | USAGE(NULL); 91 | 92 | if ((pmp = pmemalloc_init(path, MY_POOL_SIZE)) == NULL) 93 | FATALSYS("pmemalloc_init on %s", path); 94 | 95 | for (i = 0; i < NPTRS; i++) { 96 | if ((ptrs[i] = pmemalloc_reserve(pmp, 10 + i)) == NULL) 97 | FATALSYS("pmemalloc_reserve: iteration %d", i); 98 | 99 | pmemalloc_activate(pmp, ptrs[i]); 100 | } 101 | 102 | pmemalloc_check(path); 103 | 104 | for (i = 0; i < NPTRS; i += 2) { 105 | pmemalloc_free(pmp, ptrs[i]); 106 | } 107 | 108 | pmemalloc_check(path); 109 | 110 | for (i = 0; i < NPTRS; i += 2) { 111 | if ((ptrs[i] = pmemalloc_reserve(pmp, 1 + i)) == NULL) 112 | FATALSYS("pmemalloc_reserve: iteration %d", i); 113 | 114 | pmemalloc_activate(pmp, ptrs[i]); 115 | } 116 | 117 | pmemalloc_check(path); 118 | 119 | for (i = 0; i < NPTRS; i++) { 120 | pmemalloc_free(pmp, ptrs[i]); 121 | } 122 | 123 | pmemalloc_check(path); 124 | 125 | DEBUG("Done."); 126 | exit(0); 127 | } 128 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloctest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2013, Intel Corporation 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # 17 | # * Neither the name of Intel Corporation nor the names of its 18 | # contributors may be used to endorse or promote products derived 19 | # from this software without specific prior written permission. 20 | # 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | # 34 | # pmemalloctest -- unit test for pmemalloc example code 35 | # 36 | # pmemalloctest.pass contains the output this script generates if the test passes. 37 | # 38 | 39 | nflag= 40 | while getopts '' opt 41 | do 42 | case $opt in 43 | n) 44 | nflag=1 45 | ;; 46 | ?) 47 | echo "Usage: $0" >&2 48 | exit 1 49 | ;; 50 | esac 51 | done 52 | 53 | set -e 54 | 55 | echo Running test... 56 | echo rm -f testfile 57 | rm -f testfile 58 | echo ./pmemalloc_test1 testfile 1 2 3 4 59 | ./pmemalloc_test1 testfile 1 2 3 4 60 | echo ./pmemalloc_test1 testfile 61 | ./pmemalloc_test1 testfile 62 | 63 | echo Done. 64 | 65 | exit 0 66 | -------------------------------------------------------------------------------- /libpmemalloc/pmemalloctest.pass: -------------------------------------------------------------------------------- 1 | Running test... 2 | rm -f testfile 3 | ./pmemalloc_test1 testfile 1 2 3 4 4 | ./pmemalloc_test1 testfile 5 | 4 3 2 1 6 | Done. 7 | -------------------------------------------------------------------------------- /trivial/.gitignore: -------------------------------------------------------------------------------- 1 | trivial 2 | testfile 3 | -------------------------------------------------------------------------------- /trivial/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile for trivial example 33 | # 34 | 35 | all: trivial 36 | 37 | trivial: trivial.c 38 | $(CC) -o $@ $^ 39 | 40 | test: trivial trivialtest 41 | @./trivialtest 2>&1 | tee trivialtest.out 42 | @cmp -s trivialtest.out trivialtest.pass || (echo FAIL: trivialtest.out does not match trivialtest.pass; false) 43 | @echo PASS 44 | 45 | clean: 46 | $(RM) *.o core a.out testfile 47 | 48 | clobber: clean 49 | $(RM) trivial 50 | 51 | .PHONY: all test clean clobber 52 | -------------------------------------------------------------------------------- /trivial/README: -------------------------------------------------------------------------------- 1 | This is trivial/README. 2 | 3 | This is the most trivial example I could come up with to illustrate 4 | how to memory map Persistent Memory, store a few bytes to it, and 5 | make the stores durable. The example is totally self-contained in 6 | a single file. No hard problems are solved in this example -- it 7 | just shows you how to use mmap() and msync(). 8 | 9 | To build this use: 10 | make 11 | 12 | To run a trivial test use: 13 | make test 14 | -------------------------------------------------------------------------------- /trivial/trivial.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * trivial.c -- smallest possible, self-contained example 35 | * 36 | * This file memory-maps a file and stores a string to it. It is 37 | * a quick example of how to use mmap() and msync() with Persistent 38 | * Memory. 39 | * 40 | * To build this example: 41 | * gcc -o trivial trivial.c 42 | * 43 | * To run it, create a 4k file, run the example, and dump the result: 44 | * dd if=/dev/zero of=testfile bs=4k count=1 45 | * ./trivial 46 | * od -c testfile 47 | */ 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | int 56 | main(int argc, char *argv[]) 57 | { 58 | int fd; 59 | char *pmaddr; 60 | 61 | if (argc != 2) { 62 | fprintf(stderr, "Usage: %s filename\n", argv[0]); 63 | exit(1); 64 | } 65 | 66 | if ((fd = open(argv[1], O_RDWR)) < 0) { 67 | perror(argv[1]); 68 | exit(1); 69 | } 70 | 71 | /* 72 | * Map 4k from the file into our memory for read & write. 73 | * Use MAP_SHARED for Persistent Memory so that stores go 74 | * directly to the PM and are globally visible. 75 | */ 76 | if ((pmaddr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 77 | fd, 0)) == MAP_FAILED) { 78 | perror("mmap"); 79 | exit(1); 80 | } 81 | 82 | /* don't need the fd anymore, the mapping stays around */ 83 | close(fd); 84 | 85 | /* store a string to the Persistent Memory */ 86 | strcpy(pmaddr, "Hello, Persistent Memory!"); 87 | 88 | /* 89 | * The above stores may or may not be sitting in cache at 90 | * this point, depending on other system activity causing 91 | * cache pressure. Force the change to be durable (flushed 92 | * all the say to the Persistent Memory) using msync(). 93 | */ 94 | if (msync((void *)pmaddr, 4096, MS_SYNC) < 0) { 95 | perror("msync"); 96 | exit(1); 97 | } 98 | 99 | printf("Done.\n"); 100 | exit(0); 101 | } 102 | -------------------------------------------------------------------------------- /trivial/trivialtest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2013, Intel Corporation 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions 7 | # are met: 8 | # 9 | # * Redistributions of source code must retain the above copyright 10 | # notice, this list of conditions and the following disclaimer. 11 | # 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # 17 | # * Neither the name of Intel Corporation nor the names of its 18 | # contributors may be used to endorse or promote products derived 19 | # from this software without specific prior written permission. 20 | # 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | # 34 | # trivialtest -- unit test for trivial example code 35 | # 36 | # trivialtest.pass contains the output this script generates if the test passes. 37 | # 38 | 39 | nflag= 40 | while getopts '' opt 41 | do 42 | case $opt in 43 | n) 44 | nflag=1 45 | ;; 46 | ?) 47 | echo "Usage: $0" >&2 48 | exit 1 49 | ;; 50 | esac 51 | done 52 | 53 | set -e 54 | 55 | echo Running test... 56 | echo rm -f testfile 57 | rm -f testfile 58 | 59 | echo dd if=/dev/zero of=testfile bs=4k count=1 status=noxfer 60 | dd if=/dev/zero of=testfile bs=4k count=1 status=noxfer 61 | 62 | echo ./trivial testfile 63 | ./trivial testfile 64 | 65 | echo od -c testfile 66 | od -c testfile 67 | 68 | echo Done. 69 | 70 | exit 0 71 | -------------------------------------------------------------------------------- /trivial/trivialtest.pass: -------------------------------------------------------------------------------- 1 | Running test... 2 | rm -f testfile 3 | dd if=/dev/zero of=testfile bs=4k count=1 status=noxfer 4 | 1+0 records in 5 | 1+0 records out 6 | ./trivial testfile 7 | Done. 8 | od -c testfile 9 | 0000000 H e l l o , P e r s i s t e n 10 | 0000020 t M e m o r y ! \0 \0 \0 \0 \0 \0 \0 11 | 0000040 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 12 | * 13 | 0010000 14 | Done. 15 | -------------------------------------------------------------------------------- /util/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013, Intel Corporation 2 | # 3 | # Redistribution and use in source and binary forms, with or without 4 | # modification, are permitted provided that the following conditions 5 | # are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # 10 | # * Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in 12 | # the documentation and/or other materials provided with the 13 | # distribution. 14 | # 15 | # * Neither the name of Intel Corporation nor the names of its 16 | # contributors may be used to endorse or promote products derived 17 | # from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | # 32 | # Makefile for util module 33 | # 34 | OBJS = util.o 35 | 36 | all: 37 | 38 | util.o: util.h 39 | 40 | clean: 41 | rm -f *.o core a.out 42 | 43 | clobber: clean 44 | 45 | test: 46 | # no util unit test 47 | @echo PASS 48 | 49 | .PHONY: all clean clobber test 50 | -------------------------------------------------------------------------------- /util/README: -------------------------------------------------------------------------------- 1 | This is util/README. 2 | 3 | These are not the examples you're looking for. 4 | 5 | This directory just contains common routines for printing errors 6 | and debug information. Nothing particularly interesting here 7 | and nothing to do with Persistent Memory. Check out ../README 8 | to see which directories contain the examples. 9 | 10 | To use these routines, include util.h and compile util.c into 11 | your program. These are trivial to write, but they turn up 12 | again and again so they're here when you need them. They are: 13 | 14 | DEBUG(...) printf-like output to stderr, but only if 15 | the global flag Debug is non-zero The output 16 | includes file:line, name of function, and 17 | gets a newline appended. You can use DEBUG(NULL) 18 | to just trace that a line was executed. 19 | 20 | int Debug = 1; Put this at the top of one of your source files 21 | to turn on the DEBUG() statements mentioned above. 22 | 23 | FATAL(...) printf-like output to stderr with no return -- 24 | just like DEBUG() above but then this function 25 | calls exit(1). 26 | 27 | FATALSYS(...) Same as FATAL() above, but the message contains 28 | the equivalent of perror() appended to it. 29 | 30 | USAGE(...) Prints to stderr "Usage: " followed by 31 | the argument format from taken from the global 32 | variable Usage, followed by any printf-like message 33 | given as arguments to USAGE(). Calls exit(1). 34 | 35 | char Usage[] = Put this at the top of one of your source files 36 | "args..."; so USAGE() knows how to print the argument format. 37 | 38 | Myname = argv[0]; Put this at the top of your main() so USAGE() 39 | knows what name to print. 40 | 41 | ASSERT(cnd); Assert that condition is true, turns into FATAL() 42 | if it isn't. Prints the condition on failure. 43 | 44 | ASSERTinfo(cnd, info); Same as ASSERT() above, except it also includes 45 | the additional information (info must be a string). 46 | 47 | ASSERTeq(lhs, rhs); Assert two integer-valued expressions are equal, 48 | if not calls FATAL() to print both expressions 49 | and their values. Handy for printing everything you 50 | need to work on a blown assertion without having 51 | to wish you had printed the values. 52 | 53 | ASSERTne(lhs, rhs); Assert two integer-valued expressions are not equal. 54 | -------------------------------------------------------------------------------- /util/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * util.c -- some simple utility routines 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "util.h" 46 | 47 | /* 48 | * debug -- printf-like debug messages 49 | */ 50 | void 51 | debug(const char *file, int line, const char *func, const char *fmt, ...) 52 | { 53 | va_list ap; 54 | int save_errno; 55 | 56 | if (!Debug) 57 | return; 58 | 59 | save_errno = errno; 60 | 61 | fprintf(stderr, "debug: %s:%d %s()", file, line, func); 62 | if (fmt) { 63 | fprintf(stderr, ": "); 64 | va_start(ap, fmt); 65 | vfprintf(stderr, fmt, ap); 66 | va_end(ap); 67 | } 68 | fprintf(stderr, "\n"); 69 | errno = save_errno; 70 | } 71 | 72 | /* 73 | * fatal -- printf-like error exits, with and without errno printing 74 | */ 75 | void 76 | fatal(int err, const char *file, int line, const char *func, 77 | const char *fmt, ...) 78 | { 79 | va_list ap; 80 | 81 | fprintf(stderr, "ERROR: %s:%d %s()", file, line, func); 82 | if (fmt) { 83 | fprintf(stderr, ": "); 84 | va_start(ap, fmt); 85 | vfprintf(stderr, fmt, ap); 86 | va_end(ap); 87 | } 88 | if (err) 89 | fprintf(stderr, ": %s", strerror(err)); 90 | fprintf(stderr, "\n"); 91 | exit(1); 92 | } 93 | 94 | /* 95 | * exename -- figure out the name used to run this program 96 | * 97 | * Internal -- used by usage(). 98 | */ 99 | static const char * 100 | exename(void) 101 | { 102 | char proc[PATH_MAX]; 103 | static char exename[PATH_MAX]; 104 | int nbytes; 105 | 106 | snprintf(proc, PATH_MAX, "/proc/%d/exe", getpid()); 107 | if ((nbytes = readlink(proc, exename, PATH_MAX)) < 0) 108 | strcpy(exename, "Unknown"); 109 | else 110 | exename[nbytes] = '\0'; 111 | 112 | return exename; 113 | } 114 | 115 | /* 116 | * usage -- printf-like usage message emitter 117 | */ 118 | void 119 | usage(const char *argfmt, const char *fmt, ...) 120 | { 121 | va_list ap; 122 | 123 | fprintf(stderr, "Usage: %s", (Myname == NULL) ? exename() : Myname); 124 | if (argfmt) 125 | fprintf(stderr, " %s", argfmt); 126 | if (fmt) { 127 | fprintf(stderr, ": "); 128 | va_start(ap, fmt); 129 | vfprintf(stderr, fmt, ap); 130 | va_end(ap); 131 | } 132 | fprintf(stderr, "\n"); 133 | exit(1); 134 | } 135 | -------------------------------------------------------------------------------- /util/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, Intel Corporation 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in 13 | * the documentation and/or other materials provided with the 14 | * distribution. 15 | * 16 | * * Neither the name of Intel Corporation nor the names of its 17 | * contributors may be used to endorse or promote products derived 18 | * from this software without specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* 34 | * util.h -- global defines for util module 35 | */ 36 | 37 | #include 38 | 39 | int Debug; 40 | const char *Myname; 41 | 42 | #define DEBUG(...)\ 43 | debug(__FILE__, __LINE__, __func__, __VA_ARGS__) 44 | #define FATALSYS(...)\ 45 | fatal(errno, __FILE__, __LINE__, __func__, __VA_ARGS__) 46 | #define FATAL(...)\ 47 | fatal(0, __FILE__, __LINE__, __func__, __VA_ARGS__) 48 | #define USAGE(...)\ 49 | usage(Usage, __VA_ARGS__) 50 | 51 | /* assert a condition is true */ 52 | #define ASSERT(cnd)\ 53 | ((void)((cnd) || (fatal(0, __FILE__, __LINE__, __func__,\ 54 | "assertion failure: %s", #cnd), 0))) 55 | 56 | /* assertion with extra info printed if assertion fails */ 57 | #define ASSERTinfo(cnd, info) \ 58 | ((void)((cnd) || (fatal(0, __FILE__, __LINE__, __func__,\ 59 | "assertion failure: %s (%s = %s)", #cnd, #info, info), 0))) 60 | 61 | /* assert two integer values are equal */ 62 | #define ASSERTeq(lhs, rhs)\ 63 | ((void)(((lhs) == (rhs)) || (fatal(0, __FILE__, __LINE__, __func__,\ 64 | "assertion failure: %s (%d) == %s (%d)", #lhs,\ 65 | (lhs), #rhs, (rhs)), 0))) 66 | 67 | /* assert two integer values are not equal */ 68 | #define ASSERTne(lhs, rhs)\ 69 | ((void)(((lhs) != (rhs)) || (fatal(0, __FILE__, __LINE__, __func__,\ 70 | "assertion failure: %s (%d) != %s (%d)", #lhs,\ 71 | (lhs), #rhs, (rhs)), 0))) 72 | 73 | void debug(const char *file, int line, const char *func, 74 | const char *fmt, ...); 75 | void fatal(int err, const char *file, int line, const char *func, 76 | const char *fmt, ...); 77 | void usage(const char *argfmt, const char *fmt, ...); 78 | --------------------------------------------------------------------------------