Job System not as fast as mine, why not?

Okay, I’m not sure why but I’m getting very varying results and I’ve also managed to make the time in the standalone job system worse no idea how. I have created an example project. Here’s my testing results.

In Editor:
Job System: ~400 ms
Mine: ~50 ms

Non Development Mono Build:
Job System: 120ms
Mine: ~400ms

Non Development IL2CPP 2018.1.0b9:
Job System: 250ms
Mine: 40ms

I have uploaded an entire project containing just the code in question.

Here is also just the code and the test image I have used. If you setup your own project, you’ll need to set the .NET to version 4 and restart unity and make the image uncompressed 4k with read write permissions and create a folder called Resources and put the image in there.
Code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Collections;
using Unity.Jobs;

public class Test : MonoBehaviour {

    System.Threading.Tasks.ParallelOptions options = new System.Threading.Tasks.ParallelOptions();
 
    void Start () {
        Time.timeScale = 0;

        options.MaxDegreeOfParallelism = System.Environment.ProcessorCount;

        Texture2D textureImage = GameObject.Instantiate(Resources.Load<Texture2D>("testimage"));

        byte[] spriteData = textureImage.GetRawTextureData();
        int width = textureImage.width;
        int height = textureImage.height;

        UnityEngine.UI.Text JobBenchText = GameObject.Find("JobBenchText").GetComponent<UnityEngine.UI.Text>();
        UnityEngine.UI.Text MyBenchText = GameObject.Find("MyBenchText").GetComponent<UnityEngine.UI.Text>();

        var Timer = new System.Diagnostics.Stopwatch();

        //Benchmark the Job System
        Timer.Start();
        var results = new NativeArray<int>(22000, Allocator.Persistent); //Using this as a phony results list
        var spriteDataNative = new NativeArray<byte>(spriteData, Allocator.Temp);

        var job = new DoJobSystemTest()
        {
            spriteData = spriteDataNative,
            results = results,
            width = width,
            height = height
        };

        JobHandle jobHandle = job.Schedule(width, 200);
        jobHandle.Complete();

        results.Dispose();
        spriteDataNative.Dispose();

        Timer.Stop();
        JobBenchText.text = Timer.Elapsed.ToString();

        //Benchmark My Parallel Processing
        Timer.Reset();
        Timer.Start();

        DoMyParallel(width, height, spriteData);

        Timer.Stop();
        MyBenchText.text = Timer.Elapsed.ToString();


        Time.timeScale = 1;
    }

    struct DoJobSystemTest : IJobParallelFor
    {
        [ReadOnly]
        public NativeArray<byte> spriteData;

        [ReadOnly]
        public int width;

        [ReadOnly]
        public int height;

        public NativeArray<int> results;

    

        public void Execute(int x)
        {

            byte colorA;
            byte colorB;
            int index;

            for (int y = 0; y < height;)
            {
                index = (x + y * width) * 4 + 3;
                colorA = spriteData[index];
                if (colorA != 0)
                {
                    if (y + 1 < height)
                    {
                        colorB = spriteData[index + width * 4];
                        if (colorB == 0)
                        {
                            //No NativeList at this time
                            //results[cpu].AddLast(x);
                            //results[cpu].AddLast(y);
                            y += 2;
                            continue;
                        }
                    }

                    if (y - 1 > 0)
                    {
                        colorB = spriteData[index - width * 4];
                        if (colorB == 0)
                        {
                            //No NativeList at this time
                            //results[cpu].AddLast(x);
                            //results[cpu].AddLast(y);
                            y++;
                            continue;
                        }
                    }

                    if (x + 1 < width)
                    {
                        colorB = spriteData[index + 4];
                        if (colorB == 0)
                        {
                            //No NativeList at this time
                            //results[cpu].AddLast(x);
                            //results[cpu].AddLast(y);
                            y++;
                            continue;
                        }
                    }

                    if (x - 1 > 0)
                    {
                        colorB = spriteData[index - 4];
                        if (colorB == 0)
                        {
                            //No NativeList at this time
                            //results[cpu].AddLast(x);
                            //results[cpu].AddLast(y);
                            y++;
                            continue;
                        }
                    }

                    y++;
                    continue;
                }
                else
                {
                    y++;
                }
            }
        }
    }

    void DoMyParallel(int width, int height, byte[] spriteData)
    {
        LinkedList<int>[] results = new LinkedList<int>[System.Environment.ProcessorCount];

        //Used for splitting up the width of the image between processors
        int[] splitCount = new int[System.Environment.ProcessorCount + 1];

        float count = (float)width / System.Environment.ProcessorCount;

        //for an amount that doesn't divide evenly add the left overs to the other processors batch
        for (int i = 1; i < Mathf.Round((count - (int)count) * System.Environment.ProcessorCount) + 1; i++)
        {
            splitCount[i] = 1;
        }

        //initialize the results linkedlist for each processor and add the batch amount to all processors
        for (int i = 0; i < System.Environment.ProcessorCount; i++)
        {
            results[i] = new LinkedList<int>();
            splitCount[i + 1] += (int)count + splitCount[i];
        }



        System.Threading.Tasks.Parallel.For(0, System.Environment.ProcessorCount, options, cpu =>
        {
            byte colorA;
            byte colorB;
            int index;
            for (int x = splitCount[cpu]; x < splitCount[cpu + 1]; x++)
            {

                for (int y = 0; y < height;)
                {
                    index = (x + y * width) * 4 + 3;
                    colorA = spriteData[index];
                    if (colorA != 0)
                    {
                        if (y + 1 < height)
                        {
                            colorB = spriteData[index + width * 4];
                            if (colorB == 0)
                            {
                                //results[cpu].AddLast(x);
                                //results[cpu].AddLast(y);
                                y += 2;
                                continue;
                            }
                        }

                        if (y - 1 > 0)
                        {
                            colorB = spriteData[index - width * 4];
                            if (colorB == 0)
                            {
                                //results[cpu].AddLast(x);
                                //results[cpu].AddLast(y);
                                y++;
                                continue;
                            }
                        }

                        if (x + 1 < width)
                        {
                            colorB = spriteData[index + 4];
                            if (colorB == 0)
                            {
                                //results[cpu].AddLast(x);
                                //results[cpu].AddLast(y);
                                y++;
                                continue;
                            }
                        }

                        if (x - 1 > 0)
                        {
                            colorB = spriteData[index - 4];
                            if (colorB == 0)
                            {
                                //results[cpu].AddLast(x);
                                //results[cpu].AddLast(y);
                                y++;
                                continue;
                            }
                        }

                        y++;
                        continue;
                    }
                    else
                    {
                        y++;
                    }
                }
            }
        });

        //Process the results

        //LinkedListNode<int> node;
    
        for (int cpu=0; cpu < System.Environment.ProcessorCount; cpu++)
        {
            /*node = results[cpu].First;
            for (int i = 0; i < results[cpu].Count; i+=2)
            {
                DoStuff(node.Value, node.Next.Value);
                node = node.Next.Next;
            }*/
            results[cpu].Clear();
        }
    }

    // Update is called once per frame
    void Update () {
    
    }
}

3402526–267864–ParallelBenchmark.zip (58.4 KB)

1 Like