Good morning, afternoon or night,
Foreword: The code below does nothing really useful. It is just for explanation purposes.
Is there anything wrong with allocating and using an array "the safe mode" inside unsafe code? For example, should I write my code as
public static unsafe uint[] Test (uint[] firstParam, uint[] secondParam)
{
fixed (uint * first = firstParam, second = secondParam)
{
uint[] Result = new uint[firstParam.Length + secondParam.Length];
for (int IndTmp = 0; IndTmp < firstParam.Length; Result[IndTmp] = *(first + IndTmp++));
for (int IndTmp = 0; IndTmp < secondParam.Length; Result[IndTmp + firstParam.Length] = *(second + IndTmp++);
return Result;
}
}
or should I instead write a separate, unsafe method accepting only pointers and lengths as parameters and use it in the main function?
Also, is there any way I can replace the allocation with
uint * Result = stackalloc uint[firstParam.Length + secondParam.Length]
so that I can use Result as a pointer and still be able to return Result as an uint[]?
Thank you very much.
I see nothing wrong with doing that, although if you're using pointers for speed, it probably makes sense to use a pointer into Result also. Maybe like this:
public static unsafe uint[] Test (uint[] firstParam, uint[] secondParam)
{
uint[] Result = new uint[firstParam.Length + secondParam.Length];
fixed (uint * first = firstParam, second = secondParam, res = Result)
{
for (int IndTmp = 0; IndTmp < firstParam.Length; IndTmp++)
*(res + IndTmp) = *(first + IndTmp);
res += firstParam.Length;
for (int IndTmp = 0; IndTmp < secondParam.Length; IndTmp++)
*(res + IndTmp) = *(second + IndTmp++);
}
return Result;
}
DO NOT return anything you stackalloc! Once the function returns, the area allocated on the stack is reused, giving you an invalid pointer.
Related
I am writing some code on geometry processing, delaunay triangulation to be more specific, and I need it to be fast, so I use simple arrays of primitive as data structure to represent my triangulation information, here is a sample of it
private readonly float2[] points;
private readonly int[] pointsHalfEdgeStartCount;
private readonly int[] pointsIncomingHalfEdgeIndexes;
So let's say I want to iterate fast through all the incoming half-edge of the point of index p, I just do this using the precomputed arrays:
int count = pointsHalfEdgeStartCount[p * 2 + 1];
for (int i = 0; i < count; i++)
{
var e = pointsIncomingHalfEdgeIndexes[pointsHalfEdgeStartCount[p * 2] + i]
}
// pointsHalfEdgeStartCount[p * 2] is the start index
And this is fast enought, but does not feel safe or very clear. So I had the idea of wrapping my index into struct to make it clearer while retaining the performance, somthing like that:
public readonly struct Point
{
public readonly int index;
public readonly DelaunayTriangulation delaunay
public Point(int index, DelaunayTriangulation delaunay)
{
this.index = index;
this.delaunay = delaunay;
}
public int GetIncomingHalfEdgeCount() => delaunay.pointsEdgeStartCount[index * 2 + 1];
public HalfEdge GetIncomingHalfEdge(int i)
{
return new HalfEdge(
delaunay,
delaunay.pointsIncomingHalfEdgeIndexes[delaunay.pointsEdgeStartCount[index * 2] + i]
);
}
//... other methods
}
Then I can just do so:
int count = p.GetIncomingHalfEdgeCount();
for (int i = 0; i < count; i++)
{
var e = p.GetIncomingHalfEdge(i);
}
However it was kind of killing my performance, being a lot slower (around 10 times) on a benchmark I did, iterating over all the points and iterating over all their incoming half-edge. I guess because storing a reference to the delaunay triangulaiton in each point struct was an obvious waste and slowed down all the operations involving points, having twice the amount of data to move.
I could make the DelaunayTriangulation a static class but it was not practical for other reasons, so I did that:
public readonly struct Point
{
public readonly int index;
public Point(int index) => this.index = index;
public int GetIncomingHalfEdgeCount(DelaunayTriangulation delaunay) => delaunay.pointsEdgeStartCount[index * 2 + 1];
public HalfEdge GetIncomingHalfEdge(DelaunayTriangulation delaunay, int i)
{
return new HalfEdge(
delaunay.pointsIncomingHalfEdgeIndexes[delaunay.pointsEdgeStartCount[index * 2] + i]
);
}
//... other methods
}
I can just do so:
int count = p.GetIncomingHalfEdgeCount(delaunay);
for (int i = 0; i < count; i++)
{
var e = p.GetIncomingHalfEdge(delaunay, i);
}
It was quite a lot faster, but still 2.5 times slower than the first method using simple int. I wondered if it could be because I was getting int in the first method while I got HalfEdge struct in the other methods (A struct similar to the Point struct, contains only an index as data and a couple of methods), and difference between plain int and the faster struct vanished when I used the e int to instantiate a new HalfEdge struct. Though I am not sure why is that so costly.Weirder still, I explored for clarity sake the option of wrinting the method inside the Delaunay class instead of the Point struct:
// In the DelaunayTriangulation class:
public int GetPointIncomingHalfEdgeCount(Point p) => pointsEdgeStartCount[p.index * 2 + 1];
public HalfEdge GetPointIncomingHalfEdge(Point p, int i)
{
return new HalfEdge(
pointsIncomingHalfEdgeIndexes[pointsEdgeStartCount[p.index * 2] + i]
);
}
And I used it like this:
int count = delaunay.GetPointIncomingHalfEdgeCount(p);
for (int i = 0; i < count; i++)
{
var e = delaunay.GetPointIncomingHalfEdge(p, i);
}
And it was 3 times slower than the previous method! I have no idea why.
I tried to use disassembly to see what machine code was generated but I failed to do so (I am working with Unity3D). Am I condemned to rely on plain int in arrays and sane variable naming and to renounce on trying to have some compile-time type checking (is this int really a point index ?)
I am not even bringing up other questions such as, why it is even slower when I try to use IEnumerable types with yields like so:
public IEnumerable<int> GetPointIncomingHalfEdges(Point p)
{
int start = pointsEdgeStartCount[p.index * 2]; // this should be a slight optimization right ?
int count = pointsEdgeStartCount[p.index * 2 + 1];
for (int i = 0; i < count; i++)
{
yield pointsIncomingHalfEdgeIndexes[start + i];
}
}
I have added a compiler directive for aggressive inlining and it seems to make up for the discrepencies in time! For some reason the compiler fails to inline correctly for:
var e = delaunay.GetPointIncomingHalfEdge(p, i);
While it managed to do so with
var e = p.GetIncomingHalfEdge(delaunay, i);
Why ? I do not know. However It would be far easier if I was able to see how the code is compiled and I could not find how to do that. I will search that, maybe open another question and if I find a better explaination I will come back!
internal double[] fillingArray()
{
a = 1.5;
b = .5;
for (i = 0; i<10; i++)
{
c = a * b;
a = a + 1;
b = b + 1;
arrayInt[i] = c;
}
return arrayInt;
}
I wanted to call a method fillingArray() which stores array variables and display those variables via displayAll() main method.
When arrayInt is returned, console displays system.Double but not the values inside the array.
You need to parse each value like with the filling function:
static void Test()
{
Display(CreateFilledArray());
}
static internal void Display(double[] array)
{
foreach ( var value in array )
Console.WriteLine(value);
}
static internal double[] CreateFilledArray()
{
var result = new double[10];
double a = 1.5;
double b = .5;
for ( int index = 0; index < 10; index++ )
{
result[index] = a * b;
a = a + 1;
b = b + 1;
}
return result;
}
Output
0,75
3,75
8,75
15,75
24,75
35,75
48,75
63,75
80,75
99,75
I get the feeling that you're doing something like this:
Console.WriteLine(arrayInt);
And expecting it to show a representation of all the numbers in the array. C# doesn't do that; it will just print out the type of the array, which is System.Double[]
what is actually happening here is that WriteLine can only write "sensible looking things" it if it's something it can specifically handle. WriteLine can handle lots of different things:
Console.WriteLine(1); //handles numbers
Console.WriteLine('1'); //handles characters
Console.WriteLine("1"); //handles strings
WriteLine cannot handle arrays; they get passed to the version of WriteLine that handles Objects, and the only thing that that version of WriteLine does is call ToString() on the object that is passed in and then print the string result that ToString returns. When we call ToString on an array, it just returns the kind of array it is, not the values in the array
This is why you see "System.Double[]" appear in the console
Youll have to loop over the array printing the values out one by one (there are other tricks you can do, but they're more advanced c# than you know currently and it would not be wise to recommend them if this is an academic assignment)
I can see you know how to loop, so I'll leave the implementing of it up to you
I modified the method to string and returned a string value concatenating values of array -- this worked
internal string fillingArray()
{
a = 1.5;
b = .5;
for (i = 0; i<10; i++)
{
c = a * b;
a = a + 1;
b = b + 1;
arrayInt[i] = c;
//astr array string
astr = astr + arrayInt[i].ToString() + " ";
}
return astr;
in this code i am trying to simulate a task that populats an array of structs,
...unsafe to get as much throughoutput as can be achived.
the issue is that i when calling the fucntion and itterating on the result
shows different characters but within the scope of GetSomeTs() it's fine.
so just before the return i test one of the elements and it prints the correct value.
this is the testing struct.
public unsafe struct T1
{
public char* block = stackalloc char[5];<--will not compile so the process will be done within a local variable inside a method
}
public unsafe struct T1
{
public char* block;
}
static unsafe T1[] GetSomeTs(int ArrSz)
{
char[] SomeValChars = { 'a', 'b', 'c', 'd', 'e' };
T1[] RtT1Arr = new T1[ArrSz];
for (int i = 0; i < RtT1Arr.Length; i++)
{
char* tmpCap = stackalloc char[5];
for (int l = 0; l < 5; l++)
{
SomeValChars[4] = i.ToString()[0];
tmpCap[l] = SomeValChars[l];
}
RtT1Arr[i].block = tmpCap;//try 1
//arr[i].block = &tmpCap[0];//try 2
}
// here its fine
Console.WriteLine("{0}", new string(RtT1Arr[1].block));
return RtT1Arr;
}
but using it anywhere else printing garbage.
void Main()
{
T1[] tstT1 = GetSomeTs(10);
for (int i = 0; i < 10; i++)
{
Console.WriteLine("{0}", new string(tstT1[i].block));//,0,5, Encoding.Default));
}
}
When you allocate memory with stackalloc that memory only exists until the function returns in which you have allocated it. You are returning a pointer to memory that is no longer allowed to be accessed.
Hard to recommend a fix because it's unclear what you want to achieve. Probably, you should just use a managed char[].
Encoding.Default.GetBytes is pretty slow so that's likely to be your hotspot anyway and the rest is less important. i.ToString() also is quite slow and produces garbage. If you are after perf then stop creating unneeded objects all the time such as SomeValChars. Create it once and reuse.
How big is instance of following class after constructor is called?
I guess this can be written generally as size = nx + c, where x = 4
in x86, and x = 8 in x64. n = ? c = ?
Is there some method in .NET which can return this number?
class Node
{
byte[][] a;
int[] b;
List<Node> c;
public Node()
{
a = new byte[3][];
b = new int[3];
c = new List<Node>(0);
}
}
First of all this depends on environment where this program is compiled and run, but if you fix some variables you can get pretty good guess.
Answer to 2) is NO, there is no function that will give you requested answer for any object given as argument.
In solving 1) you have two approaches:
Try to perform some tests to find out
Analyze the object and do the math
Test approach
First take a look at these:
what-is-the-memory-overhead-of-a-net-object
Overhead of a .NET array?
C# List size vs double[] size
Method you need is this:
const int Size = 100000;
private static void InstanceOverheadTest()
{
object[] array = new object[Size];
long initialMemory = GC.GetTotalMemory(true);
for (int i = 0; i < Size; i++)
{
array[i] = new Node();
}
long finalMemory = GC.GetTotalMemory(true);
GC.KeepAlive(array);
long total = finalMemory - initialMemory;
Console.WriteLine("Measured size of each element: {0:0.000} bytes",
((double)total) / Size);
}
On my Windows 7 machine, VS 2012, .NET 4.5, x86 (32 bit) result is 96.000. When changed to x64 result is 176.000.
Do the math approach
Do the math approach can be written as a function that will give you result, but is specific for your Node class, and it is only valid before other operations on your object are performed. Also notice that this is made in 32-bit program and also note that this number can change with framework implementation and version. This is just example how you can give pretty good guess about object size in some moment if object is simple enough. Array and List overhead constants are taken from Overhead of a .NET array? and C# List size vs double[] size
public const int PointerSize32 = 4;
public const int ValueArrayOverhead32 = 12;
public const int RefArrayOverhead32 = 16;
public const int ListOverhead32 = 32;
private static int instanceOverheadAssume32()
{
int sa = RefArrayOverhead32 + 3 * PointerSize32;
int sb = ValueArrayOverhead32 + 3 * sizeof(int);
int sc = ListOverhead32;
return 3 * PointerSize32 + sa + sb + sc;
}
This will also return 96 so I assume that method is correct.
Consider a 2D, rectangular array. Say:
int[,] values = new int[len1, len2];
How can you iterate through all of its values in unsafe code?
The following works in an unsafe context.
fixed (int* baseOffset = values)
{
var offset = baseOffset;
var count = len1 * len2;
for (int i = 0; i < count; i++)
{
int value = *offset;
// Do whatever you need to do here
offset++;
}
}
Note that to get a pointer to the first item in an array, the types must match. So if you have a byte* which you want to treat as ushort*, you cannot cast the pointer within the fixed statement's parentheses, although you can do this within the block.