#Burst Loop Investigation
1 messages · Page 1 of 1 (latest)
ok it's much weirder than i expected
public static TData Calculate<T, TData>(this ref DataHeader<TData> header, in EntityContext entityContext, ref T context)
where T : unmanaged, IContext<T>
where TData : unmanaged
{
return (DataType)header.Type switch
{
DataType.Default => default,
DataType.ScalarConstant => ScalarConstant.Calculate<T, TData>(ref Data<ScalarConstantData<TData>>(ref header)),
DataType.ScalarAdd => As(ScalarAdd.Calculate(ref Data<ScalarAddData>(ref header), in entityContext, ref context)),
DataType.ScalarMultiply => As(ScalarMultiply.Calculate(ref Data<ScalarMultiplyData>(ref header), in entityContext, ref context)),
DataType.QualifierAllOrNothing => As(QualifierAllOrNothing.Calculate(ref Data<QualifierAllOrNothingData>(ref header), in entityContext, ref context)),
// DataType.QualifierMinimumOrNothing => As(QualifierMinimumOrNothing.Calculate(ref Data<QualifierMinimumOrNothingData>(ref header), in entityContext, ref context)),
// DataType.QualifierSumAllAboveThreshold => As(QualifierSumAllAboveThreshold.Calculate(ref Data<QualifierSumAllAboveThresholdData>(ref header), in entityContext, ref context)),
// DataType.QualifierSumAll => As(QualifierSumAll.Calculate(ref Data<QualifierSumAllData>(ref header), in entityContext, ref context)),
DataType.QualifierSumWhileAboveThreshold => As(QualifierSumWhileAboveThreshold.Calculate(ref Data<QualifierSumWhileAboveThresholdData>(ref header), in entityContext, ref context)),
_ => context.DataGenerated(ref header, in entityContext, ref context),
};
static TData As<TFrom>(TFrom from)
where TFrom : unmanaged
{
return *(TData*)&from;
}
static ref TD Data<TD>(ref DataHeader<TData> header)
where TD : unmanaged
{
return ref UnsafeUtility.AsRef<TD>((byte*)UnsafeUtility.AddressOf(ref header) + sizeof(DataHeader<TData>));
}
}```
the 3 comment out lines are busted
the rest work fine
for example this works
public struct QualifierSumWhileAboveThresholdData
{
internal BlobArray<BlobPtr<DataHeader<float>>> Scorers;
internal BlobPtr<DataHeader<float>> Threshold;
}
/// <summary> Qualifier that sums all scores until one is no longer above the threshold then stops. </summary>
public static class QualifierSumWhileAboveThreshold
{
[DataNode((int)DataType.QualifierSumWhileAboveThreshold)]
public static float Calculate<T>(ref QualifierSumWhileAboveThresholdData data, in EntityContext entityContext, ref T context)
where T : unmanaged, IContext<T>
{
var sum = 0f;
var threshold = data.Threshold.Value.Calculate(in entityContext, ref context);
for (var i = 0; i < data.Scorers.Length; i++)
{
var score = data.Scorers[i].Value.Calculate(in entityContext, ref context);
if (score <= threshold)
{
return sum;
}
sum += score;
}
return sum;
}
}```
while this is busted and never finishes compiling
public struct QualifierSumAllAboveThresholdData
{
internal BlobArray<BlobPtr<DataHeader<float>>> Scorers;
internal BlobPtr<DataHeader<float>> Threshold;
}
/// <summary> Qualifier that sums all scores above the threshold. </summary>
public static class QualifierSumAllAboveThreshold
{
[DataNode((int)DataType.QualifierSumAllAboveThreshold)]
public static float Calculate<T>(ref QualifierSumAllAboveThresholdData data, in EntityContext entityContext, ref T context)
where T : unmanaged, IContext<T>
{
var sum = 0f;
var threshold = data.Threshold.Value.Calculate(in entityContext, ref context);
for (var i = 0; i < data.Scorers.Length; i++)
{
var score = data.Scorers[i].Value.Calculate(in entityContext, ref context);
if (score > threshold)
{
sum += score;
}
}
return sum;
}
}```
they're near identical
[BurstCompile]
public partial struct TestSystemJob : IJobEntity
{
public void Execute(ref TestComponent component)
{
var context = new TestContext();
component.Result = component.Blob.Value.Calculate(default, ref context);
}
}
public struct TestContext : IContext<TestContext>
{
public DynamicUntypedHashMap<short> GetState(int index)
{
return default;
}
}
public struct TestComponent : IComponentData
{
public BlobAssetReference<DataHeader<float>> Blob;
public float Result;
}```
well i've got standalone project repro down to this + 1 library assembly (rest deleted)
I don't seem to be able to reduce it anymore easily
so hopefully that'll be small enough
i bet it'll be fine
IN-96494
nice! great that you found it
well i didn't really find it as much as i'd like as it's still a, what the hell is going on
but i'm hoping it's enough that someone at unity can find it
it's actually kind of blocking me
i was hoping i could have at least found a workaround
burst maven has picked it up
QA confirmed it which is always a relief that it isn't some local problem
ok, after a bunch of trial and error I actually found a workaround
but it makes the original being busted even more confusing
replacing the above shown method
public static TData Calculate<T, TData>(this ref DataHeader<TData> header, in EntityContext entityContext, ref T context)
where T : unmanaged, IContext<T>
where TData : unmanaged
{```
with
```cs
public static TData Calculate<T, TData>(this ref DataHeader<TData> header, in EntityContext entityContext, ref T context)
where T : unmanaged, IContext<T>
where TData : unmanaged
{
return UnsafeUtility.As<DataHeader<TData>, DataHeader>(ref header).Calculate<T, TData>(entityContext, ref context);
}
private static TData Calculate<T, TData>(this ref DataHeader header, in EntityContext entityContext, ref T context)
where T : unmanaged, IContext<T>
where TData : unmanaged```
solves the issue
basically removing the generic header struct from the actual switch statement method
the actual generic struct has no generic fields or anything in it, it's purely there for some graph type safety in authoring
public struct DataHeader<T> : INode
where T : unmanaged
{
/// <summary> The unique data type. </summary>
public int Type;
internal int TypeHash;
}
public struct DataHeader
{
/// <summary> The unique data type. </summary>
public int Type;
internal int TypeHash;
}```
very odd