public void ParallelWorkTestPasses() { var workManager = new WorkManager(); int result = 0; var work1 = SimpleWork.Create(() => result += 1); work1.Name = "simple work 1"; var work2 = WaitSecondsWork.Create(2); work2.Name = "wait work"; work2.ContinueWith((_) => result += 1); var work3 = SimpleWork.Create(() => result += 4); work3.Name = "simple work 2"; var paralleWork = ParallelWork.Create(work1, work2, work3); Assert.That(paralleWork.RunningWorks.Count, Is.EqualTo(3)); workManager.StartWork(paralleWork); workManager.Update(1, 1); Assert.That(result, Is.EqualTo(5)); Assert.That(paralleWork.RunningWorks.Count, Is.EqualTo(1)); Assert.That(paralleWork.CompleteWorks.Count, Is.EqualTo(2)); workManager.Update(1, 1); Assert.That(result, Is.EqualTo(6)); }
public void WaitForAllWork_should_return_immediately_if_no_work_queued() { var stopWatch = new Stopwatch(); "Given no work going on".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); }); var result = default(bool); "When WaitForAllWork is called".Do(() => { stopWatch.Start(); result = ParallelWork.WaitForAllWork(TimeSpan.FromSeconds(1)); }); "It should return immediately without going into any wait period".Assert(() => { Assert.True(stopWatch.Elapsed < TimeSpan.FromSeconds(1)); }); "It should return true".Assert(() => { Assert.True(result); }); }
private void ContentEditor_TextChanged(object sender, EventArgs e) { if (AutoRefreshCheckbox.IsChecked.Value) { if (!_RefreshDiagramTimerStarted) { _RefreshDiagramTimerStarted = true; ParallelWork.StartAfter(SaveAndRefreshDiagram, TimeSpan.FromSeconds( int.Parse(RefreshSecondsTextBox.Text))); } } }
//[Specification] //[STAThread] //public void IsAnyWorkRunning_should_return_true_only_if_some_thread_running() //{ // DateTime workStartedAt = default(DateTime); // TimeSpan waitDuration = TimeSpan.FromSeconds(2); // TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(1); // TimeSpan timeout = waitDuration.Add(howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500))); // DispatcherFrame frame = default(DispatcherFrame); // "Given a timed work queued that hasn't started yet".Context(() => // { // Assert.False(ParallelWork.IsWorkOrTimerQueued()); // frame = new DispatcherFrame(); // workStartedAt = default(DateTime); // ParallelWork.DoWorkAfter(() => // { // workStartedAt = DateTime.Now; // Thread.Sleep(howLongWorkTakes); // }, // () => // { // frame.Continue = false; // }, waitDuration); // }); // var result = default(bool); // "When IsAnyWorkRunning is called".Do(() => // { // result = ParallelWork.IsAnyWorkRunning(); // }); // "It should return false if the work hasn't started yet".Assert(() => // { // Assert.False(result); // Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); // }); // "It should return true when a work is still going on".Assert(() => // { // Dispatcher.PushFrame(frame); // Thread.Sleep(waitDuration); // Thread.Sleep(howLongWorkTakes.Milliseconds / 2); // Assert.NotEqual(default(DateTime), workStartedAt); // Assert.True(result); // Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); // }); //} private bool WaitForWorkDoneAndFireCallback(TimeSpan timeout, DispatcherFrame frame) { if (ParallelWork.WaitForAllWork(timeout)) { // Let the Disptacher.BeginInvoke calls proceed Dispatcher.PushFrame(frame); return(true); } else { // waiting timed out. Work did not finish on time. return(false); } }
private void Window_Loaded(object sender, RoutedEventArgs e) { if (!CheckGraphViz()) { this.Close(); return; } this.DiagramLocationTextBox.Text = string.IsNullOrEmpty(Settings.Default.LastPath) ? System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PlantUmlEditor\\samples\\") : Settings.Default.LastPath; // After a while check for new version ParallelWork.StartAfter(CheckForUpdate, TimeSpan.FromMinutes(1)); }
public void Should_fire_onprogress_on_UI_thread() { var onprogressMessages = new List <string>(); var callerThreadId = default(int); var onprogressCalledOnThreadId = default(int); var frame = default(DispatcherFrame); "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); callerThreadId = Thread.CurrentThread.ManagedThreadId; onprogressCalledOnThreadId = default(int); frame = new DispatcherFrame(); }); Func <int, string> getMessage = (progress) => "Message " + progress.ToString(); "When a parallel work is queued and onprogress callback is fired".Do(() => { Start.Work((onprogress) => { for (int i = 0; i < 10; i++) { Thread.Sleep(100); onprogress(getMessage(i), i); } }) .OnProgress((msg, progress) => { onprogressCalledOnThreadId = Thread.CurrentThread.ManagedThreadId; onprogressMessages.Add(msg); }) .OnComplete(() => { frame.Continue = false; }) .Run(); }); "It should fire onprogress callback on the UI thread".Assert(() => { WaitForWorkDoneAndFireCallback(TimeSpan.FromSeconds(5), frame); Assert.Equal(10, onprogressMessages.Count); Assert.Equal(callerThreadId, onprogressCalledOnThreadId); }); }
public void DoWork_should_return_objects_from_parallel_thread_to_callbacks() { TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(1); TimeSpan timeout = howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500)); DispatcherFrame frame = default(DispatcherFrame); "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); frame = new DispatcherFrame(); }); var test = default(Dictionary <string, string>); var output = default(Dictionary <string, string>); "When StartNow<> is called".Do(() => { Start <Dictionary <string, string> > .Work(() => { test = new Dictionary <string, string>(); test.Add("test", "test"); return(test); }) .OnComplete((result) => { output = result; frame.Continue = false; }) .Run(); }); @"It should return the object produced in separate thread and the object should be modifiable" .Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.True(output.ContainsKey("test")); Assert.DoesNotThrow(() => output.Add("another key", "another value")); }); }
public static void DoWorkInParallel(ParallelWork work, int numOfItemInTheFirstLoop) { int amountPartition = numOfItemInTheFirstLoop / threadCount; int totalItemInPartition = amountPartition * threadCount; int leftOver = numOfItemInTheFirstLoop - totalItemInPartition; //the leftover workload will be given to the first thread for (int i = 0; i < threadCount; i++) { int end = amountPartition * (i + 1) + (i != 0 ? leftOver : 0); //offset the ending for the rest of the thread int start = end - amountPartition; end += (i == 0 ? leftOver : 0); //add leftOver to the first thread 'after' assigning declaring so that 'start' will have value of 0 array[i] = new Thread(() => work(start, end)); array[i].Start(); } foreach (Thread thread in array) { thread.Join(); // Wait for all thread to finish } }
public static async Task Run(string accessToken) { var oneComputePlatformClient = new OneComputePlatformClient(ApiUrl, accessToken); // 2. Create Job Console.Write("Creating the job...."); var workItems = new List <WorkItem>(); for (var parallelTask = 0; parallelTask < NumWorkUnits; parallelTask++) { workItems.Add(new WorkUnit(new PiEstimateInput() { NumberOfSamples = NumSamplesPerWorkUnit })); } var reductionWorkUnit = new WorkUnit(); var work = new ParallelWork { WorkItems = workItems, ReductionTask = reductionWorkUnit }; var job = new Job { ServiceName = "PiCalc", Work = work, PoolId = "OneComputePlatformDemoPool" }; Console.WriteLine("Done"); // When running on a pool that does not have PiCalc pre-deployed, a DeploymentModel must be set that specifies that the PiCalc application // must be deployed for the job. In that case, uncomment the next 3 lines. var deploymentModel = new DeploymentModel(); deploymentModel.AddApplicationPackage("PiCalc"); job.DeploymentModel = deploymentModel; // 3. Submit job // Submit the job and return the monitor Console.Write("Submitting the job...."); var monitor = await oneComputePlatformClient.SubmitJobAsync(job); Console.WriteLine("Done"); // 4. Monitor Job // Set up callbacks on the job monitor to handle status and progress events. monitor.JobStatusChanged += async(s, e) => await JobStatusChanged(s, e); monitor.JobProgressChanged += JobProgressChanged; Console.WriteLine("Monitoring the job....."); await monitor.AwaitTerminationAsync(job.JobId); // Local callback handler for job status changed events // ReSharper disable StyleCop.SA1126 async Task JobStatusChanged(object sender, JobEventArgs jobEvent) { try { var jobStatusFlag = jobEvent.WorkStatus; var message = jobEvent.Message; switch (jobStatusFlag) { case WorkStatus.Faulted: message = $"Cloud job {job.JobId} faulted. Details: {message}"; Console.WriteLine($"{message}{Environment.NewLine}"); break; case WorkStatus.Aborted: Console.WriteLine($"Aborted{Environment.NewLine}"); break; case WorkStatus.Completed: Console.WriteLine($"JobStatusChanged - Completed!{Environment.NewLine}"); Console.WriteLine($"Retrieving results...{Environment.NewLine}"); // 5. Results retrieval var finalResultItem = await oneComputePlatformClient.GetWorkItemResult(job.JobId, reductionWorkUnit.Id); if (finalResultItem != null) { var finalResult = finalResultItem.GetResult <PiEstimateFinalResult>(); Console.WriteLine("FINAL RESULT"); Console.WriteLine($"PI = {finalResult.PI}"); Console.WriteLine($"Std. dev. = {finalResult.StandardDeviation:E1}"); Console.WriteLine($"Number of samples = {finalResult.TotalNumberOfSamples}"); Console.WriteLine($"Number within unit circle = {finalResult.TotalNumberWithinUnitCircle}"); } break; default: return; } // The job has now terminated - successfully or otherwise. Obtain the status record and write out the compute duration var jobStatusInfo = oneComputePlatformClient.GetJobStatus(job.JobId).GetAwaiter().GetResult(); if (jobStatusInfo != null) { Console.WriteLine($"Job completed at {jobStatusInfo.CompletionTime}{Environment.NewLine}"); Console.WriteLine($"Job total compute time {jobStatusInfo.TotalComputeSeconds} seconds{Environment.NewLine}"); Console.WriteLine("Press any key to exit..."); } } catch (Exception ex) { Console.WriteLine(ex.Message + ex.StackTrace); } } // Local callback handler for job progress update events void JobProgressChanged(object sender, JobEventArgs jobEvent) { var currentProgress = jobEvent.Progress * 100; var message = jobEvent.Message; Console.WriteLine($"JobProgressChanged => currentProgress={currentProgress} {message}"); } // And wait for response Console.WriteLine("Press any key to exit..."); Console.ReadKey(); }
public static Glyph[] ParseGlyf(ByteReader reader, int[] locaOffsets) { var glyphs = new Glyph[locaOffsets.Length - 1]; // Go through all glyphs and resolve them, leaving composite glyphs for later. var compositeGlyphParse = new List <CompositeGlyphRequest>(); ParallelWork.FastLoops(glyphs.Length, (start, end) => { for (int i = start; i < end; i++) { var current = new Glyph(); glyphs[i] = current; if (i > locaOffsets.Length) { continue; } int glyphOffset = locaOffsets[i]; int nextOffset = locaOffsets[i + 1]; // No data for glyph. if (glyphOffset == nextOffset || glyphOffset >= reader.Data.Length) { current.Vertices = new GlyphVertex[0]; continue; } ByteReader glyphData = reader.Branch(glyphOffset, true); int numberOfContours = glyphData.ReadShortBE(); current.XMin = glyphData.ReadShortBE(); current.YMin = glyphData.ReadShortBE(); current.XMax = glyphData.ReadShortBE(); current.YMax = glyphData.ReadShortBE(); // Non-composite if (numberOfContours > 0) { ResolveTtfGlyph(numberOfContours, glyphData, current); } // Composite else if (numberOfContours == -1) { lock (compositeGlyphParse) { compositeGlyphParse.Add(new CompositeGlyphRequest(glyphData, current)); } } // 0 is an invalid value. } }).Wait(); // ReSharper disable once ImplicitlyCapturedClosure ParallelWork.FastLoops(compositeGlyphParse.Count, (start, end) => { for (int i = start; i < end; i++) { CompositeGlyphRequest request = compositeGlyphParse[i]; ResolveCompositeTtfGlyph(request.Reader, request.Glyph, glyphs); } }); Debug.Assert(glyphs.All(x => x != null)); return(glyphs); }
public void StartNow_should_queue_a_new_thread_to_do_the_work() { TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(2); TimeSpan timeout = howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500)); var doWorkCalled = false; var successCallbackFired = false; var onExceptionFired = false; var doWorkThreadId = default(int); var onCompleteThreadId = default(int); var onExceptionThreadId = default(int); var letsThrowException = false; Stopwatch stopWatch = new Stopwatch(); DispatcherFrame frame = default(DispatcherFrame); Action callbackFiredOnDispatcher = () => { frame.Continue = false; // Dispatcher should stop now }; "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsWorkOrTimerQueued()); frame = new DispatcherFrame(); doWorkCalled = false; successCallbackFired = false; onExceptionFired = false; doWorkThreadId = default(int); onCompleteThreadId = default(int); onExceptionThreadId = default(int); stopWatch.Reset(); }); "When a new work is started by Start.Work().Run()".Do(() => { var shouldThrowException = letsThrowException; Start.Work(() => { doWorkThreadId = Thread.CurrentThread.ManagedThreadId; doWorkCalled = true; // Simulate some delay in background work Thread.Sleep(howLongWorkTakes); if (shouldThrowException) { throw new ApplicationException("Exception"); } }) .OnComplete(() => { onCompleteThreadId = Thread.CurrentThread.ManagedThreadId; successCallbackFired = true; callbackFiredOnDispatcher(); }) .OnException((x) => { onExceptionThreadId = Thread.CurrentThread.ManagedThreadId; onExceptionFired = true; callbackFiredOnDispatcher(); }) .Run(); stopWatch.Start(); }); "It should return control immediately without blocking the current thread".Assert(() => { Assert.True(stopWatch.Elapsed < howLongWorkTakes, string.Format("{0}<{1}", stopWatch.Elapsed, howLongWorkTakes)); Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); }); "It should return true if IsWorkQueued is called".Assert(() => { Assert.True(ParallelWork.IsWorkOrTimerQueued()); Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); }); "It should wait for the work to complete if WaitForAllWork is called".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); // The work should finish within the duration it takes with max 1 sec buffer // for additional stuff xunit does. Assert.True(stopWatch.Elapsed < howLongWorkTakes.Add(TimeSpan.FromSeconds(1))); }); "It should execute the work in a separate thread".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.True(doWorkCalled); Assert.NotEqual(Thread.CurrentThread.ManagedThreadId, doWorkThreadId); }); "It should fire onComplete on the same thread as the UI thread".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.True(successCallbackFired); Assert.Equal(Thread.CurrentThread.ManagedThreadId, onCompleteThreadId); }); "It should not fire onException if there's no exception".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.False(onExceptionFired); letsThrowException = true; // This is for next assert }); "It should fire exception on UI thread".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); Assert.False(successCallbackFired); Assert.True(onExceptionFired); Assert.Equal(Thread.CurrentThread.ManagedThreadId, onExceptionThreadId); }); }
/// <summary> /// Checks if there's a new version of the app and downloads and installs /// if user wants to. /// </summary> private void CheckForUpdate() { var me = new Weak <Window>(this); // Check if there's a newer version of the app Start <bool> .Work(() => { var versionFileName = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Settings.Default.VersionFileName); if (File.Exists(versionFileName)) { var localVersion = File.ReadAllText(versionFileName); return(UpdateChecker.HasUpdate(Settings.Default.VersionFileUrl, localVersion)); } else { return(true); } }) .OnComplete((hasUpdate) => { if (hasUpdate) { if (MessageBox.Show(Window.GetWindow(me), "There's a newer version available. Do you want to download and install?", "New version available", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) { ParallelWork.StartNow(() => { var tempPath = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Settings.Default.SetupExeName); UpdateChecker.DownloadLatestUpdate(Settings.Default.DownloadUrl, tempPath); }, () => { }, (x) => { MessageBox.Show(Window.GetWindow(me), "Download failed. When you run next time, it will try downloading again.", "Download failed", MessageBoxButton.OK, MessageBoxImage.Warning); }); } } }) .OnException((x) => { MessageBox.Show(Window.GetWindow(me), x.Message, "Download failed", MessageBoxButton.OK, MessageBoxImage.Exclamation); }) .Run(); UpdateChecker.DownloadCompleted = new Action <AsyncCompletedEventArgs>((e) => { Dispatcher.BeginInvoke(new Action(() => { if (e.Cancelled || e.Error != default(Exception)) { MessageBox.Show(Window.GetWindow(me), "Download failed. When you run next time, it will try downloading again.", "Download failed", MessageBoxButton.OK, MessageBoxImage.Warning); } else { Process.Start(UpdateChecker.DownloadedLocation).Dispose(); this.Close(); } })); }); UpdateChecker.DownloadProgressChanged = new Action <DownloadProgressChangedEventArgs>((e) => { Dispatcher.BeginInvoke(new Action(() => { this.StartProgress("New version downloaded " + e.ProgressPercentage + "%"); })); }); }
private static byte[] Parse(int scanlineLength, int scanlineCount, byte[] pureData, int bytesPerPixel, PngFileHeader header, ColorReader reader, int bytesPerPixelOutput) { var width = (int)header.Size.X; var height = (int)header.Size.Y; var pixels = new byte[width * height * bytesPerPixelOutput]; int length = scanlineLength - 1; var data = new Span <byte>(pureData); // Analyze if the scanlines can be read in parallel. byte filterMode = data[0]; for (var i = 0; i < scanlineCount; i++) { byte f = data[scanlineLength * i]; if (f == filterMode) { continue; } filterMode = byte.MaxValue; break; } // Multiple filters or a dependency filter are in affect. if (filterMode == byte.MaxValue || filterMode != 0 && filterMode != 1) { if (scanlineCount >= 1500) { Engine.Log.Trace("Loaded a big PNG with scanlines which require filtering. If you re-export it without filters, it will load faster.", MessageSource.ImagePng); } PerfProfiler.ProfilerEventStart("PNG Parse Sequential", "Loading"); var readOffset = 0; var previousScanline = Span <byte> .Empty; for (var i = 0; i < scanlineCount; i++) { // Early out for invalid data. if (data.Length - readOffset < scanlineLength) { break; } Span <byte> scanline = data.Slice(readOffset + 1, length); int filter = data[readOffset]; ApplyFilter(scanline, previousScanline, filter, bytesPerPixel); reader(width, ConvertBitArray(scanline, header), pixels, i); previousScanline = scanline; readOffset += scanlineLength; } PerfProfiler.ProfilerEventEnd("PNG Parse Sequential", "Loading"); return(pixels); } // Single line filter if (filterMode == 1) { PerfProfiler.ProfilerEventStart("PNG Parse Threaded", "Loading"); ParallelWork.FastLoops(scanlineCount, (start, end) => { int readOffset = start * scanlineLength; for (int i = start; i < end; i++) { // Early out for invalid data. if (pureData.Length - readOffset < scanlineLength) { break; } Span <byte> scanline = new Span <byte>(pureData).Slice(readOffset + 1, length); for (int j = bytesPerPixel; j < scanline.Length; j++) { scanline[j] = (byte)(scanline[j] + scanline[j - bytesPerPixel]); } reader(width, ConvertBitArray(scanline, header), pixels, i); readOffset += scanlineLength; } }).Wait(); PerfProfiler.ProfilerEventEnd("PNG Parse Threaded", "Loading"); } // No filter! // ReSharper disable once InvertIf if (filterMode == 0) { PerfProfiler.ProfilerEventStart("PNG Parse Threaded", "Loading"); ParallelWork.FastLoops(scanlineCount, (start, end) => { int readOffset = start * scanlineLength; for (int i = start; i < end; i++) { // Early out for invalid data. if (pureData.Length - readOffset < scanlineLength) { break; } Span <byte> row = ConvertBitArray(new Span <byte>(pureData).Slice(readOffset + 1, length), header); reader(width, row, pixels, i); readOffset += scanlineLength; } }).Wait(); PerfProfiler.ProfilerEventEnd("PNG Parse Threaded", "Loading"); } return(pixels); }
public void StopAllWork_should_stop_all_parallel_work() { DateTime work1StartedAt = default(DateTime); DateTime work2StartedAt = default(DateTime); DateTime work1EndedAt = default(DateTime); DateTime work2EndedAt = default(DateTime); TimeSpan waitDuration = TimeSpan.FromSeconds(2); TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(1); TimeSpan timeout = waitDuration.Add(howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500))); DispatcherFrame frame = default(DispatcherFrame); "Given some parallel work running".Context(() => { frame = new DispatcherFrame(); Start.Work(() => { work1StartedAt = DateTime.Now; Thread.Sleep(howLongWorkTakes); work1EndedAt = DateTime.Now; }) .OnComplete(() => { frame.Continue = false; }) .Run(); Start.Work(() => { work2StartedAt = DateTime.Now; Thread.Sleep(howLongWorkTakes); work2EndedAt = DateTime.Now; }) .OnComplete(() => { frame.Continue = false; }) .Run(); }); "When StopAllWork is called".Do(() => { // Let the work be half way through Thread.Sleep((int)howLongWorkTakes.TotalMilliseconds / 2); ParallelWork.StopAll(); }); "It should stop all work from completing".Assert(() => { // Confirm the work started Assert.NotEqual(default(DateTime), work1StartedAt); Assert.NotEqual(default(DateTime), work2StartedAt); // Confirm the work did not end Assert.Equal(default(DateTime), work1EndedAt); Assert.Equal(default(DateTime), work2EndedAt); Thread.Sleep(timeout); }); }
public void DoWorkAfter_should_execute_the_work_after_given_duration() { DateTime workStartedAt = default(DateTime); DateTime workCompletedAt = default(DateTime); DateTime countDownStartedAt = default(DateTime); TimeSpan waitDuration = TimeSpan.FromSeconds(2); TimeSpan howLongWorkTakes = TimeSpan.FromSeconds(1); TimeSpan timeout = waitDuration.Add(howLongWorkTakes.Add(TimeSpan.FromMilliseconds(500))); DispatcherFrame frame = default(DispatcherFrame); "Given no parallel work running".Context(() => { Assert.False(ParallelWork.IsAnyWorkRunning()); frame = new DispatcherFrame(); workStartedAt = default(DateTime); workCompletedAt = default(DateTime); }); "When Start.Work().RunAfter() is called".Do(() => { Start.Work(() => { workStartedAt = DateTime.Now; Thread.Sleep(howLongWorkTakes); }) .OnComplete(() => { workCompletedAt = DateTime.Now; frame.Continue = false; }) .RunAfter(waitDuration); countDownStartedAt = DateTime.Now; }); "It should not start the work until the duration has elapsed".Assert(() => { Assert.Equal(default(DateTime), workStartedAt); Assert.Equal(default(DateTime), workCompletedAt); Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); }); "It should start the work after duration has elapsed".Assert(() => { Assert.True(WaitForWorkDoneAndFireCallback(timeout, frame)); // Work should start within 500ms of start time DateTime expectedStartTime = countDownStartedAt.Add(waitDuration); Assert.InRange(workStartedAt, expectedStartTime, expectedStartTime.AddMilliseconds(500)); // Work should end within 500ms of expected end time DateTime expectedEndTime = countDownStartedAt.Add(waitDuration).Add(howLongWorkTakes); Assert.InRange(workCompletedAt, expectedEndTime, expectedEndTime.AddMilliseconds(500)); }); }
private static void Parse(byte[] data, PngFileHeader fileHeader, int bytesPerPixel, IColorReader reader, byte[] pixels) { // Find the scan line length. int scanlineLength = GetScanlineLength(fileHeader.Width, fileHeader) + 1; int scanLineCount = data.Length / scanlineLength; // Run through all scanlines. var cannotParallel = new List <int>(); ParallelWork.FastLoops(scanLineCount, (start, end) => { int readOffset = start * scanlineLength; for (int i = start; i < end; i++) { // Early out for invalid data. if (data.Length - readOffset < scanlineLength) { break; } // Get the current scanline. var rowData = new Span <byte>(data, readOffset + 1, scanlineLength - 1); int filter = data[readOffset]; readOffset += scanlineLength; // Check if it has a filter. // PNG filters require the previous row. // We can't do those in parallel. if (filter != 0) { lock (cannotParallel) { cannotParallel.Add(i); } continue; } reader.ReadScanline(rowData, pixels, fileHeader, i); } }).Wait(); if (cannotParallel.Count == 0) { return; } PerfProfiler.ProfilerEventStart("PNG Parse Sequential", "Loading"); // Run scanlines which couldn't be parallel processed. if (scanLineCount >= 2000) { Engine.Log.Trace("Loaded a big PNG with scanlines which require filtering. If you re-export it without that, it will load faster.", MessageSource.ImagePng); } cannotParallel.Sort(); for (var i = 0; i < cannotParallel.Count; i++) { int idx = cannotParallel[i]; int rowStart = idx * scanlineLength; Span <byte> prevRowData = idx == 0 ? null : new Span <byte>(data, (idx - 1) * scanlineLength + 1, scanlineLength - 1); var rowData = new Span <byte>(data, rowStart + 1, scanlineLength - 1); // Apply filter to the whole row. int filter = data[rowStart]; for (var column = 0; column < rowData.Length; column++) { rowData[column] = ApplyFilter(rowData, prevRowData, filter, column, bytesPerPixel); } reader.ReadScanline(rowData, pixels, fileHeader, idx); } PerfProfiler.ProfilerEventEnd("PNG Parse Sequential", "Loading"); }
private void SaveAndRefreshDiagram() { if (DesignerProperties.GetIsInDesignMode(this)) { return; } if (this.CurrentDiagram == default(DiagramFile)) { return; } _RefreshDiagramTimerStarted = false; var diagramFileName = this.CurrentDiagram.DiagramFilePath; var pathForContentEditor = ContentEditor.Tag as string; if (diagramFileName != pathForContentEditor) { MessageBox.Show(Window.GetWindow(this), "Aha! This is one of those weird race condition I am getting into." + Environment.NewLine + "Close the app and start again", "Weird race condition", MessageBoxButton.OK, MessageBoxImage.Error); return; } // Take a backup if this is the first time the diagram being modified // after opening if (_FirstSaveAfterOpen) { File.Copy(diagramFileName, diagramFileName.Replace(new FileInfo(diagramFileName).Extension, ".bak"), true); _FirstSaveAfterOpen = false; } var content = ContentEditor.Text; this.CurrentDiagram.Content = content; OnBeforeSave(this.CurrentDiagram); string plantUmlPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Thirdparty\\plantuml.exe"); if (!File.Exists(plantUmlPath)) { MessageBox.Show(Window.GetWindow(this), "Cannot find file: " + Environment.NewLine + plantUmlPath, "PlantUml.exe not found", MessageBoxButton.OK, MessageBoxImage.Error); return; } if (ParallelWork.IsAnyWorkRunning()) { return; } Start.Work(() => { // Save the diagram content using UTF-8 encoding to support // various international characters, which ASCII won't support // and Unicode won't make it cross platform File.WriteAllText(diagramFileName, content, Encoding.UTF8); // Use plantuml to generate the graph again using (var process = new Process()) { var startInfo = new ProcessStartInfo(); startInfo.FileName = plantUmlPath; startInfo.Arguments = "-charset UTF-8 -graphvizdot \"" + Settings.Default.GraphVizLocation + "\" \"" + diagramFileName + "\""; startInfo.WindowStyle = ProcessWindowStyle.Hidden; // OMAR: Trick #5 startInfo.CreateNoWindow = true; // OMAR: Trick #5 process.StartInfo = startInfo; if (process.Start()) { process.WaitForExit(10000); } } }) .OnComplete(() => { BindingOperations.GetBindingExpression(DiagramImage, Image.SourceProperty).UpdateTarget(); OnAfterSave(this.CurrentDiagram); }) .OnException((exception) => { OnAfterSave(this.CurrentDiagram); MessageBox.Show(Window.GetWindow(this), exception.Message, "Error running PlantUml", MessageBoxButton.OK, MessageBoxImage.Error); }) .Run(); }