-
Notifications
You must be signed in to change notification settings - Fork 36
SVM optimizations #130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
SVM optimizations #130
Changes from 82 commits
634f871
e110c7e
b537708
4c01d0b
8a823f5
e788dd2
f0a6581
e115574
3dcfc0b
d2d6cee
b0f02e9
147a3bc
e7839b4
f91a799
cee9447
22b44c1
2ca9dbd
e247715
08d1672
e4f9696
0b9188d
66756cc
4f3a431
c9dbb4a
8abad91
7251d4e
99f366d
de31156
46c76ba
c5f1e44
c27b432
487457d
ceeea20
ab925c5
66e517c
36a600a
a709a25
70abd26
173fcf8
4370685
453775e
b251e88
67d77da
b325b53
dc2170c
b6906b0
4db3cc3
b8e663d
25af3e9
6aa02e7
747a36c
fbfcf51
c33fa0b
f5b6252
545e56c
62d99e3
7794e7c
e698159
c2b15d8
96d1dac
58edff0
73430cf
f90e040
e9cb57f
b208155
5698618
220bb8b
11e2ea4
97afb91
1ebc138
01d8c38
3905341
01a6d34
cbadf8c
3291c74
78cd8c1
35e4756
40edf31
defb901
fd05f66
9a592c2
a9b40c3
2449219
dd65e89
cef420d
de680e3
e2fcd66
a8226e1
23e00c0
49b281c
b66151d
5d624a6
d71e132
d077c56
814d398
c0f325f
b5a2ebd
53419b6
0ffc829
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| using VSharp.Core; | ||
|
|
||
| namespace VSharp | ||
| { | ||
| /// <summary> | ||
| /// Advanced symbolic virtual machine options. | ||
| /// </summary> | ||
| /// <param name="IsConstraintIndependenceEnabled">If true, independent constraint sets are maintained (constraint independence optimization).</param> | ||
| /// <param name="IsConditionEvaluationEnabled">If true, branch condition is evaluated with current model to avoid extra SMT solver queries.</param> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. эту опцию предлагаю просто убрать -- оставить ее всегда включенной |
||
| /// <param name="IsSolverIncrementalityEnabled">If true, SMT solver works in incremental mode.</param> | ||
| public readonly record struct SvmOptions( | ||
| bool IsConstraintIndependenceEnabled = false, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. это выставим по умолчанию в true |
||
| bool IsConditionEvaluationEnabled = false, | ||
| bool IsSolverIncrementalityEnabled = false | ||
| ) | ||
| { | ||
| internal featureFlags GetFeatureFlags() => | ||
| new featureFlags( | ||
| isConstraintIndependenceEnabled: IsConstraintIndependenceEnabled, | ||
| isConditionEvaluationEnabled: IsConditionEvaluationEnabled, | ||
| isIncrementalityEnabled: IsSolverIncrementalityEnabled | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,7 +71,7 @@ public void GenerateReport(TextWriter writer) | |
|
|
||
| public static class TestGenerator | ||
| { | ||
| private static Statistics StartExploration(List<MethodBase> methods, string resultsFolder, string[] mainArguments = null) | ||
| private static Statistics StartExploration(List<MethodBase> methods, string resultsFolder, SvmOptions svmOptions, string[] mainArguments = null) | ||
| { | ||
| var recThreshold = 0u; | ||
| var options = | ||
|
|
@@ -80,6 +80,9 @@ private static Statistics StartExploration(List<MethodBase> methods, string resu | |
| SILI explorer = new SILI(options); | ||
| UnitTests unitTests = new UnitTests(resultsFolder); | ||
| Core.API.ConfigureSolver(SolverPool.mkSolver()); | ||
| Core.API.SetFeatureFlags(svmOptions.GetFeatureFlags()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. все option'ы надо унифицировать в SILIOptions |
||
|
|
||
| // TODO: single solver instance for multiple methods causes problems in incrementality mode | ||
| foreach (var method in methods) | ||
| { | ||
| if (method == method.Module.Assembly.EntryPoint) | ||
|
|
@@ -111,21 +114,23 @@ private static bool Reproduce(DirectoryInfo testDir) | |
| /// </summary> | ||
| /// <param name="method">Type to be covered with tests.</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>Summary of tests generation process.</returns> | ||
| public static Statistics Cover(MethodBase method, string outputDirectory = "") | ||
| public static Statistics Cover(MethodBase method, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. если и передавать, то все SILIOptions |
||
| { | ||
| List<MethodBase> methods = new List<MethodBase> {method}; | ||
| return StartExploration(methods, outputDirectory); | ||
| return StartExploration(methods, outputDirectory, svmOptions); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Generates test coverage for all public methods of specified type. | ||
| /// </summary> | ||
| /// <param name="type">Type to be covered with tests.</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>Summary of tests generation process.</returns> | ||
| /// <exception cref="ArgumentException">Thrown if specified class does not contain public methods.</exception> | ||
| public static Statistics Cover(Type type, string outputDirectory = "") | ||
| public static Statistics Cover(Type type, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | | ||
| BindingFlags.DeclaredOnly; | ||
|
|
@@ -140,18 +145,19 @@ public static Statistics Cover(Type type, string outputDirectory = "") | |
| throw new ArgumentException("I've not found any public method of class " + type.FullName); | ||
| } | ||
|
|
||
| return StartExploration(methods, outputDirectory); | ||
| return StartExploration(methods, outputDirectory, svmOptions); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Generates test coverage for all public methods of all public classes in the specified assembly. | ||
| /// </summary> | ||
| /// <param name="assembly">Assembly to be covered with tests.</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>Summary of tests generation process.</returns> | ||
| /// <exception cref="ArgumentException">Thrown if no public methods found in assembly. | ||
| /// </exception> | ||
| public static Statistics Cover(Assembly assembly, string outputDirectory = "") | ||
| public static Statistics Cover(Assembly assembly, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| List<MethodBase> methods; | ||
| BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | | ||
|
|
@@ -173,7 +179,7 @@ public static Statistics Cover(Assembly assembly, string outputDirectory = "") | |
| throw new ArgumentException("I've not found any public method in assembly"); | ||
| } | ||
|
|
||
| return StartExploration(methods, outputDirectory); | ||
| return StartExploration(methods, outputDirectory, svmOptions); | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -182,10 +188,11 @@ public static Statistics Cover(Assembly assembly, string outputDirectory = "") | |
| /// <param name="assembly">Assembly to be covered with tests.</param> | ||
| /// <param name="args">Command line arguments of entry point</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>Summary of tests generation process.</returns> | ||
| /// <exception cref="ArgumentException">Thrown if assembly does not contain entry point. | ||
| /// </exception> | ||
| public static Statistics Cover(Assembly assembly, string[] args, string outputDirectory = "") | ||
| public static Statistics Cover(Assembly assembly, string[] args, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| List<MethodBase> methods; | ||
| var entryPoint = assembly.EntryPoint; | ||
|
|
@@ -195,18 +202,19 @@ public static Statistics Cover(Assembly assembly, string[] args, string outputDi | |
| } | ||
| methods = new List<MethodBase> { entryPoint }; | ||
|
|
||
| return StartExploration(methods, outputDirectory, args); | ||
| return StartExploration(methods, outputDirectory, svmOptions, args); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Generates test coverage for the specified method and runs all tests. | ||
| /// </summary> | ||
| /// <param name="method">Type to be covered with tests.</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>True if all generated tests have passed.</returns> | ||
| public static bool CoverAndRun(MethodBase method, string outputDirectory = "") | ||
| public static bool CoverAndRun(MethodBase method, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| var stats = Cover(method, outputDirectory); | ||
| var stats = Cover(method, outputDirectory, svmOptions); | ||
| return Reproduce(stats.OutputDir); | ||
| } | ||
|
|
||
|
|
@@ -215,11 +223,12 @@ public static bool CoverAndRun(MethodBase method, string outputDirectory = "") | |
| /// </summary> | ||
| /// <param name="type">Type to be covered with tests.</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>True if all generated tests have passed.</returns> | ||
| /// <exception cref="ArgumentException">Thrown if specified class does not contain public methods.</exception> | ||
| public static bool CoverAndRun(Type type, string outputDirectory = "") | ||
| public static bool CoverAndRun(Type type, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| var stats = Cover(type, outputDirectory); | ||
| var stats = Cover(type, outputDirectory, svmOptions); | ||
| return Reproduce(stats.OutputDir); | ||
| } | ||
|
|
||
|
|
@@ -228,12 +237,13 @@ public static bool CoverAndRun(Type type, string outputDirectory = "") | |
| /// </summary> | ||
| /// <param name="assembly">Assembly to be covered with tests.</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>True if all generated tests have passed.</returns> | ||
| /// <exception cref="ArgumentException">Thrown if no public methods found in assembly. | ||
| /// </exception> | ||
| public static bool CoverAndRun(Assembly assembly, string outputDirectory = "") | ||
| public static bool CoverAndRun(Assembly assembly, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| var stats = Cover(assembly, outputDirectory); | ||
| var stats = Cover(assembly, outputDirectory, svmOptions); | ||
| return Reproduce(stats.OutputDir); | ||
| } | ||
|
|
||
|
|
@@ -243,11 +253,12 @@ public static bool CoverAndRun(Assembly assembly, string outputDirectory = "") | |
| /// <param name="assembly">Assembly to be covered with tests.</param> | ||
| /// <param name="args">Command line arguments of entry point</param> | ||
| /// <param name="outputDirectory">Directory to place generated *.vst tests. If null or empty, process working directory is used.</param> | ||
| /// <param name="svmOptions">Advanced symbolic virtual machine options.</param> | ||
| /// <returns>True if all generated tests have passed.</returns> | ||
| /// <exception cref="ArgumentException">Thrown if assembly does not contain entry point.</exception> | ||
| public static bool CoverAndRun(Assembly assembly, string[] args, string outputDirectory = "") | ||
| public static bool CoverAndRun(Assembly assembly, string[] args, string outputDirectory = "", SvmOptions svmOptions = new()) | ||
| { | ||
| var stats = Cover(assembly, args, outputDirectory); | ||
| var stats = Cover(assembly, args, outputDirectory, svmOptions); | ||
| return Reproduce(stats.OutputDir); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.CommandLine; | ||
| using System.CommandLine.Invocation; | ||
| using System.IO; | ||
|
|
@@ -122,6 +121,10 @@ public static int Main(string[] args) | |
| var unknownArgsOption = | ||
| new Option("--unknown-args", description: "Force engine to generate various input console arguments"); | ||
|
|
||
| var constraintIndependenceOption = new Option<bool>("--c-independence", description: "Advanced: maintain independent constraint sets (constraint independence optimization)"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. тут всё тоже надо синхронизировать с опциями выше: удалить conditionEvaluation, плюс написать дефолтное значение каждой опции |
||
| var conditionEvaluationOption = new Option<bool>("--eval-condition", description: "Advanced: evaluate branch condition with current model to avoid extra SMT solver queries"); | ||
| var incrementalityOption = new Option<bool>("--incrementality", description: "Advanced: enable SMT solver incremental mode"); | ||
|
|
||
| var rootCommand = new RootCommand(); | ||
|
|
||
| var entryPointCommand = | ||
|
|
@@ -131,66 +134,97 @@ public static int Main(string[] args) | |
| entryPointCommand.AddArgument(concreteArguments); | ||
| entryPointCommand.AddGlobalOption(outputOption); | ||
| entryPointCommand.AddOption(unknownArgsOption); | ||
| entryPointCommand.AddOption(constraintIndependenceOption); | ||
| entryPointCommand.AddOption(conditionEvaluationOption); | ||
| entryPointCommand.AddOption(incrementalityOption); | ||
|
|
||
| var allPublicMethodsCommand = | ||
| new Command("--all-public-methods", "Generate unit tests for all public methods of all public classes of assembly"); | ||
| rootCommand.AddCommand(allPublicMethodsCommand); | ||
| allPublicMethodsCommand.AddArgument(assemblyPathArgument); | ||
| allPublicMethodsCommand.AddGlobalOption(outputOption); | ||
| allPublicMethodsCommand.AddOption(constraintIndependenceOption); | ||
| allPublicMethodsCommand.AddOption(conditionEvaluationOption); | ||
| allPublicMethodsCommand.AddOption(incrementalityOption); | ||
|
|
||
| var publicMethodsOfClassCommand = | ||
| new Command("--public-methods-of-class", "Generate unit tests for all public methods of specified class"); | ||
| rootCommand.AddCommand(publicMethodsOfClassCommand); | ||
| var classArgument = new Argument<string>("class-name"); | ||
| publicMethodsOfClassCommand.AddArgument(classArgument); | ||
| publicMethodsOfClassCommand.AddArgument(assemblyPathArgument); | ||
| publicMethodsOfClassCommand.AddGlobalOption(outputOption); | ||
| publicMethodsOfClassCommand.AddOption(constraintIndependenceOption); | ||
| publicMethodsOfClassCommand.AddOption(conditionEvaluationOption); | ||
| publicMethodsOfClassCommand.AddOption(incrementalityOption); | ||
|
|
||
| var specificMethodCommand = | ||
| new Command("--method", "Try to resolve and generate unit test coverage for the specified method"); | ||
| rootCommand.AddCommand(specificMethodCommand); | ||
| var methodArgument = new Argument<string>("method-name"); | ||
| specificMethodCommand.AddArgument(methodArgument); | ||
| specificMethodCommand.AddArgument(assemblyPathArgument); | ||
| specificMethodCommand.AddGlobalOption(outputOption); | ||
| specificMethodCommand.AddOption(constraintIndependenceOption); | ||
| specificMethodCommand.AddOption(conditionEvaluationOption); | ||
| specificMethodCommand.AddOption(incrementalityOption); | ||
|
|
||
| rootCommand.Description = "Symbolic execution engine for .NET"; | ||
|
|
||
| entryPointCommand.Handler = CommandHandler.Create<FileInfo, string[], DirectoryInfo, bool>((assemblyPath, args, output, unknownArgs) => | ||
| { | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (unknownArgs) | ||
| args = null; | ||
| if (assembly != null) | ||
| PostProcess(TestGenerator.Cover(assembly, args, output.FullName)); | ||
| }); | ||
| allPublicMethodsCommand.Handler = CommandHandler.Create<FileInfo, DirectoryInfo>((assemblyPath, output) => | ||
| { | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (assembly != null) | ||
| PostProcess(TestGenerator.Cover(assembly, output.FullName)); | ||
| }); | ||
| publicMethodsOfClassCommand.Handler = CommandHandler.Create<string, FileInfo, DirectoryInfo>((className, assemblyPath, output) => | ||
| { | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (assembly != null) | ||
| entryPointCommand.Handler = CommandHandler.Create<FileInfo, string[], DirectoryInfo, bool, bool, bool, bool> | ||
| ( | ||
| (assemblyPath, args, output, unknownArgs, cIndependence, evalCondition, incrementality) => | ||
| { | ||
| var type = ResolveType(assembly, className); | ||
| if (type != null) | ||
| var options = new SvmOptions(cIndependence, evalCondition, incrementality); | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (unknownArgs) | ||
| args = null; | ||
| if (assembly != null) | ||
| PostProcess(TestGenerator.Cover(assembly, args, output.FullName, options)); | ||
| } | ||
| ); | ||
| allPublicMethodsCommand.Handler = CommandHandler.Create<FileInfo, DirectoryInfo, bool, bool, bool> | ||
| ( | ||
| (assemblyPath, output, cIndependence, evalCondition, incrementality) => | ||
| { | ||
| var options = new SvmOptions(cIndependence, evalCondition, incrementality); | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (assembly != null) | ||
| PostProcess(TestGenerator.Cover(assembly, output.FullName, options)); | ||
| } | ||
| ); | ||
| publicMethodsOfClassCommand.Handler = CommandHandler.Create<string, FileInfo, DirectoryInfo, bool, bool, bool> | ||
| ( | ||
| (className, assemblyPath, output, cIndependence, evalCondition, incrementality) => | ||
| { | ||
| var options = new SvmOptions(cIndependence, evalCondition, incrementality); | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (assembly != null) | ||
| { | ||
| PostProcess(TestGenerator.Cover(type, output.FullName)); | ||
| var type = ResolveType(assembly, className); | ||
| if (type != null) | ||
| { | ||
| PostProcess(TestGenerator.Cover(type, output.FullName, options)); | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| specificMethodCommand.Handler = CommandHandler.Create<string, FileInfo, DirectoryInfo>((methodName, assemblyPath, output) => | ||
| { | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (assembly != null) | ||
| ); | ||
| specificMethodCommand.Handler = CommandHandler.Create<string, FileInfo, DirectoryInfo, bool, bool, bool> | ||
| ( | ||
| (methodName, assemblyPath, output, cIndependence, evalCondition, incrementality) => | ||
| { | ||
| var method = ResolveMethod(assembly, methodName); | ||
| if (method != null) | ||
| var options = new SvmOptions(cIndependence, evalCondition, incrementality); | ||
| var assembly = ResolveAssembly(assemblyPath); | ||
| if (assembly != null) | ||
| { | ||
| PostProcess(TestGenerator.Cover(method, output.FullName)); | ||
| var method = ResolveMethod(assembly, methodName); | ||
| if (method != null) | ||
| { | ||
| PostProcess(TestGenerator.Cover(method, output.FullName, options)); | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| ); | ||
|
|
||
| return rootCommand.InvokeAsync(args).Result; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
этот файл надо смёржить с SILIOptions