Never seen this pop in the profiler before… What is String.memcpy()? I am not using strings…
Not at all?
Strings in .NET are immutable, so even something as simple and as innocuous as:
Debug.Log("The value of the variable is " + myVariable);
Generates a memory copy operation.
There is also game object tags, name comparisons, repeat invoking, co-routines, and so on.
And then again, it may just be a smallish glitch in the profiler that has shown that in the past, but you don’t have sufficient other processing happening to swamp that value.
How much CPU was the memcpy using?
Does using the constructor of a Struct convert / use String.memcpy()?
EDIT: If I remove Vector2 Location from the Struct … String.memcpy() is not where to be found and function runs (deep profiling) in 1.76ms. If I add it back, String.memcpy() is back and function runs in 5.64ms.
So why does using the Vector2 using this string.memcpy()? Is it just because Vector2 has a ToString() function in it?
public struct Cell
{
public int x, y;
public Vector2 Location;
public byte Walls;
public float DistanceToTarget;
public Cell(int X, int Y)
{
x = X;
y = Y;
Location = new Vector2(X, Y);
Walls = 0;
DistanceToTarget = 0;
}
public Cell(Vector2 location)
{
x = (int)location.x;
y = (int)location.y;
Location = location;
Walls = 0;
DistanceToTarget = 0;
}
public Cell(int X, int Y, byte walls)
{
x = X;
y = Y;
Location = new Vector2(X, Y);
Walls = walls;
DistanceToTarget = 0;
}
}
public struct Cell
{
public int x, y;
public Vector2 Location;
Should you have a struct in a struct? I was under the impression that structs should contain base types only. Maybe you mean for Cell to be a class rather than a struct. I’m not clear why you have the location variable anyway when you already have x and y, which seem to be the same thing. It seems like a waste, especially in a struct. Likewise, do you really need a distance to target variable? Seems like something that should be computed as necessary.
–Eric
Depends on who you ask. MS best practice states that in the .NET environment, structs should be kept under 16 bytes and be immutable. Structs inside structs are not discouraged.
Rarely have I seen people follow “best practice.”
I’m confused as to why this particular struct will cause additional String.memcpy operations. Are you sure you aren’t implicitly converting it to a string somewhere?
Not sure if you all posted before I made the EDIT.
Looks like Vector2 is causing this String.memcpy().
In terms of having this Vector2 Location when I have X and Y, it was purely for convenience but apparently that came with a price.
With respect to storing DistanceToTarget, after an area is created, I have a function returning a list of cells with their relative distance to a target which never changes so it avoided having to recalculate the distance.
Right now, I was just experimenting in generating a path to a target. Learning / Trying difference ways when I ran into this String.memcpy() thing.
Are you sure the Vector2 isn’t being auto-serialized and displayed somewhere, like an inspector?
I checked it out, and merely using a struct in a struct causes this String.memcpy() thing. Not just Vector2, but any struct, including a custom bare-bones one. If you use a class instead of a struct, it doesn’t happen. Not sure what it means, or if it should happen, but probably staying away from structs in structs is a good idea for now.
–Eric
Thank you!
Any word on this from someone with knowledge on the guts and inner workings that cause this to happen?
I am using structs in structs in a perfectly “reasonable” way in the world of horrendously bad GC (generic structs in generic structs, actually, and if it wasn’t for the GC, I’d just use objects) and am seeing tons of these string function calls. They don’t take up much time compared to the actual work that is being done, but why they are there at all is quite troubling.
Unity 4.3.4 on OSX, btw.
Pure speculation:
I’m figuring the memcpy calls are a “worse is better” implementation detail that the Mono guys did in the early days when they were just trying to get a working runtime out the door. Certainly you’d rather copy bytes without a method call, but these probably get inlined on a JIT-able RT anyway. All the method calls could potentially be sapping performance on iOS though.
And I’m sure there is tons of worse is better code in the ancient Unity Mono build.
Reviving this old thread because I encountered the same String.memcpy in the profiler in Unity 2018.3. For me it had nothing to do with structs inside structs. I just had to keep the struct size no bigger than 40 bytes.
I am seeing the same thing and I have a feeling its to do with Matrix4x4, at least in my case
Can you give a example why you think it has something to do with Matrix4x4 ?
I mean i got it to on code that runs 100 calls in 0.45 ms (0.08 self) where 0.30 ms (0.05 self) is caused by this.
I dont got it on the code where i do anything with Matrix data.
Its because of where it was appearing. So this is the profiling sample that was showing the hit for me:
if (fromInstant)
UnityEngine.Profiling.Profiler.BeginSample("Bending");
if (block.basicBending)
{
bendingAxis.Add(new Vector2(1, 0));
bendingCenters.Add(new Vector3(x, y - 0.5f, z));
}
else
{
bendingCenters.Add(directionMatrix.MultiplyPoint3x4(block.bendingData.pivotOffset[i / block.bendingData.verticesPerSection]));//bendingCenters.Add(new Vector3(x, y - 0.5f, z) + offset + data.pivotOffset[i / data.verticesPerSection]);
Matrix4x4 bendingMatrix = Matrix4x4.TRS(LairMaths.zero, Quaternion.AngleAxis(rotationDegrees, LairMaths.up), LairMaths.one);//so rotate the axis only
Vector3 axis = new Vector3(block.bendingData.axis[i / block.bendingData.verticesPerSection].x, 0, block.bendingData.axis[i / block.bendingData.verticesPerSection].y);//expand the data
axis = bendingMatrix.MultiplyPoint3x4(axis);//rotate
bendingAxis.Add(new Vector2(axis.x, axis.z));//store
}
if (fromInstant)
UnityEngine.Profiling.Profiler.EndSample();
The main thing that is going on here is the Matrices. I doubt its adding to the lists since the rest of my code is heavy in the same operations and wasn’t seeing the spike.
Edit: also pretty sure the majority of the time this code was running the basic bending flag was false since I was also seeing the hit for the matrix math in general
I got it a where i use a name for a set of data in a class that in a list that a grab and make a instance of,
Will try to see if it helps if i remove it tomorrow.
Did sadly not get the string out of my class because its used to much troughout the program so far, i think i just got to live with it.
Same here. Lots of string.memcpy() on just a foreach() loop, x2 times each time I start each loop.
This must be a problem with data copy in structs. I removed the error by avoiding accessing a struct on an array by doing
var value = array
I used array everywhere instead, and it was faster and no String.memcpy()
You probably saw the speed increase because of things covered in this blog:
Structs have the potential to perform better if used properly but it of course all depends on your data:
If your only using 1 array then sure your arrays will be faster, but you could beat arrays if you change your structure to be more tightly controlled for the cache access (So if your struct has only 3 values it could be faster than looking up 3 different arrays, if your struct has 20 or so values its likely slower).
Sorry to bump on old thread, but what exactly is this issue? I did some profiling and found some strange results.
Here is my test script:
https://gist.github.com/prodigga/d2f77012678535bd38cf60817f164886
Here are some benchmarks:
-
Using Struct
-
Array of values
-
Test1 (Local Copy) 83ms
-
Test2 (Direct access) 19ms
-
List of values
-
Test1 (Local Copy) 126ms
-
Test2 (Direct access) 88ms
-
Using Class
-
Array of values
-
Test1 (Local Copy) 19ms
-
Test2 (Direct access) 19ms
-
List of values
-
Test1 (Local Copy) 24ms
-
__Test2 (Direct access)__24ms
Using structs is immensely slower, and it seems to be related to the size of the struct. The bigger your struct, the worse the performance.
However, for some reason, structs perform just as well as classes if you are using arrays and you are using the value ‘directly’… That is, myArray_.property
instead of var element = myArray*; element.property...
.*_
If I reduce the member count down to just a single Vector3, then the performance is similar between structs/classes. But that’s pretty restricting. I am doing some processing on some polygons, and for each vertex I am storing position, normal, tangent and bitangent for later use. This is making my code run much slower compared to just using classes. This doesnt feel right. Is this… ‘expected’ behaviour… ? Are structs really supposed to be this much slower?
Benchmark reveals that the slowdown is due to String.memcpy.