diff --git a/src/test/Makefile b/src/test/Makefile index 575d83f1f02cf4f32090da257c7024f49a273b06..220341883419638920fd6bb00dfa41e47cd7c579 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2014-2018, Intel Corporation +# Copyright 2014-2019, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -306,6 +306,7 @@ DAXIO_TESTS = \ daxio PMREORDER_TESTS = \ + pmreorder_flushes\ pmreorder_simple\ pmreorder_stack diff --git a/src/test/pmreorder_flushes/.gitignore b/src/test/pmreorder_flushes/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..bf4997a9e95a297641dbd18f7de4880dfc11e603 --- /dev/null +++ b/src/test/pmreorder_flushes/.gitignore @@ -0,0 +1 @@ +pmreorder_flushes diff --git a/src/test/pmreorder_flushes/Makefile b/src/test/pmreorder_flushes/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..41e84025211cbb4b638c44bad6cafbdbc5b8730c --- /dev/null +++ b/src/test/pmreorder_flushes/Makefile @@ -0,0 +1,43 @@ +# +# Copyright 2019, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# src/test/pmreorder_flushes/Makefile -- build pmreorder_flushes test +# + +TARGET = pmreorder_flushes +OBJS = pmreorder_flushes.o + +LIBPMEM=y +LIBPMEMCOMMON=y + +include ../Makefile.inc diff --git a/src/test/pmreorder_flushes/TEST0 b/src/test/pmreorder_flushes/TEST0 new file mode 100755 index 0000000000000000000000000000000000000000..c004c942ef32fef9643dc40adb9447f6c2562938 --- /dev/null +++ b/src/test/pmreorder_flushes/TEST0 @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# +# Copyright 2019, Intel Corporation +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +# +# src/test/pmreorder_flushes/TEST0 -- test for the reordering script +# Tests positive case using no reorder engine. Checks if once flushed +# variable can be overwrite in the next barrier and then persisted properly. +# + +# standard unit test setup +. ../unittest/unittest.sh + +require_fs_type pmem non-pmem +require_build_type debug +require_test_type medium +require_pmemcheck_version_ge 1 0 +require_pmemcheck_version_lt 2 0 +require_pmreorder + +setup + +export PMREORDER_EMIT_LOG=1 + +# create holey file +truncate -s 4M $DIR/testfile + +LOG_FILE=./pmreorder_flushes${UNITTEST_NUM}.log +touch $LOG_FILE + +BIN="./pmreorder_flushes$EXESUFFIX" +PMEMCHECK_CMD="$BIN g $DIR/testfile $LOG_FILE" +PMREORDER_CMD="$BIN c $DIR/testfile $LOG_FILE" + +pmreorder_create_store_log $DIR/testfile "$PMEMCHECK_CMD" +pmreorder_expect_success NoReorderDoCheck "DO_NOT_CHECK_E=NoReorderNoCheck" "$PMREORDER_CMD" + +check + +pass diff --git a/src/test/pmreorder_flushes/pmreorder_flushes.c b/src/test/pmreorder_flushes/pmreorder_flushes.c new file mode 100644 index 0000000000000000000000000000000000000000..5ba3b5ce44ce5bef5b61c81f8e2c1d7513fb1833 --- /dev/null +++ b/src/test/pmreorder_flushes/pmreorder_flushes.c @@ -0,0 +1,172 @@ +/* + * Copyright 2019, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * pmreorder_flushes.c -- test for store reordering with flushes + * in different barriers + * + * usage: pmreorder_flushes g|c file + * + * g - write data in a specific manner - some flushes + * of the stores are made in diffrent barriers, + * c - check data consistency - stores should be applied only + * after flush - no matter in which barrier the flush will happen + * + */ + +#include "unittest.h" +#include "util.h" +#include "valgrind_internal.h" + +#define STORE_SIZE 64 +static FILE *fp; + +struct stores_fields { + char A[STORE_SIZE]; + char B[STORE_SIZE]; + char C[STORE_SIZE]; + char D[STORE_SIZE]; + char E[STORE_SIZE]; +}; + +/* + * write_consistent -- (internal) write data in a specific order + */ +static void +write_consistent(struct stores_fields *sf) +{ + /* + * STORE (A) + * STORE (B) + * STORE (C) + * + * FLUSH (A, B) (no flush C) + * FENCE + */ + pmem_memset(&sf->A, -1, sizeof(sf->A), PMEM_F_MEM_NODRAIN); + pmem_memset(&sf->B, 2, sizeof(sf->B), PMEM_F_MEM_NODRAIN); + pmem_memset(&sf->C, 3, sizeof(sf->C), PMEM_F_MEM_NOFLUSH); + pmem_drain(); + + /* + * STORE (A) + * STORE (D) + * + * FLUSH (D) (no flush A, still no flush C) + * FENCE + */ + pmem_memset(sf->A, 1, sizeof(sf->A), PMEM_F_MEM_NOFLUSH); + pmem_memset(sf->D, 4, sizeof(sf->D), PMEM_F_MEM_NODRAIN); + pmem_drain(); + + /* + * STORE (D) + * + * FLUSH (C, D) (still no flush A) + * FENCE + */ + pmem_memset(sf->D, 5, sizeof(sf->D), PMEM_F_MEM_NODRAIN); + pmem_flush(sf->C, sizeof(sf->C)); + pmem_drain(); + + /* + * STORE (E) to verify if A will be finally persisted + * FLUSH (E) + * FENCE + */ + pmem_memset(sf->E, 6, sizeof(sf->E), PMEM_F_MEM_NODRAIN); + pmem_drain(); + + /* + * FLUSH (A) + * FENCE + */ + pmem_flush(sf->A, sizeof(sf->A)); + pmem_drain(); +} + +/* + * check_consistency -- (internal) check if stores are made in proper manner + */ +static int +check_consistency(struct stores_fields *sf) +{ + fprintf(fp, "A=%d B=%d C=%d D=%d E=%d\n", + sf->A[0], sf->B[0], sf->C[0], sf->D[0], sf->E[0]); + return 0; +} + +int +main(int argc, char *argv[]) +{ + START(argc, argv, "pmreorder_flushes"); + + util_init(); + + if ((argc < 4) || (strchr("gc", argv[1][0]) == NULL) || + argv[1][1] != '\0') + UT_FATAL("usage: %s g|c file log_file", argv[0]); + + int fd = OPEN(argv[2], O_RDWR); + size_t size; + /* mmap and register in valgrind pmemcheck */ + void *map = pmem_map_file(argv[2], 0, 0, 0, &size, NULL); + UT_ASSERTne(map, NULL); + + struct stores_fields *sf = map; + + char opt = argv[1][0]; + + /* clear the struct to get a consistent start state for writing */ + if (strchr("g", opt)) + pmem_memset_persist(sf, 0, sizeof(*sf)); + + switch (opt) { + case 'g': + write_consistent(sf); + break; + case 'c': + fp = fopen(argv[3], "a"); + if (fp == NULL) + UT_FATAL("!fopen"); + int ret; + ret = check_consistency(sf); + fclose(fp); + return ret; + default: + UT_FATAL("Unrecognized option %c", opt); + } + + CLOSE(fd); + + DONE(NULL); +} diff --git a/src/test/pmreorder_flushes/pmreorder_flushes0.log.match b/src/test/pmreorder_flushes/pmreorder_flushes0.log.match new file mode 100644 index 0000000000000000000000000000000000000000..86b81736be187bdb0a55429d60aa3b91fe102c3d --- /dev/null +++ b/src/test/pmreorder_flushes/pmreorder_flushes0.log.match @@ -0,0 +1,6 @@ +A=0 B=0 C=0 D=0 E=0 +A=-1 B=2 C=0 D=0 E=0 +A=-1 B=2 C=0 D=4 E=0 +A=-1 B=2 C=3 D=5 E=0 +A=-1 B=2 C=3 D=5 E=6 +A=1 B=2 C=3 D=5 E=6 diff --git a/src/tools/pmreorder/statemachine.py b/src/tools/pmreorder/statemachine.py index e819994c84b41999fb6018dcea249bba1270e4c3..39b84de4c2501da5dfa49e99102b4f2f9b5f239b 100644 --- a/src/tools/pmreorder/statemachine.py +++ b/src/tools/pmreorder/statemachine.py @@ -1,4 +1,4 @@ -# Copyright 2018, Intel Corporation +# Copyright 2018-2019, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -40,7 +40,11 @@ class State: :ivar _context: The reordering context. :type _context: opscontext.OpsContext + :ivar trans_stores: The list of unflushed stores. + :type trans_stores: list of :class:`memoryoperations.Store` """ + trans_stores = [] + def __init__(self, context): """ Default state constructor. @@ -130,6 +134,7 @@ class CollectingState(State): """ super(CollectingState, self).__init__(context) self._ops_list = [] + self._ops_list += State.trans_stores self._inner_state = "init" def next(self, in_op): @@ -268,6 +273,9 @@ class CollectingState(State): elif isinstance(in_op, memops.Fence) and \ self._inner_state is "flush": self._inner_state = "fence" + elif isinstance(in_op, memops.Flush) and \ + self._inner_state is "init": + self._inner_state = "flush" class ReplayingState(State): @@ -312,8 +320,19 @@ class ReplayingState(State): """ # specifies consistency state of sequence consistency = True + # consider only flushed stores flushed_stores = list(filter(lambda x: x.flushed, self._ops_list)) + + # already flushed stores should be removed from the transitive list + common_part = list(set(flushed_stores) & set(State.trans_stores)) + State.trans_stores = list(set(State.trans_stores) - set(common_part)) + + # do not add redundant stores + State.trans_stores = list(set(State.trans_stores) | + set(list(filter(lambda x: x.flushed is False, + self._ops_list)))) + if self._context.test_on_barrier: for seq in self._context.reorder_engine.generate_sequence( flushed_stores):