diff --git a/src/PMDK.sln b/src/PMDK.sln index b35594d61d2f88b1d83921563ff945b7ce70785a..18f14b72e928f72893bccf4d24669de70a04930b 100644 --- a/src/PMDK.sln +++ b/src/PMDK.sln @@ -538,6 +538,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_include", "test\obj_inc EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpmempool_sync", "test\libpmempool_sync\libpmempool_sync.vcxproj", "{AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_defrag_advanced", "test\obj_defrag_advanced\obj_defrag_advanced.vcxproj", "{AE952763-5C84-43FC-B344-CACC950F056C}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "signal_handle", "test\signal_handle\signal_handle.vcxproj", "{AE9E908D-BAEC-491F-9914-436B3CE35E94}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obj_ctl_config", "test\obj_ctl_config\obj_ctl_config.vcxproj", "{AEAA72CD-E060-417C-9CA1-49B4738384E0}" @@ -1416,6 +1418,10 @@ Global {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Debug|x64.Build.0 = Debug|x64 {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Release|x64.ActiveCfg = Release|x64 {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8}.Release|x64.Build.0 = Release|x64 + {AE952763-5C84-43FC-B344-CACC950F056C}.Debug|x64.ActiveCfg = Debug|x64 + {AE952763-5C84-43FC-B344-CACC950F056C}.Debug|x64.Build.0 = Debug|x64 + {AE952763-5C84-43FC-B344-CACC950F056C}.Release|x64.ActiveCfg = Release|x64 + {AE952763-5C84-43FC-B344-CACC950F056C}.Release|x64.Build.0 = Release|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Debug|x64.ActiveCfg = Debug|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Debug|x64.Build.0 = Debug|x64 {AE9E908D-BAEC-491F-9914-436B3CE35E94}.Release|x64.ActiveCfg = Release|x64 @@ -1926,6 +1932,7 @@ Global {A7CA7975-CEDB-48E6-9AEB-1209DCBD07F2} = {91C30620-70CA-46C7-AC71-71F3C602690E} {AB15A115-E429-4123-BEBF-206FBA4CF615} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {AE1C32FB-9B52-4760-ABFC-0D2FA2C7A6C8} = {2F543422-4B8A-4898-BE6B-590F52B4E9D1} + {AE952763-5C84-43FC-B344-CACC950F056C} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {AE9E908D-BAEC-491F-9914-436B3CE35E94} = {B870D8A6-12CD-4DD0-B843-833695C2310A} {AEAA72CD-E060-417C-9CA1-49B4738384E0} = {63C9B3F8-437D-4AD9-B32D-D04AE38C35B6} {AF038868-2432-4159-A62F-941F11D12C5D} = {59AB6976-D16B-48D0-8D16-94360D3FE51D} diff --git a/src/test/Makefile b/src/test/Makefile index 7911541a7a015053ce368ae742eec8be367afa14..a4aaab44a29cd21b601312924e9c4f27bc432308 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,5 +1,5 @@ # -# Copyright 2014-2019, Intel Corporation +# Copyright 2014-2020, Intel Corporation # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -88,6 +88,7 @@ OBJ_TESTS = \ obj_ctl_stats\ obj_debug\ obj_defrag\ + obj_defrag_advanced\ obj_direct\ obj_direct_volatile\ obj_extend\ diff --git a/src/test/obj_defrag_advanced/.gitignore b/src/test/obj_defrag_advanced/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..55413109ceadc4e20192f558c06c425488b8cf3b --- /dev/null +++ b/src/test/obj_defrag_advanced/.gitignore @@ -0,0 +1 @@ +obj_defrag_advanced diff --git a/src/test/obj_defrag_advanced/Makefile b/src/test/obj_defrag_advanced/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f2e8eda94bf761a84a119d58b963abcdcedeefdf --- /dev/null +++ b/src/test/obj_defrag_advanced/Makefile @@ -0,0 +1,43 @@ +# +# Copyright 2020, 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/obj_defrag_advanced/Makefile -- build obj_defrag_advanced test +# +TARGET = obj_defrag_advanced +OBJS = vgraph.o pgraph.o obj_defrag_advanced.o + +LIBPMEMOBJ=y + +include ../Makefile.inc + +CFLAGS += -DDEBUG diff --git a/src/test/obj_defrag_advanced/TESTS.py b/src/test/obj_defrag_advanced/TESTS.py new file mode 100755 index 0000000000000000000000000000000000000000..8846f119b71b22fb1a313470c27a8f802ad23464 --- /dev/null +++ b/src/test/obj_defrag_advanced/TESTS.py @@ -0,0 +1,136 @@ +#!../env.py +# +# Copyright 2020, 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. +# + +import testframework as t + + +class ObjDefragAdvanced(t.BaseTest): + test_type = t.Short + + max_nodes = 50 + max_edges = 10 + graph_copies = 10 + pool_size = 500 * t.MiB + max_rounds = 10 + min_root_size = 0 + + def run(self, ctx): + path = ctx.create_holey_file(self.pool_size, 'testfile') + dump1 = 'dump1.log' + dump2 = 'dump2.log' + + ctx.exec('obj_defrag_advanced', + 'op_pool_create', path, + 'op_graph_create', str(self.max_nodes), str(self.max_edges), + str(self.graph_copies), str(self.min_root_size), + 'op_graph_dump', dump1, + 'op_graph_defrag', str(self.max_rounds), + 'op_graph_dump', dump2, + 'op_pool_close', + 'op_dump_compare', dump1, dump2) + + +class TEST0(ObjDefragAdvanced): + max_nodes = 5 + max_edges = 5 + graph_copies = 5 + + +class TEST1(ObjDefragAdvanced): + max_nodes = 2048 + max_edges = 5 + graph_copies = 5 + + +class TEST2(ObjDefragAdvanced): + test_type = t.Medium + fs = t.Pmem + + max_nodes = 512 + max_edges = 64 + graph_copies = 5 + min_root_size = 4096 + + +class ObjDefragAdvancedMt(ObjDefragAdvanced): + test_type = t.Medium + fs = t.Pmem + + nthreads = 2 + ncycles = 2 + + def run(self, ctx): + path = ctx.create_holey_file(self.pool_size, 'testfile') + + ctx.exec('obj_defrag_advanced', + 'op_pool_create', path, + 'op_graph_create_n_defrag_mt', str(self.max_nodes), str(self.max_edges), + str(self.graph_copies), str(self.min_root_size), str(self.max_rounds), + str(self.nthreads), str(self.ncycles), + 'op_pool_close'); + + +class TEST3(ObjDefragAdvancedMt): + max_nodes = 256 + max_edges = 64 + graph_copies = 10 + nthreads = 1 + ncycles = 25 + + +class TEST4(ObjDefragAdvancedMt): + max_nodes = 128 + max_edges = 32 + graph_copies = 10 + nthreads = 10 + ncycles = 25 + + +class TEST5(ObjDefragAdvancedMt): + max_nodes = 256 + max_edges = 32 + graph_copies = 5 + nthreads = 10 + ncycles = 25 + + +# a testcase designed to verify the pool content in case of fail +# class TESTX(ObjDefragAdvanced): +# def run(self, ctx): +# path = '/custom/pool/path' +# dump_prefix = 'dump' +# +# ctx.exec('obj_defrag_advanced', +# 'op_pool_open', path, +# 'op_graph_dump_all', dump_prefix, +# 'op_pool_close') diff --git a/src/test/obj_defrag_advanced/obj_defrag_advanced.c b/src/test/obj_defrag_advanced/obj_defrag_advanced.c new file mode 100644 index 0000000000000000000000000000000000000000..7dc42161998e87b58aec492712b982df18d930dc --- /dev/null +++ b/src/test/obj_defrag_advanced/obj_defrag_advanced.c @@ -0,0 +1,595 @@ +/* + * Copyright 2020, 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. + */ + +/* + * obj_defrag_advanced.c -- test for libpmemobj defragmentation feature + */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <stddef.h> +#include <unistd.h> +#include <stdlib.h> + +#include "rand.h" +#include "vgraph.h" +#include "pgraph.h" +#include "os_thread.h" +#include "unittest.h" + +struct create_params_t { + uint64_t seed; + rng_t rng; + + struct vgraph_params vparams; + struct pgraph_params pparams; +}; + +/* + * graph_create -- create a graph + * - generate an intermediate volatile graph representation + * - use the volatile graph to allocate a persistent one + */ +static void +graph_create(struct create_params_t *task, PMEMobjpool *pop, PMEMoid *oidp, + rng_t *rngp) +{ + struct vgraph_t *vgraph = vgraph_new(&task->vparams, rngp); + pgraph_new(pop, oidp, vgraph, &task->pparams, rngp); + vgraph_delete(vgraph); +} + +/* + * graph_defrag -- defragment the pool + * - collect pointers to all PMEMoids + * - do a sanity checks + * - call pmemobj_defrag + * - return # of relocated objects + */ +static size_t +graph_defrag(PMEMobjpool *pop, PMEMoid oid) +{ + struct pgraph_t *pgraph = (struct pgraph_t *)pmemobj_direct(oid); + + /* count number of oids */ + unsigned oidcnt = pgraph->nodes_num; + for (unsigned i = 0; i < pgraph->nodes_num; ++i) { + struct pnode_t *pnode = (struct pnode_t *)pmemobj_direct + (pgraph->nodes[i]); + oidcnt += pnode->edges_num; + } + + /* create array of oid pointers */ + PMEMoid **oidv = (PMEMoid **)MALLOC(sizeof(PMEMoid *) * oidcnt); + unsigned oidi = 0; + for (unsigned i = 0; i < pgraph->nodes_num; ++i) { + oidv[oidi++] = &pgraph->nodes[i]; + + struct pnode_t *pnode = (struct pnode_t *)pmemobj_direct + (pgraph->nodes[i]); + for (unsigned j = 0; j < pnode->edges_num; ++j) { + oidv[oidi++] = &pnode->edges[j]; + } + } + + UT_ASSERTeq(oidi, oidcnt); + + /* check if all oids are valid */ + for (unsigned i = 0; i < oidcnt; ++i) { + void *ptr = pmemobj_direct(*oidv[i]); + UT_ASSERTne(ptr, NULL); + } + + /* check if all oids appear only once */ + for (unsigned i = 0; i < oidcnt - 1; ++i) { + for (unsigned j = i + 1; j < oidcnt; ++j) { + UT_ASSERTne(oidv[i], oidv[j]); + } + } + + struct pobj_defrag_result result; + int ret = pmemobj_defrag(pop, oidv, oidcnt, &result); + UT_ASSERTeq(ret, 0); + UT_ASSERTeq(result.total, pgraph->nodes_num); + + FREE(oidv); + + return result.relocated; +} + +/* + * graph_defrag_ntimes -- defragment the graph N times + * - where N <= max_rounds + * - it stops defrag if # of relocated objects == 0 + */ +static void +graph_defrag_ntimes(PMEMobjpool *pop, PMEMoid oid, unsigned max_rounds) +{ + size_t relocated; + unsigned rounds = 0; + do { + relocated = graph_defrag(pop, oid); + ++rounds; + } while (relocated > 0 && rounds < max_rounds); + + UT_OUT("# of defragmentation rounds: %u", rounds); +} + +#define HAS_TO_EXIST (1) + +/* + * graph_dump -- dump a graph from the pool to a text file + */ +static void +graph_dump(PMEMoid oid, const char *path, int has_exist) +{ + struct pgraph_t *pgraph = (struct pgraph_t *)pmemobj_direct(oid); + if (has_exist) + UT_ASSERTne(pgraph, NULL); + + if (pgraph) + pgraph_print(pgraph, path); +} + +#define FGETS_BUFF_LEN 1024 + +/* + * dump_compare -- compare graph dumps + * Test fails if the contents of dumps do not match + */ +static void +dump_compare(const char *path1, const char *path2) +{ + FILE *dump1 = FOPEN(path1, "r"); + FILE *dump2 = FOPEN(path2, "r"); + + char buff1[FGETS_BUFF_LEN]; + char buff2[FGETS_BUFF_LEN]; + char *sret1, *sret2; + + do { + sret1 = fgets(buff1, FGETS_BUFF_LEN, dump1); + sret2 = fgets(buff2, FGETS_BUFF_LEN, dump2); + + /* both files have to end at the same time */ + if (!sret1) { + UT_ASSERTeq(sret2, NULL); + + FCLOSE(dump1); + FCLOSE(dump2); + + return; + } + + UT_ASSERTeq(sret1, buff1); + UT_ASSERTeq(sret2, buff2); + + UT_ASSERTeq(strcmp(buff1, buff2), 0); + } while (1); +} + +/* + * create_params_init -- initialize create params + */ +static void +create_params_init(struct create_params_t *params) +{ + params->seed = 1; + + /* good enough defaults - no magic here */ + params->vparams.max_nodes = 50; + params->vparams.max_edges = 10; + params->vparams.range_nodes = 10; + params->vparams.range_edges = 10; + params->vparams.min_pattern_size = 8; + params->vparams.max_pattern_size = 1024; + + params->pparams.graph_copies = 10; +} + +/* global state */ +static struct global_t { + PMEMobjpool *pop; +} global; + +/* + * PMEMobj root object structure + */ +struct root_t { + unsigned graphs_num; + PMEMoid graphs[]; +}; + +/* + * root_size -- calculate a root object size + */ +static inline size_t +root_size(unsigned graph_num, size_t min_root_size) +{ + size_t size = sizeof(struct root_t) + sizeof(PMEMoid) * graph_num; + return MAX(size, min_root_size); +} + +#define QUERY_GRAPHS_NUM UINT_MAX + +static struct root_t * +get_root(unsigned graphs_num, size_t min_root_size) +{ + PMEMoid roid; + struct root_t *root; + + if (graphs_num == QUERY_GRAPHS_NUM) { + /* allocate a root object without graphs */ + roid = pmemobj_root(global.pop, root_size(0, 0)); + if (OID_IS_NULL(roid)) + UT_FATAL("!pmemobj_root:"); + root = (struct root_t *)pmemobj_direct(roid); + UT_ASSERTne(root, NULL); + + graphs_num = root->graphs_num; + } + + UT_ASSERT(graphs_num > 0); + + /* reallocate a root object with all known graphs */ + roid = pmemobj_root(global.pop, root_size(graphs_num, min_root_size)); + if (OID_IS_NULL(roid)) + UT_FATAL("!pmemobj_root:"); + root = (struct root_t *)pmemobj_direct(roid); + UT_ASSERTne(root, NULL); + + return root; +} + +/* + * parse_nonzero -- parse non-zero unsigned + */ +static void +parse_nonzero(unsigned *var, const char *arg) +{ + unsigned long v = STRTOUL(arg, NULL, 10); + UT_ASSERTne(v, 0); + UT_ASSERT(v < UINT_MAX); + + *var = v; +} + +#define GRAPH_LAYOUT POBJ_LAYOUT_NAME(graph) + +/* + * op_pool_create -- create a pool + */ +static int +op_pool_create(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: %s <path>", tc->name); + + /* parse arguments */ + const char *path = argv[0]; + + /* open a pool */ + global.pop = pmemobj_create(path, GRAPH_LAYOUT, 0, S_IWUSR | S_IRUSR); + if (global.pop == NULL) { + UT_FATAL("!pmemobj_create: %s", path); + } + + return 1; +} + +/* + * op_pool_close -- close the poll + */ +static int +op_pool_close(const struct test_case *tc, int argc, char *argv[]) +{ + pmemobj_close(global.pop); + global.pop = NULL; + + return 0; +} + +/* + * op_graph_create -- create a graph + */ +static int +op_graph_create(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 4) + UT_FATAL("usage: %s <max-nodes> <max-edges> <graph-copies>" + " <min-root-size>", tc->name); + + /* parse arguments */ + struct create_params_t cparams; + create_params_init(&cparams); + parse_nonzero(&cparams.vparams.max_nodes, argv[0]); + parse_nonzero(&cparams.vparams.max_edges, argv[1]); + parse_nonzero(&cparams.pparams.graph_copies, argv[2]); + size_t min_root_size = STRTOULL(argv[3], NULL, 10); + + struct root_t *root = get_root(1, min_root_size); + + randomize(cparams.seed); + + /* generate a single graph */ + graph_create(&cparams, global.pop, &root->graphs[0], NULL); + root->graphs_num = 1; + pmemobj_persist(global.pop, root, root_size(1, min_root_size)); + + return 4; +} + +/* + * op_graph_dump -- dump the graph + */ +static int +op_graph_dump(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: %s <dump>", tc->name); + + /* parse arguments */ + const char *dump = argv[0]; + + struct root_t *root = get_root(QUERY_GRAPHS_NUM, 0); + UT_ASSERTeq(root->graphs_num, 1); + + /* dump the graph before defrag */ + graph_dump(root->graphs[0], dump, HAS_TO_EXIST); + + return 1; +} + +/* + * op_graph_defrag -- defrag the graph + */ +static int +op_graph_defrag(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: %s <max-rounds>", tc->name); + + /* parse arguments */ + unsigned max_rounds; + parse_nonzero(&max_rounds, argv[0]); + + struct root_t *root = get_root(QUERY_GRAPHS_NUM, 0); + UT_ASSERTeq(root->graphs_num, 1); + + /* do the defrag */ + graph_defrag_ntimes(global.pop, root->graphs[0], max_rounds); + + return 1; +} + +/* + * op_dump_compare -- compare dumps + */ +static int +op_dump_compare(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 2) + UT_FATAL("usage: %s <dump1> <dump2>", tc->name); + + /* parse arguments */ + const char *dump1 = argv[0]; + const char *dump2 = argv[1]; + + dump_compare(dump1, dump2); + + return 2; +} + +struct create_n_defrag_params_t { + unsigned thread_id; + + struct create_params_t cparams; + + PMEMobjpool *pop; + PMEMoid *oidp; + + unsigned max_rounds; + unsigned ncycles; +}; + +/* + * create_n_defrag_thread -- create and defrag graphs mutiple times + */ +static void * +create_n_defrag_thread(void *arg) +{ + struct create_n_defrag_params_t *params = + (struct create_n_defrag_params_t *)arg; + + char dump1[PATH_MAX]; + char dump2[PATH_MAX]; + + snprintf(dump1, PATH_MAX, "dump_t%u_1.log", params->thread_id); + snprintf(dump2, PATH_MAX, "dump_t%u_2.log", params->thread_id); + + struct create_params_t *cparams = ¶ms->cparams; + + for (unsigned i = 0; i < params->ncycles; ++i) { + graph_create(cparams, global.pop, params->oidp, &cparams->rng); + graph_dump(*params->oidp, dump1, HAS_TO_EXIST); + + graph_defrag_ntimes(params->pop, *params->oidp, + params->max_rounds); + graph_dump(*params->oidp, dump2, HAS_TO_EXIST); + + dump_compare(dump1, dump2); + + pgraph_delete(params->oidp); + } + + return NULL; +} + +/* + * op_graph_create_n_defrag_mt -- multi-threaded graphs creation & defrag + */ +static int +op_graph_create_n_defrag_mt(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 7) + UT_FATAL("usage: %s <max-nodes> <max-edges> <graph-copies>" + " <min-root-size> <max-defrag-rounds> <n-threads>" + "<n-create-defrag-cycles>", tc->name); + + /* parse arguments */ + struct create_params_t cparams; + create_params_init(&cparams); + parse_nonzero(&cparams.vparams.max_nodes, argv[0]); + parse_nonzero(&cparams.vparams.max_edges, argv[1]); + parse_nonzero(&cparams.pparams.graph_copies, argv[2]); + size_t min_root_size = STRTOULL(argv[3], NULL, 10); + unsigned max_rounds; + parse_nonzero(&max_rounds, argv[4]); + unsigned nthreads; + parse_nonzero(&nthreads, argv[5]); + unsigned ncycles; + parse_nonzero(&ncycles, argv[6]); + + struct root_t *root = get_root(nthreads, min_root_size); + root->graphs_num = nthreads; + pmemobj_persist(global.pop, root, sizeof(*root)); + + /* prepare threads params */ + struct create_n_defrag_params_t *paramss = + (struct create_n_defrag_params_t *)MALLOC( + sizeof(*paramss) * nthreads); + + for (unsigned i = 0; i < nthreads; ++i) { + struct create_n_defrag_params_t *params = ¶mss[i]; + + params->thread_id = i; + memcpy(¶ms->cparams, &cparams, sizeof(cparams)); + params->cparams.seed += i; + randomize_r(¶ms->cparams.rng, params->cparams.seed); + params->pop = global.pop; + params->oidp = &root->graphs[i]; + params->max_rounds = max_rounds; + params->ncycles = ncycles; + } + + /* spawn threads */ + os_thread_t *threads = (os_thread_t *)MALLOC( + sizeof(*threads) * nthreads); + for (unsigned i = 0; i < nthreads; ++i) + os_thread_create(&threads[i], NULL, create_n_defrag_thread, + ¶mss[i]); + + /* join all threads */ + void *ret = NULL; + for (unsigned i = 0; i < nthreads; ++i) { + os_thread_join(&threads[i], &ret); + UT_ASSERTeq(ret, NULL); + } + + FREE(threads); + FREE(paramss); + + return 7; +} + +/* + * op_pool_open -- open the pool + */ +static int +op_pool_open(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: %s <path>", tc->name); + + /* parse arguments */ + const char *path = argv[0]; + + /* open a pool */ + global.pop = pmemobj_open(path, GRAPH_LAYOUT); + if (global.pop == NULL) + UT_FATAL("!pmemobj_create: %s", path); + + return 1; +} + +/* + * op_graph_dump_all -- dump all graphs + */ +static int +op_graph_dump_all(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: %s <dump-prefix>", tc->name); + + /* parse arguments */ + const char *dump_prefix = argv[0]; + + struct root_t *root = get_root(QUERY_GRAPHS_NUM, 0); + + char dump[PATH_MAX]; + for (unsigned i = 0; i < root->graphs_num; ++i) { + snprintf(dump, PATH_MAX, "%s_%u.log", dump_prefix, i); + graph_dump(root->graphs[i], dump, HAS_TO_EXIST); + } + + return 1; +} + +/* + * ops -- available ops + */ +static struct test_case ops[] = { + TEST_CASE(op_pool_create), + TEST_CASE(op_pool_close), + TEST_CASE(op_graph_create), + TEST_CASE(op_graph_dump), + TEST_CASE(op_graph_defrag), + TEST_CASE(op_dump_compare), + TEST_CASE(op_graph_create_n_defrag_mt), + + /* for pool validation only */ + TEST_CASE(op_pool_open), + TEST_CASE(op_graph_dump_all), +}; + +#define NOPS ARRAY_SIZE(ops) + +#define TEST_NAME "obj_defrag_advanced" + +int +main(int argc, char *argv[]) +{ + START(argc, argv, TEST_NAME); + TEST_CASE_PROCESS(argc, argv, ops, NOPS); + DONE(NULL); +} diff --git a/src/test/obj_defrag_advanced/obj_defrag_advanced.vcxproj b/src/test/obj_defrag_advanced/obj_defrag_advanced.vcxproj new file mode 100644 index 0000000000000000000000000000000000000000..48e76ed69c40701c6bd8da64366fdfc55222e9b0 --- /dev/null +++ b/src/test/obj_defrag_advanced/obj_defrag_advanced.vcxproj @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{AE952763-5C84-43FC-B344-CACC950F056C}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>obj_defrag_advanced</RootNamespace> + <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile /> + <Link /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile /> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\test_debug.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\test_release.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <Optimization>Disabled</Optimization> + </ClCompile> + <Link /> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>NotUsing</PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + </ClCompile> + <Link /> + </ItemDefinitionGroup> + <ItemGroup> + <ProjectReference Include="..\..\libpmemobj\libpmemobj.vcxproj"> + <Project>{1baa1617-93ae-4196-8a1a-bd492fb18aef}</Project> + </ProjectReference> + <ProjectReference Include="..\..\libpmem\libpmem.vcxproj"> + <Project>{9e9e3d25-2139-4a5d-9200-18148ddead45}</Project> + </ProjectReference> + <ProjectReference Include="..\..\windows\getopt\getopt.vcxproj"> + <Project>{9186eac4-2f34-4f17-b940-6585d7869bcd}</Project> + </ProjectReference> + <ProjectReference Include="..\unittest\libut.vcxproj"> + <Project>{ce3f2dfb-8470-4802-ad37-21caf6cb2681}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <None Include="TESTS.py" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="obj_defrag_advanced.c" /> + <ClCompile Include="pgraph.c" /> + <ClCompile Include="vgraph.c" /> + <ClCompile Include="..\..\common\rand.c" /> + <ClCompile Include="..\..\common\os_thread_windows.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pgraph.h" /> + <ClInclude Include="vgraph.h" /> + <ClInclude Include="..\..\common\os_thread.h" /> + <ClInclude Include="..\..\common\rand.h" /> + <ClInclude Include="..\unittest\unittest.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project> diff --git a/src/test/obj_defrag_advanced/obj_defrag_advanced.vcxproj.filters b/src/test/obj_defrag_advanced/obj_defrag_advanced.vcxproj.filters new file mode 100644 index 0000000000000000000000000000000000000000..5a2693130b3d0447ebeaff2672fe5edc1537cad7 --- /dev/null +++ b/src/test/obj_defrag_advanced/obj_defrag_advanced.vcxproj.filters @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <None Include="README" /> + <None Include="TESTS.py"> + <Filter>Test Scripts</Filter> + </None> + </ItemGroup> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{06b70714-04ff-4d74-8f1d-eb33a3318a3c}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{06b70714-04ff-4d74-8f1d-eb33a3318a3c}</UniqueIdentifier> + </Filter> + <Filter Include="Test Scripts"> + <UniqueIdentifier>{f6970093-c229-475a-a462-7718dc17b32e}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="obj_defrag_advanced.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pgraph.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="vgraph.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\common\rand.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\common\os_thread_windows.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="pgraph.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="vgraph.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\common\os_thread.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\..\common\rand.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="..\unittest\unittest.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project> \ No newline at end of file diff --git a/src/test/obj_defrag_advanced/pgraph.c b/src/test/obj_defrag_advanced/pgraph.c new file mode 100644 index 0000000000000000000000000000000000000000..e7a933ed030cf575c5cca9de123af19d0950a882 --- /dev/null +++ b/src/test/obj_defrag_advanced/pgraph.c @@ -0,0 +1,271 @@ +/* + * Copyright 2020, 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. + */ + +/* + * pgraph.c -- persistent graph representation + */ + +#include <inttypes.h> + +#include "unittest.h" + +#include "vgraph.h" +#include "pgraph.h" + +#define PATTERN 'g' + +/* + * pnode_size -- return the entire of node size + */ +static size_t +pnode_size(unsigned edges_num, size_t pattern_size) +{ + size_t node_size = sizeof(struct pnode_t); + node_size += sizeof(PMEMoid) * edges_num; + node_size += pattern_size; + return node_size; +} + +/* + * pnode_init -- initialize the node + */ +static void +pnode_init(PMEMobjpool *pop, PMEMoid pnode_oid, struct vnode_t *vnode, + PMEMoid pnodes[]) +{ + struct pnode_t *pnode = (struct pnode_t *)pmemobj_direct(pnode_oid); + pnode->node_id = vnode->node_id; + pnode->size = vnode->psize; + + /* set edges */ + pnode->edges_num = vnode->edges_num; + for (unsigned i = 0; i < vnode->edges_num; ++i) + pnode->edges[i] = pnodes[vnode->edges[i]]; + + /* initialize pattern */ + pnode->pattern_size = vnode->pattern_size; + void *pattern = (void *)&pnode->edges[pnode->edges_num]; + pmemobj_memset(pop, pattern, PATTERN, pnode->pattern_size, + PMEMOBJ_F_MEM_NOFLUSH); + + /* persist the whole node state */ + pmemobj_persist(pop, (const void *)pnode, pnode->size); +} + +/* + * order_shuffle -- shuffle the nodes in graph + */ +static void +order_shuffle(unsigned *order, unsigned num, rng_t *rngp) +{ + for (unsigned i = 0; i < num; ++i) { + unsigned j = rand_range(0, num, rngp); + unsigned temp = order[j]; + order[j] = order[i]; + order[i] = temp; + } +} + +/* + * order_new -- generate the sequence of the graph nodes allocation + */ +static unsigned * +order_new(struct vgraph_t *vgraph, rng_t *rngp) +{ + unsigned *order = (unsigned *)MALLOC(sizeof(unsigned) + * vgraph->nodes_num); + + /* initialize id list */ + for (unsigned i = 0; i < vgraph->nodes_num; ++i) + order[i] = i; + + order_shuffle(order, vgraph->nodes_num, rngp); + + return order; +} + +/* + * pgraph_copy_new -- allocate a persistent copy of the volatile graph + */ +static PMEMoid * +pgraph_copy_new(PMEMobjpool *pop, struct vgraph_t *vgraph, rng_t *rngp) +{ + /* to be returned array of PMEMoids to raw nodes allocations */ + PMEMoid *nodes = (PMEMoid *)MALLOC(sizeof(PMEMoid) * vgraph->nodes_num); + + /* generates random order of nodes allocation */ + unsigned *order = order_new(vgraph, rngp); + + /* allocate the nodes in the random order */ + int ret; + for (unsigned i = 0; i < vgraph->nodes_num; ++i) { + struct vnode_t vnode = vgraph->node[order[i]]; + PMEMoid *node = &nodes[order[i]]; + ret = pmemobj_alloc(pop, node, vnode.psize, 0, NULL, NULL); + UT_ASSERTeq(ret, 0); + } + + FREE(order); + + return nodes; +} + +/* + * pgraph_copy_delete -- free copies of the graph + */ +static void +pgraph_copy_delete(PMEMoid *nodes, unsigned num) +{ + for (unsigned i = 0; i < num; ++i) { + if (OID_IS_NULL(nodes[i])) + continue; + + pmemobj_free(&nodes[i]); + } + + FREE(nodes); +} + +/* + * pgraph_size -- return the struct pgraph_t size + */ +static size_t +pgraph_size(unsigned nodes_num) +{ + return sizeof(struct pgraph_t) + sizeof(PMEMoid) * nodes_num; +} + +/* + * pgraph_new -- allocate a new persistent graph in such a way + * that the fragmentation is as large as possible + */ +void +pgraph_new(PMEMobjpool *pop, PMEMoid *oidp, struct vgraph_t *vgraph, + struct pgraph_params *params, rng_t *rngp) +{ + int ret = pmemobj_alloc(pop, oidp, pgraph_size(vgraph->nodes_num), + 0, NULL, NULL); + UT_ASSERTeq(ret, 0); + + struct pgraph_t *pgraph = (struct pgraph_t *)pmemobj_direct(*oidp); + pgraph->nodes_num = vgraph->nodes_num; + pmemobj_persist(pop, pgraph, sizeof(*pgraph)); + + /* calculate size of pnodes */ + for (unsigned i = 0; i < vgraph->nodes_num; ++i) { + struct vnode_t *vnode = &vgraph->node[i]; + vnode->psize = pnode_size(vnode->edges_num, + vnode->pattern_size); + } + + /* prepare multiple copies of the nodes */ + unsigned copies_num = rand_range(1, params->graph_copies, rngp); + PMEMoid **copies = (PMEMoid **)MALLOC(sizeof(PMEMoid *) * copies_num); + for (unsigned i = 0; i < copies_num; ++i) + copies[i] = pgraph_copy_new(pop, vgraph, rngp); + + /* peek exactly the one copy of each node */ + for (unsigned i = 0; i < pgraph->nodes_num; ++i) { + unsigned copy_id = rand_range(0, copies_num, rngp); + pgraph->nodes[i] = copies[copy_id][i]; + copies[copy_id][i] = OID_NULL; + } + pmemobj_persist(pop, pgraph->nodes, + sizeof(PMEMoid) * pgraph->nodes_num); + + /* free unused copies of the nodes */ + for (unsigned i = 0; i < copies_num; ++i) + pgraph_copy_delete(copies[i], vgraph->nodes_num); + + FREE(copies); + + /* initialize pnodes */ + for (unsigned i = 0; i < pgraph->nodes_num; ++i) + pnode_init(pop, pgraph->nodes[i], &vgraph->node[i], + pgraph->nodes); +} + +/* + * pgraph_delete -- free the persistent graph + */ +void +pgraph_delete(PMEMoid *oidp) +{ + struct pgraph_t *pgraph = (struct pgraph_t *)pmemobj_direct(*oidp); + + /* free pnodes */ + for (unsigned i = 0; i < pgraph->nodes_num; ++i) + pmemobj_free(&pgraph->nodes[i]); + + pmemobj_free(oidp); +} + +/* + * pgraph_print -- print graph in human readable format + */ +void +pgraph_print(struct pgraph_t *pgraph, const char *dump) +{ + UT_ASSERTne(dump, NULL); + + FILE *out = FOPEN(dump, "w"); + + /* print the graph statistics */ + fprintf(out, "# of nodes: %u\n", pgraph->nodes_num); + + uint64_t total_edges_num = 0; + for (unsigned i = 0; i < pgraph->nodes_num; ++i) { + PMEMoid node_oid = pgraph->nodes[i]; + struct pnode_t *pnode = + (struct pnode_t *)pmemobj_direct(node_oid); + total_edges_num += pnode->edges_num; + } + fprintf(out, "Total # of edges: %" PRIu64 "\n\n", total_edges_num); + + /* print the graph itself */ + for (unsigned i = 0; i < pgraph->nodes_num; ++i) { + PMEMoid node_oid = pgraph->nodes[i]; + struct pnode_t *pnode = + (struct pnode_t *)pmemobj_direct(node_oid); + fprintf(out, "%u:", pnode->node_id); + for (unsigned j = 0; j < pnode->edges_num; ++j) { + PMEMoid edge_oid = pnode->edges[j]; + struct pnode_t *edge = + (struct pnode_t *)pmemobj_direct(edge_oid); + UT_ASSERT(edge->node_id < pgraph->nodes_num); + fprintf(out, "%u, ", edge->node_id); + } + fprintf(out, "\n"); + } + + FCLOSE(out); +} diff --git a/src/test/obj_defrag_advanced/pgraph.h b/src/test/obj_defrag_advanced/pgraph.h new file mode 100644 index 0000000000000000000000000000000000000000..ebe639ece1122b46d14e5527a619cd68f7186706 --- /dev/null +++ b/src/test/obj_defrag_advanced/pgraph.h @@ -0,0 +1,68 @@ +/* + * Copyright 2020, 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. + */ + +/* + * pgraph.h -- persistent graph representation + */ + +#ifndef OBJ_DEFRAG_ADV_PGRAPH +#define OBJ_DEFRAG_ADV_PGRAPH + +#include <libpmemobj/base.h> + +struct pgraph_params +{ + unsigned graph_copies; +}; + +struct pnode_t +{ + unsigned node_id; + unsigned edges_num; + size_t pattern_size; + size_t size; + PMEMoid edges[]; +}; + +struct pgraph_t +{ + unsigned nodes_num; + PMEMoid nodes[]; +}; + +void pgraph_new(PMEMobjpool *pop, PMEMoid *oidp, struct vgraph_t *vgraph, + struct pgraph_params *params, rng_t *rngp); +void pgraph_delete(PMEMoid *oidp); + +void pgraph_print(struct pgraph_t *graph, const char *dump); + +#endif /* pgraph.h */ diff --git a/src/test/obj_defrag_advanced/vgraph.c b/src/test/obj_defrag_advanced/vgraph.c new file mode 100644 index 0000000000000000000000000000000000000000..c05b2f8377426f72b70cdad19c6a9ee93c6e52b2 --- /dev/null +++ b/src/test/obj_defrag_advanced/vgraph.c @@ -0,0 +1,159 @@ +/* + * Copyright 2020, 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. + */ + +/* + * vgraph.c -- volatile graph representation + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "rand.h" +#include "unittest.h" +#include "vgraph.h" + +/* + * rand_range -- generate pseudo-random number from given interval [min, max] + */ +unsigned +rand_range(unsigned min, unsigned max, rng_t *rngp) +{ + if (min == max) + return min; + + if (min > max) + UT_FATAL("!rand_range"); + + unsigned ret; + if (rngp) + ret = (unsigned)rnd64_r(rngp); + else + ret = (unsigned)rnd64(); + + return ((unsigned)ret % (max - min)) + min; +} + +/* + * vnode_new -- allocate a new volatile node + */ +static void +vnode_new(struct vnode_t *node, unsigned v, struct vgraph_params *params, + rng_t *rngp) +{ + unsigned min_edges = 1; + if (params->max_edges > params->range_edges) + min_edges = params->max_edges - params->range_edges; + unsigned edges_num = rand_range(min_edges, params->max_edges, rngp); + node->node_id = v; + node->edges_num = edges_num; + node->edges = (unsigned *)MALLOC(sizeof(int) * edges_num); + node->pattern_size = rand_range(params->min_pattern_size, + params->max_pattern_size, rngp); +} + +/* + * vnode_delete -- free a volatile node + */ +static void +vnode_delete(struct vnode_t *node) +{ + FREE(node->edges); +} + +/* + * vgraph_get_node -- return node in graph based on given id_node + */ +static struct vnode_t * +vgraph_get_node(struct vgraph_t *graph, unsigned id_node) +{ + struct vnode_t *node; + + node = &graph->node[id_node]; + return node; +} + +/* + * vgraph_add_edges -- randomly assign destination nodes to the edges + */ +static void +vgraph_add_edges(struct vgraph_t *graph, rng_t *rngp) +{ + unsigned nodes_count = 0; + unsigned edges_count = 0; + struct vnode_t *node; + for (nodes_count = 0; nodes_count < graph->nodes_num; nodes_count++) { + node = vgraph_get_node(graph, nodes_count); + unsigned edges_num = node->edges_num; + for (edges_count = 0; edges_count < edges_num; edges_count++) { + unsigned node_link = + rand_range(0, graph->nodes_num, rngp); + node->edges[edges_count] = node_link; + } + } +} + +/* + * vgraph_new -- allocate a new volatile graph + */ +struct vgraph_t * +vgraph_new(struct vgraph_params *params, rng_t *rngp) +{ + unsigned min_nodes = 1; + if (params->max_nodes > params->range_nodes) + min_nodes = params->max_nodes - params->range_nodes; + unsigned nodes_num = rand_range(min_nodes, params->max_nodes, rngp); + + struct vgraph_t *graph = + (struct vgraph_t *)MALLOC(sizeof(struct vgraph_t) + + sizeof(struct vnode_t) * nodes_num); + graph->nodes_num = nodes_num; + + for (unsigned i = 0; i < nodes_num; i++) { + vnode_new(&graph->node[i], i, params, rngp); + } + + vgraph_add_edges(graph, rngp); + + return graph; +} + +/* + * vgraph_delete -- free the volatile graph + */ +void +vgraph_delete(struct vgraph_t *graph) +{ + for (unsigned i = 0; i < graph->nodes_num; i++) + vnode_delete(&graph->node[i]); + + FREE(graph); +} diff --git a/src/test/obj_defrag_advanced/vgraph.h b/src/test/obj_defrag_advanced/vgraph.h new file mode 100644 index 0000000000000000000000000000000000000000..25648c270ecd6148fcaf98de1c0a8c1d8d4dedf2 --- /dev/null +++ b/src/test/obj_defrag_advanced/vgraph.h @@ -0,0 +1,76 @@ +/* + * Copyright 2020, 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. + */ + +/* + * vgraph.h -- volatile graph representation + */ + +#ifndef OBJ_DEFRAG_ADV_VGRAPH +#define OBJ_DEFRAG_ADV_VGRAPH + +#include "rand.h" + +struct vgraph_params +{ + unsigned max_nodes; /* max # of nodes per graph */ + unsigned max_edges; /* max # of edges per node */ + /* # of nodes is between [max_nodes - range_nodes, max_nodes] */ + unsigned range_nodes; + /* # of edges is between [max_edges - range_edges, max_edges] */ + unsigned range_edges; + unsigned min_pattern_size; + unsigned max_pattern_size; +}; + +struct vnode_t +{ + unsigned node_id; + unsigned edges_num; /* # of edges starting from this node */ + unsigned *edges; /* ids of nodes the edges are pointing to */ + + /* the persistent node attributes */ + size_t pattern_size; /* size of the pattern allocated after the node */ + size_t psize; /* the total size of the node */ +}; + +struct vgraph_t +{ + unsigned nodes_num; + struct vnode_t node[]; +}; + +unsigned rand_range(unsigned min, unsigned max, rng_t *rngp); + +struct vgraph_t *vgraph_new(struct vgraph_params *params, rng_t *rngp); +void vgraph_delete(struct vgraph_t *graph); + +#endif