예제 #1
0
    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));
    }
예제 #2
0
        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)));
         }
     }
 }
예제 #4
0
        //[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);
            }
        }
예제 #5
0
        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));
        }
예제 #6
0
        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);
            });
        }
예제 #7
0
        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
            }
        }
예제 #9
0
        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();
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
            });
        }
예제 #12
0
        /// <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 + "%");
                }));
            });
        }
예제 #13
0
        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);
        }
예제 #14
0
        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);
            });
        }
예제 #15
0
        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));
            });
        }
예제 #16
0
        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();
        }