File: helpers.cmake

package info (click to toggle)
libpmemobj-cpp 1.12-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 8,388 kB
  • sloc: cpp: 136,076; sh: 1,022; perl: 381; ansic: 163; makefile: 13
file content (378 lines) | stat: -rw-r--r-- 13,701 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2018-2021, Intel Corporation

set(DIR ${PARENT_DIR}/${TEST_NAME})

function(setup)
    execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${PARENT_DIR}/${TEST_NAME})
    execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${PARENT_DIR}/${TEST_NAME})
    execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${BIN_DIR})
    execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${BIN_DIR})
endfunction()

function(print_logs)
    message(STATUS "Test ${TEST_NAME}:")
    if(EXISTS ${BIN_DIR}/${TEST_NAME}.out)
        file(READ ${BIN_DIR}/${TEST_NAME}.out OUT)
        message(STATUS "Stdout:\n${OUT}")
    endif()
    if(EXISTS ${BIN_DIR}/${TEST_NAME}.err)
        file(READ ${BIN_DIR}/${TEST_NAME}.err ERR)
        message(STATUS "Stderr:\n${ERR}")
    endif()
    if(EXISTS ${BIN_DIR}/${TEST_NAME}.pmreorder)
       file(READ ${BIN_DIR}/${TEST_NAME}.pmreorder PMEMREORDER)
       message(STATUS "Pmreorder:\n${PMEMREORDER}")
    endif()
endfunction()

# Performs cleanup and log matching.
function(finish)
    print_logs()

    if(EXISTS ${SRC_DIR}/${TEST_NAME}.err.match)
        match(${BIN_DIR}/${TEST_NAME}.err ${SRC_DIR}/${TEST_NAME}.err.match)
    endif()
    if(EXISTS ${SRC_DIR}/${TEST_NAME}.out.match)
        match(${BIN_DIR}/${TEST_NAME}.out ${SRC_DIR}/${TEST_NAME}.out.match)
    endif()

    execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory ${PARENT_DIR}/${TEST_NAME})
endfunction()

# Verifies ${log_file} matches ${match_file} using "match".
function(match log_file match_file)
    execute_process(COMMAND
            ${PERL_EXECUTABLE} ${MATCH_SCRIPT} -o ${log_file} ${match_file}
            RESULT_VARIABLE MATCH_ERROR)

    if(MATCH_ERROR)
        message(FATAL_ERROR "Log does not match: ${MATCH_ERROR}")
    endif()
endfunction()

# Verifies file exists
function(check_file_exists file)
    if(NOT EXISTS ${file})
        message(FATAL_ERROR "${file} doesn't exist")
    endif()
endfunction()

# Verifies file doesn't exist
function(check_file_doesnt_exist file)
    if(EXISTS ${file})
        message(FATAL_ERROR "${file} exists")
    endif()
endfunction()

# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=810295
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=780173
# https://bugs.kde.org/show_bug.cgi?id=303877
#
# valgrind issues an unsuppressable warning when exceeding
# the brk segment, causing matching failures. We can safely
# ignore it because malloc() will fallback to mmap() anyway.
#
# list of ignored warnings should match the list provided by PMDK:
# https://github.com/pmem/pmdk/blob/master/src/test/unittest/unittest.sh
function(valgrind_ignore_warnings valgrind_log)
    execute_process(COMMAND bash "-c" "cat ${valgrind_log} | grep -v \
    -e \"WARNING: Serious error when reading debug info\" \
    -e \"When reading debug info from \" \
    -e \"Ignoring non-Dwarf2/3/4 block in .debug_info\" \
    -e \"Last block truncated in .debug_info; ignoring\" \
    -e \"parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4\" \
    -e \"brk segment overflow\" \
    -e \"see section Limitations in user manual\" \
    -e \"Warning: set address range perms: large range\"\
    -e \"further instances of this message will not be shown\"\
    >  ${valgrind_log}.tmp
mv ${valgrind_log}.tmp ${valgrind_log}")
endfunction()

function(execute_common expect_success output_file name)
    if(TESTS_USE_FORCED_PMEM)
        set(ENV{PMEM_IS_PMEM_FORCE} 1)
    endif()

    if(${TRACER} STREQUAL pmemcheck)
        if(TESTS_USE_FORCED_PMEM)
            # pmemcheck runs really slow with pmem, disable it
            set(ENV{PMEM_IS_PMEM_FORCE} 0)
        endif()
        set(TRACE valgrind --error-exitcode=99 --tool=pmemcheck)
        set(ENV{LIBPMEMOBJ_CPP_TRACER_PMEMCHECK} 1)
    elseif(${TRACER} STREQUAL memcheck)
        set(TRACE valgrind --error-exitcode=99 --tool=memcheck --leak-check=full
           --suppressions=${TEST_ROOT_DIR}/ld.supp --suppressions=${TEST_ROOT_DIR}/memcheck-stdcpp.supp --suppressions=${TEST_ROOT_DIR}/memcheck-libunwind.supp)
        set(ENV{LIBPMEMOBJ_CPP_TRACER_MEMCHECK} 1)
    elseif(${TRACER} STREQUAL helgrind)
        set(TRACE valgrind --error-exitcode=99 --tool=helgrind)
        set(ENV{LIBPMEMOBJ_CPP_TRACER_HELGRIND} 1)
    elseif(${TRACER} STREQUAL drd)
        set(TRACE valgrind --error-exitcode=99 --tool=drd)
        set(ENV{LIBPMEMOBJ_CPP_TRACER_DRD} 1)
    elseif(${TRACER} STREQUAL gdb)
        set(TRACE gdb --batch --command=${GDB_BATCH_FILE} --args)
        set(ENV{LIBPMEMOBJ_CPP_TRACER_GDB} 1)
    elseif(${TRACER} MATCHES "none.*")
        # nothing
    else()
        message(FATAL_ERROR "Unknown tracer '${TRACER}'")
    endif()

    if (NOT $ENV{CGDB})
        if (NOT WIN32)
            set(TRACE timeout -s SIGALRM -k 200s 180s ${TRACE})
        endif()
    endif()

    string(REPLACE ";" " " TRACE_STR "${TRACE}")
    message(STATUS "Executing: ${TRACE_STR} ${name} ${ARGN}")

    set(cmd ${TRACE} ${name} ${ARGN})

    if($ENV{CGDB})
        find_program(KONSOLE NAMES konsole)
        find_program(GNOME_TERMINAL NAMES gnome-terminal)
        find_program(CGDB NAMES cgdb)

        if (NOT KONSOLE AND NOT GNOME_TERMINAL)
            message(FATAL_ERROR "konsole or gnome-terminal not found.")
        elseif (NOT CGDB)
            message(FATAL_ERROR "cdgb not found.")
        elseif(NOT (${TRACER} STREQUAL none))
            message(FATAL_ERROR "Cannot use cgdb with ${TRACER}")
        else()
            if (KONSOLE)
                set(cmd konsole -e cgdb --args ${cmd})
            elseif(GNOME_TERMINAL)
                set(cmd gnome-terminal --tab --active --wait -- cgdb --args ${cmd})
            endif()
        endif()
    endif()

    if(${output_file} STREQUAL none)
        execute_process(COMMAND ${cmd}
            OUTPUT_QUIET
            RESULT_VARIABLE res)
    else()
        execute_process(COMMAND ${cmd}
            RESULT_VARIABLE res
            OUTPUT_FILE ${BIN_DIR}/tmp.out
            ERROR_FILE ${BIN_DIR}/tmp.err)

            file(READ ${BIN_DIR}/tmp.out OUT_FILE)
            file(READ ${BIN_DIR}/tmp.err ERR_FILE)

            file(APPEND ${BIN_DIR}/${TEST_NAME}.out ${OUT_FILE})
            file(APPEND ${BIN_DIR}/${TEST_NAME}.err ${ERR_FILE})

            file(REMOVE ${BIN_DIR}/tmp.out)
            file(REMOVE ${BIN_DIR}/tmp.err)
    endif()

    print_logs()

    # memcheck and pmemcheck match files should follow name pattern:
    # testname_testcaseno_memcheck/pmemcheck.err.match
    # If they do exist, ignore test result - it will be verified during
    # log matching in finish() function.
    if(EXISTS ${SRC_DIR}/${TEST_NAME}.err.match)
        valgrind_ignore_warnings(${BIN_DIR}/${TEST_NAME}.err)
    # pmemcheck is a special snowflake and it doesn't set exit code when
    # it detects an error, so we have to look at its output if match file
    # was not found.
    else()
        if(${TRACER} STREQUAL pmemcheck)
            if(NOT EXISTS ${BIN_DIR}/${TEST_NAME}.err)
                message(FATAL_ERROR "${TEST_NAME}.err not found.")
            endif()

            file(READ ${BIN_DIR}/${TEST_NAME}.err PMEMCHECK_ERR)
            message(STATUS "Stderr:\n${PMEMCHECK_ERR}\nEnd of stderr")
            if(NOT PMEMCHECK_ERR MATCHES "ERROR SUMMARY: 0")
                message(FATAL_ERROR "${TRACE} ${name} ${ARGN} failed: ${res}")
            endif()
        endif()

        if(res AND expect_success)
            message(FATAL_ERROR "${TRACE} ${name} ${ARGN} failed: ${res}")
        endif()

        if(NOT res AND NOT expect_success)
            message(FATAL_ERROR "${TRACE} ${name} ${ARGN} unexpectedly succeeded: ${res}")
        endif()
    endif()

    if(${TRACER} STREQUAL pmemcheck)
        unset(ENV{LIBPMEMOBJ_CPP_TRACER_PMEMCHECK})
    elseif(${TRACER} STREQUAL memcheck)
        unset(ENV{LIBPMEMOBJ_CPP_TRACER_MEMCHECK})
    elseif(${TRACER} STREQUAL helgrind)
        unset(ENV{LIBPMEMOBJ_CPP_TRACER_HELGRIND})
    elseif(${TRACER} STREQUAL drd)
        unset(ENV{LIBPMEMOBJ_CPP_TRACER_DRD})
    elseif(${TRACER} STREQUAL gdb)
        unset(ENV{LIBPMEMOBJ_CPP_TRACER_GDB})
    endif()

    if(TESTS_USE_FORCED_PMEM)
        unset(ENV{PMEM_IS_PMEM_FORCE})
    endif()
endfunction()

function(check_target name)
    if(NOT EXISTS ${name})
        message(FATAL_ERROR "Test file: \"${name}\" was not found! If test wasn't built, run make first.")
    endif()
endfunction()

# Generic command executor which handles failures and prints command output
# to specified file.
function(execute_with_output out name)
    check_target(${name})

    execute_common(true ${out} ${name} ${ARGN})
endfunction()

# Generic command executor which handles failures but ignores output.
function(execute_ignore_output name)
    check_target(${name})

    execute_common(true none ${name} ${ARGN})
endfunction()

# Executes test command ${name} and verifies its status.
# First argument of the command is test directory name.
# Optional function arguments are passed as consecutive arguments to
# the command.
function(execute name)
    check_target(${name})

    execute_common(true ${TRACER}_${TESTCASE} ${name} ${ARGN})
endfunction()

# Executes command ${name} and creates a storelog.
# First argument is pool file.
# Second argument is test executable.
# Optional function arguments are passed as consecutive arguments to
# the command.
function(pmreorder_create_store_log pool name)
    check_target(${name})

    if(NOT (${TRACER} STREQUAL none))
        message(FATAL_ERROR "Pmreorder test must be run without any tracer.")
    endif()

    configure_file(${pool} ${pool}.copy COPYONLY)

    set(ENV{PMREORDER_EMIT_LOG} 1)

    if(DEFINED ENV{PMREORDER_STACKTRACE_DEPTH})
        set(PMREORDER_STACKTRACE_DEPTH $ENV{PMREORDER_STACKTRACE_DEPTH})
        set(PMREORDER_STACKTRACE "yes")
    else()
        set(PMREORDER_STACKTRACE_DEPTH 1)
        set(PMREORDER_STACKTRACE "no")
    endif()

    set(cmd valgrind --tool=pmemcheck -q
        --log-stores=yes
        --print-summary=no
        --log-file=${BIN_DIR}/${TEST_NAME}.storelog
        --log-stores-stacktraces=${PMREORDER_STACKTRACE}
        --log-stores-stacktraces-depth=${PMREORDER_STACKTRACE_DEPTH}
        --expect-fence-after-clflush=yes
        ${name} ${ARGN})

    execute_common(true ${TRACER}_${TESTCASE} ${cmd})

    unset(ENV{PMREORDER_EMIT_LOG})

    file(REMOVE ${pool})
    configure_file(${pool}.copy ${pool} COPYONLY)
endfunction()

# Executes pmreorder.
# First argument is expected result.
# Second argument is engine type.
# Third argument is path to configure file.
# Fourth argument is path to the checker program.
# Optional function arguments are passed as consecutive arguments to
# the command.
function(pmreorder_execute expect_success engine conf_file name)
    check_target(${name})

    if(NOT (${TRACER} STREQUAL none))
        message(FATAL_ERROR "Pmreorder test must be run without any tracer.")
    endif()

    set(ENV{PMEMOBJ_CONF} "copy_on_write.at_open=1")

    set(cmd pmreorder -l ${BIN_DIR}/${TEST_NAME}.storelog
                    -o ${BIN_DIR}/${TEST_NAME}.pmreorder
                    -r ${engine}
                    -p "${name} ${ARGN}"
                    -x ${conf_file})

    execute_common(${expect_success} ${TRACER}_${TESTCASE} ${cmd})

    unset(ENV{PMEMOBJ_CONF})
endfunction()

# Executes test command ${name} under GDB.
# First argument of the command is a gdb batch file.
# Second argument of the command is the test command.
# Optional function arguments are passed as consecutive arguments to
# the command.
function(crash_with_gdb gdb_batch_file name)
    check_target(${name})

    set(PREV_TRACER ${TRACER})
    set(TRACER gdb)
    set(GDB_BATCH_FILE ${gdb_batch_file})

    execute_common(true ${TRACER}_${TESTCASE} ${name} ${ARGN})

    set(TRACER ${PREV_TRACER})
endfunction()

# Checks whether specified filename is located on persistent memory and emits
# FATAL_ERROR in case it's not.
function(check_is_pmem filename)
    execute_process(COMMAND ${BIN_DIR}/../check_is_pmem ${filename} RESULT_VARIABLE is_pmem)

    if (${is_pmem} EQUAL 2)
        message(FATAL_ERROR "check_is_pmem failed.")
    elseif ((${is_pmem} EQUAL 1) AND (NOT TESTS_USE_FORCED_PMEM))
        # Return value 1 means that path points to non-pmem
        message(FATAL_ERROR "${TEST_NAME} can only be run on PMEM.")
    endif()
endfunction()

function(set_libpmemobj_version_num)
    # XXX: if you want to use it, make sure to add and use return variable
    # set variable ${LIBPMEMOBJ_VERSION_NUM}; it can possibly be used in e.g. tests
    if(LIBPMEMOBJ_VERSION AND LIBPMEMOBJ_VERSION MATCHES "[0-9]+[.][0-9]+.*")
        string(REGEX REPLACE "\\+git.*" "" LIBPMEMOBJ_VERSION_SHORT ${LIBPMEMOBJ_VERSION})
        string(REGEX REPLACE "-rc.*" "" LIBPMEMOBJ_VERSION_SHORT ${LIBPMEMOBJ_VERSION_SHORT})
        string(REPLACE "." ";" VERSION_LIST ${LIBPMEMOBJ_VERSION_SHORT})
        list(GET VERSION_LIST 0 LIBPMEMOBJ_VERSION_MAJOR)
        list(GET VERSION_LIST 1 LIBPMEMOBJ_VERSION_MINOR)
        list(LENGTH VERSION_LIST OBJ_VER_COMPS)
        if(${OBJ_VER_COMPS} LESS 3)
            list(APPEND VERSION_LIST "0")
        endif()
        list(GET VERSION_LIST 2 LIBPMEMOBJ_VERSION_PATCH)
    else()
        # XXX: will them skip?
        message(WARNING "cannot detect libpmemobj version, some tests will be skipped")
        # assume 0.0.0
        set(LIBPMEMOBJ_VERSION_MAJOR 0)
        set(LIBPMEMOBJ_VERSION_MINOR 0)
        set(LIBPMEMOBJ_VERSION_PATCH 0)
    endif()

    math(EXPR LIBPMEMOBJ_VERSION_NUM "${LIBPMEMOBJ_VERSION_PATCH} + ${LIBPMEMOBJ_VERSION_MINOR} * 100 + ${LIBPMEMOBJ_VERSION_MAJOR} * 10000")
endfunction()