Skip to content

Commit dec0612

Browse files
committed
Track hardness of solver queries
Introduces a functionality to track and collect the complexity of individual solver queries. For SAT solvers we collect the number of clauses, literals, and variables. The functionality matches solver queries to the SSA steps that produced them. After running the solver, we produce a JSON report that matches program line to GOTO instruction to SSA step to solver hardness. At present the collection is command-line optional and only works with the default SAT solver (minisat2). Extension to other SAT and SMT solvers should be possible. A simple regression test is included. Note: the solver-hardness structure lives in the minisat2 and is accessible via the interface of hardness-collector (which minisat2 inherits from). Hence to find out if symex should collect the statistics one must try-cast `prop` to `hardness-collector`. `prop` is part of the `solvert` but not directly accessible from `decision-procedure`. So we also had to extend the interface that initialises the SSA conversion (to include `prop` as well).
1 parent 5568f64 commit dec0612

29 files changed

+925
-40
lines changed

regression/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,5 @@ if(WITH_MEMORY_ANALYZER)
6060
add_subdirectory(snapshot-harness)
6161
add_subdirectory(memory-analyzer)
6262
endif()
63+
64+
add_subdirectory(solver-hardness)

regression/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ DIRS = cbmc \
3030
goto-cc-file-local \
3131
linking-goto-binaries \
3232
symtab2gb \
33+
solver-hardness \
3334
# Empty last line
3435

3536
ifeq ($(OS),Windows_NT)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
add_test_pl_tests(
2+
"../chain.sh $<TARGET_FILE:cbmc>")
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
default: tests.log
2+
3+
include ../../src/config.inc
4+
include ../../src/common
5+
6+
CBMC_EXE=../../../src/cbmc/cbmc
7+
8+
test:
9+
@../test.pl -e -p -c "../chain.sh $(CBMC_EXE)"
10+
11+
tests.log: ../test.pl
12+
@../test.pl -e -p -c "../chain.sh $(CBMC_EXE)"
13+
14+
show:
15+
@for dir in *; do \
16+
if [ -d "$$dir" ]; then \
17+
vim -o "$$dir/*.c" "$$dir/*.out"; \
18+
fi; \
19+
done;
20+
21+
clean:
22+
find -name '*.out' -execdir $(RM) '{}' \;
23+
$(RM) tests.log
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/bash
2+
3+
cbmc=$1
4+
5+
name=${*:$#}
6+
args=${*:2:$#-2}
7+
8+
$cbmc ${name} ${args}
9+
CBMC_RETURN_CODE="$?"
10+
../parse_json.py "solver_hardness.json"
11+
exit ${CBMC_RETURN_CODE}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env python
2+
3+
import sys
4+
import json
5+
6+
def main():
7+
with open(sys.argv[1], "r") as json_file:
8+
data = json.load(json_file)
9+
print ("Valid JSON File")
10+
print (json.dumps(data))
11+
12+
if __name__ == "__main__":
13+
main()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int a;
6+
int b;
7+
assert(a + b < 10);
8+
return 0;
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--write-solver-stats-to "solver_hardness.json"
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main.assertion.\d+\] line \d+ assertion a \+ b \< 10: FAILURE$
7+
^VERIFICATION FAILED$
8+
^Valid JSON File$
9+
\"SAT_hardness\": \{(\"Clauses\": \d+|\"Variables\": \d+|\"Literals\": \d+), (\"Clauses\": \d+|\"Variables\": \d+|\"Literals\": \d+), (\"Clauses\": \d+|\"Variables\": \d+|\"Literals\": \d+)\}
10+
--
11+
^warning: ignoring

src/cbmc/cbmc_parse_options.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,12 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
460460
}
461461
}
462462

463+
if(cmdline.isset("write-solver-stats-to"))
464+
{
465+
options.set_option(
466+
"write-solver-stats-to", cmdline.get_value("write-solver-stats-to"));
467+
}
468+
463469
if(cmdline.isset("beautify"))
464470
options.set_option("beautify", true);
465471

@@ -1106,6 +1112,8 @@ void cbmc_parse_optionst::help()
11061112
HELP_FLUSH
11071113
" --verbosity # verbosity level\n"
11081114
HELP_TIMESTAMP
1115+
" --write-solver-stats-to json-file\n"
1116+
" collect the solver query complexity\n"
11091117
"\n";
11101118
// clang-format on
11111119
}

src/cbmc/cbmc_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class optionst;
4646
OPT_REACHABILITY_SLICER \
4747
"(debug-level):(no-propagation)(no-simplify-if)" \
4848
"(document-subgoals)(outfile):(test-preprocessor)" \
49+
"(write-solver-stats-to):" \
4950
"D:I:(c89)(c99)(c11)(cpp98)(cpp03)(cpp11)" \
5051
"(object-bits):" \
5152
OPT_GOTO_CHECK \

0 commit comments

Comments
 (0)