// Entry point public static int Main(string[] args, ISimpleLineWriter output) { var start = DateTime.Now; var slicingOptions = new SlicingOptions(args); // we use it to parse the clousot options, and to split the work var clousot = new NewCCI2Driver(slicingOptions.remainingArgs.ToArray(), output); if (!clousot.CheckOptions()) { return(-1); } var errorCode = 0; WorkerPool workerPool = null; IQueue queue = null; IWorkerFactory localWorkerFactory = null; List <IWorkerFactory> remoteWorkerFactories = null; Func <SliceDefinition, ISliceWorkResult> workOnSlice = null; Dictionary <ISliceId, int> failedRegressions = null; var localWorkers = slicingOptions.LocalWorkers; var remoteWorkers = slicingOptions.RemoteWorkers; var workers = localWorkers + remoteWorkers; // If we have workers, we create a Worker factory if (workers > 0) { IDB db; if (remoteWorkers > 0 || clousot.options.useCache) { // Use Clousot Database db = new StdDB(clousot.options); } else { // In-memory database db = new MemorySingletonDB(); } workerPool = new WorkerPool("Worker", canCancel: false); queue = new FIFOQueue(workerPool, db); // When a job is done, it choses which jobs to put in the queue (e.g., analyze the dependencies) var scheduler = clousot.options.InferObjectInvariantsOnlyForReadonlyFields? new LazySchedulerForObjectInvariants(queue, db) : // use LazySchedulerForObjectInvariants for global fixpoint computation including object invariants new LazyScheduler(queue, db); // use LazyScheduler for the global fixpoint computation //var scheduler = new NoloopScheduler(queue); // Usual cache var clousotDB = slicingOptions.useDB ? db : null; var argsForWorker = clousot.argsForWorker.ToFList(); if (localWorkers > 0) { if (slicingOptions.cci1) { localWorkerFactory = new Clousot1WorkerFactory(scheduler, argsForWorker, output, clousotDB); } else { localWorkerFactory = new Clousot2WorkerFactory(scheduler, argsForWorker, output, clousotDB); } // TODO: use a lighter version of ClousotMain since options are already checked here } if (remoteWorkers > 0) // so far 1 factory per remote worker but we can do better { // TODO: specifiy, for each address the number of workers // We have a list, because we can have several addresses remoteWorkerFactories = slicingOptions.serviceAddress.Select(addr => new Clousot2SWorkerFactory(scheduler, argsForWorker, output, addr)).ToList <IWorkerFactory>(); } if (clousot.options.IsRegression) { failedRegressions = new Dictionary <ISliceId, int>(); } // fail if any work fails scheduler.OnWorkDone += (sliceId, returnCode) => { if (errorCode >= 0) { if (returnCode < 0) // special error code, keep only one { errorCode = returnCode; } else { int prevValue; if (clousot.options.IsRegression) { lock (failedRegressions) { Contract.Assume(failedRegressions != null); if (failedRegressions.TryGetValue(sliceId, out prevValue)) { output.WriteLine("[Regression] We already analyzed {0} with outcome {1}. Now we update the outcome to {2}", sliceId.Dll, prevValue, returnCode); } failedRegressions[sliceId] = returnCode; } } errorCode += returnCode; // regression error count, additive } } }; // What we do for each slice. Two things: // 1. Register the slice in the db // 2. Add to the queue (via the scheduler, who decides how to do it) workOnSlice = sliceDef => { var sliceId = db.RegisterSlice(sliceDef); scheduler.FeedQueue(new ISliceId[] { sliceId }); return(null); }; } ISlicerResult slicerResult = null; if (slicingOptions.sliceFirst) { slicerResult = clousot.SplitWork(workOnSlice); output.WriteLine("Slicing time: {0}", DateTime.Now - start); } if (workerPool != null) { if (localWorkerFactory != null) { for (var i = 0; i < localWorkers; i++) { workerPool.CreateWorker(localWorkerFactory); } } if (remoteWorkerFactories != null) { foreach (var factory in remoteWorkerFactories) { workerPool.CreateWorker(factory); } } } if (!slicingOptions.sliceFirst) { slicerResult = clousot.SplitWork(workOnSlice); output.WriteLine("Slicing time and thread creation time : {0}", DateTime.Now - start); } if (workerPool != null) { // workerPool != null ==> queue != null Contract.Assume(queue != null); workerPool.WaitAllAnd(queue.EmptyQueueWaitHandle); // Something else can arrive at the queue, so we want to stop all of them workerPool.StopAll(); } if (slicerResult != null) { var errors = slicerResult.GetErrors(); if (errors.Any()) { foreach (var errMessage in errors) { output.WriteLine(errMessage); } errorCode = errors.Count(); } } output.WriteLine("Total analysis time: {0}", DateTime.Now - start); var returnValue = errorCode; if (failedRegressions != null && clousot.options.IsRegression && errorCode >= 0) { returnValue = failedRegressions.Where(pair => pair.Value != 0).Select(pair => Math.Abs(pair.Value)).Sum(); } #if DEBUG if (clousot.options.IsRegression) { Console.WriteLine("[Regression] Returned value {0}", returnValue); } #endif return(returnValue); }
// Entry point public static int Main(string[] args, ISimpleLineWriter output) { var start = DateTime.Now; var slicingOptions = new SlicingOptions(args); // we use it to parse the clousot options, and to split the work var clousot = new NewCCI2Driver(slicingOptions.remainingArgs.ToArray(), output); if (!clousot.CheckOptions()) { return -1; } var errorCode = 0; WorkerPool workerPool = null; IQueue queue = null; IWorkerFactory localWorkerFactory = null; List<IWorkerFactory> remoteWorkerFactories = null; Func<SliceDefinition, ISliceWorkResult> workOnSlice = null; Dictionary<ISliceId, int> failedRegressions = null; var localWorkers = slicingOptions.LocalWorkers; var remoteWorkers = slicingOptions.RemoteWorkers; var workers = localWorkers + remoteWorkers; // If we have workers, we create a Worker factory if (workers > 0) { IDB db; if (remoteWorkers > 0 || clousot.options.useCache) { // Use Clousot Database db = new StdDB(clousot.options); } else { // In-memory database db = new MemorySingletonDB(); } workerPool = new WorkerPool("Worker", canCancel: false); queue = new FIFOQueue(workerPool, db); // When a job is done, it choses which jobs to put in the queue (e.g., analyze the dependencies) var scheduler = clousot.options.InferObjectInvariantsOnlyForReadonlyFields? new LazySchedulerForObjectInvariants(queue, db) : // use LazySchedulerForObjectInvariants for global fixpoint computation including object invariants new LazyScheduler(queue, db); // use LazyScheduler for the global fixpoint computation //var scheduler = new NoloopScheduler(queue); // Usual cache var clousotDB = slicingOptions.useDB ? db : null; var argsForWorker = clousot.argsForWorker.ToFList(); if (localWorkers > 0) { if (slicingOptions.cci1) localWorkerFactory = new Clousot1WorkerFactory(scheduler, argsForWorker, output, clousotDB); else localWorkerFactory = new Clousot2WorkerFactory(scheduler, argsForWorker, output, clousotDB); // TODO: use a lighter version of ClousotMain since options are already checked here } if (remoteWorkers > 0) // so far 1 factory per remote worker but we can do better { // TODO: specifiy, for each address the number of workers // We have a list, because we can have several addresses remoteWorkerFactories = slicingOptions.serviceAddress.Select(addr => new Clousot2SWorkerFactory(scheduler, argsForWorker, output, addr)).ToList<IWorkerFactory>(); } if (clousot.options.IsRegression) { failedRegressions = new Dictionary<ISliceId, int>(); } // fail if any work fails scheduler.OnWorkDone += (sliceId, returnCode) => { if (errorCode >= 0) { if (returnCode < 0) // special error code, keep only one { errorCode = returnCode; } else { int prevValue; if (clousot.options.IsRegression) { lock (failedRegressions) { Contract.Assume(failedRegressions != null); if (failedRegressions.TryGetValue(sliceId, out prevValue)) { output.WriteLine("[Regression] We already analyzed {0} with outcome {1}. Now we update the outcome to {2}", sliceId.Dll, prevValue, returnCode); } failedRegressions[sliceId] = returnCode; } } errorCode += returnCode; // regression error count, additive } } }; // What we do for each slice. Two things: // 1. Register the slice in the db // 2. Add to the queue (via the scheduler, who decides how to do it) workOnSlice = sliceDef => { var sliceId = db.RegisterSlice(sliceDef); scheduler.FeedQueue(new ISliceId[] { sliceId }); return null; }; } ISlicerResult slicerResult = null; if (slicingOptions.sliceFirst) { slicerResult = clousot.SplitWork(workOnSlice); output.WriteLine("Slicing time: {0}", DateTime.Now - start); } if (workerPool != null) { if (localWorkerFactory != null) for (var i = 0; i < localWorkers; i++) workerPool.CreateWorker(localWorkerFactory); if (remoteWorkerFactories != null) foreach (var factory in remoteWorkerFactories) workerPool.CreateWorker(factory); } if (!slicingOptions.sliceFirst) { slicerResult = clousot.SplitWork(workOnSlice); output.WriteLine("Slicing time and thread creation time : {0}", DateTime.Now - start); } if (workerPool != null) { // workerPool != null ==> queue != null Contract.Assume(queue != null); workerPool.WaitAllAnd(queue.EmptyQueueWaitHandle); // Something else can arrive at the queue, so we want to stop all of them workerPool.StopAll(); } if (slicerResult != null) { var errors = slicerResult.GetErrors(); if (errors.Any()) { foreach (var errMessage in errors) output.WriteLine(errMessage); errorCode = errors.Count(); } } output.WriteLine("Total analysis time: {0}", DateTime.Now - start); var returnValue = errorCode; if (failedRegressions != null && clousot.options.IsRegression && errorCode >= 0) { returnValue = failedRegressions.Where(pair => pair.Value != 0).Select(pair => Math.Abs(pair.Value)).Sum(); } #if DEBUG if (clousot.options.IsRegression) { Console.WriteLine("[Regression] Returned value {0}", returnValue); } #endif return returnValue; }