Files
Misaki.HighPerformance/Misaki.HighPerformance.Jobs/JobInfo.cs

170 lines
4.7 KiB
C#

using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Misaki.HighPerformance.Jobs;
/// <summary>
/// The state of a job in its lifecycle.
/// </summary>
public enum JobState
{
/// <summary>
/// The job is in an invalid state, indicating an error or uninitialized state.
/// </summary>
Invalid = -1,
/// <summary>
/// The job has been created but not yet scheduled for execution.
/// </summary>
Created = 0,
/// <summary>
/// The job is scheduled and waiting to be executed.
/// </summary>
Scheduled = 1,
/// <summary>
/// The job is currently being executed.
/// </summary>
Running = 2,
/// <summary>
/// The job has completed execution.
/// </summary>
Completed = 3
}
internal enum HeapType
{
Native,
Managed,
}
internal unsafe struct JobInfo
{
public ref struct DependentIterator
{
private readonly ref JobInfo _jobInfo;
private int _index;
public DependentIterator(ref JobInfo jobInfo)
{
_jobInfo = ref jobInfo;
_index = -1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
_index++;
return _index < _jobInfo.dependentCount;
}
public JobHandle Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (_index < MAX_DEPENDENTS)
{
return new JobHandle(_jobInfo.dependentsID[_index], _jobInfo.dependentsGeneration[_index]);
}
else
{
return _jobInfo.additionalDependents[_index - MAX_DEPENDENTS];
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
_index = -1;
}
}
public const int MAX_DEPENDENTS = 8;
// The list of jobs that are waiting for THIS job to complete.
public fixed int dependentsID[MAX_DEPENDENTS]; // The actual list of IDs
public fixed int dependentsGeneration[MAX_DEPENDENTS]; // The actual list of generations
public UnsafeList<JobHandle> additionalDependents;
public int dependentCount;
public JobRanges jobRanges;
public void* pJobData;
public JobExecutionFunc pExecutionFunc;
public int state;
public int remainingBatches;
public int threadIndex; // The preferred thread index to run this job on, -1 means any thread
public int dependencyCount; // Numbers of jobs that this job depends on, when it reaches 0, the job can be executed
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[UnscopedRef]
public DependentIterator GetDependentIterator()
{
return new DependentIterator(ref this);
}
}
internal struct JobRanges
{
public int batchSize;
public int totalIteration;
public int currentIndex;
public static JobRanges Single => new()
{
batchSize = 1,
totalIteration = 1,
currentIndex = 0,
};
}
internal static class JobUtility
{
// Lock-Free constants: State mask (low 16 bits) and RC unit (1 << 16)
public const int STATE_MASK = 0xFFFF;
public const int RC_ONE = 0x10000;
public const int JOBSTATE_INVALID = (int)JobState.Invalid & STATE_MASK;
public const int JOBSTATE_CREATED = (int)JobState.Created & STATE_MASK;
public const int JOBSTATE_SCHEDULED = (int)JobState.Scheduled & STATE_MASK;
public const int JOBSTATE_RUNNING = (int)JobState.Running & STATE_MASK;
public const int JOBSTATE_COMPLETED = (int)JobState.Completed & STATE_MASK;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static JobState ReadState(ref JobInfo jobInfo)
{
var stateVal = Volatile.Read(ref jobInfo.state);
return (JobState)(stateVal & STATE_MASK);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ReadStateValue(ref JobInfo jobInfo)
{
var stateVal = Volatile.Read(ref jobInfo.state);
return stateVal & STATE_MASK;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetStateValue(JobState state)
{
return (int)state & STATE_MASK;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static JobState GetState(int value)
{
return (JobState)(value & STATE_MASK);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReleaseRC(ref int jobState)
{
Interlocked.Add(ref jobState, -RC_ONE);
}
}