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)