|
You last visited: Today at 06:02
Advertisement
[Questions] Faster Methods?
Discussion on [Questions] Faster Methods? within the CO2 Private Server forum part of the Conquer Online 2 category.
08/29/2011, 19:10
|
#1
|
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
|
[Questions] Faster Methods?
Hey everyone.
So I've been working with pointers and I was wondering what's faster and if their are any alternative methods that might speed up my server.
1. Buffer.BlockCopy VS an unsafe for loop.
2. Encoding.ASCII.GetString VS an unsafe for loop with System.Convert.ToChar
3. Marshal.AllocHGlobal VS ??
I'm in class so I'll check back later.
Cyah.
Sincerely,
Fang
|
|
|
08/29/2011, 19:21
|
#2
|
elite*gold: 0
Join Date: May 2011
Posts: 1,769
Received Thanks: 756
|
First question can be answered here:
Quote:
Originally Posted by CptSky
Managed vs Unmanaged in C#... I know these things, but it will give a better idea of the reality and you'll see that the difference is so little that you can use what you want...
Tested on Windows XP x64, for a copy of 50'000'000 elements and tested 1000 times for precision. All values in ms.
Target | Buffer.BlockCopy | Array.Copy | memcpy (void*) | memcpy (IntPtr) | memcpy (void*, fixed byte*) | memcpy (fixed byte*, fixed byte*) | x64 | 31.547 | 30.734 | 30.201 | 30.922 | 34.817 | 29.760 | x86 | 43.606 | 41.208 | 37.309 | 37.626 | 40.051 | 37.704 | Any | 28.422 | 27.097 | 25.858 | 26.542 | 30.531 | 26.087 |
Results:
Allocating managed resources takes more times than unmanaged resources.
Byte[] = new Byte[], Byte* = (Byte*)Marshal.AllocHGlobal()
x64 is fastest than x86 on 64 bits OS.
Any CPU is fastest than x64 on 64 bits OS and probably on 32 bits OS (x86).
Array.Copy is fastest than Buffer.BlockCopy.
There is no difference between void* and IntPtr.
There is no difference between fixed pointer and pointer.
Native function memcpy is fastest than Array.Copy.
|
|
|
|
08/29/2011, 19:35
|
#3
|
elite*gold: 20
Join Date: Mar 2006
Posts: 6,125
Received Thanks: 2,518
|
Blockcopy's alternative should be memcpy, not a loop, pretty sure blockcopy and arraycopy both use memcpy within the methods.
For converting to a string you could do something like this within a for loop:
Code:
newstring += (char)*((char*)(lpBuffer + x);
Marshal.AllocHGlobal... i guess you could call LocalAlloc directly from kernel32, although i dont believe theres really much difference between the 2 methods, it just nicely wraps the call for you, possibly with some additional checks, i havent looked at the source.
|
|
|
08/29/2011, 22:50
|
#4
|
elite*gold: 20
Join Date: Jan 2008
Posts: 2,012
Received Thanks: 2,882
|
Quote:
Originally Posted by BaussHacker
First question can be answered here:
|
Buffer.ArrayCopy and Array.Copy need to be JIT-compiled on their first invoke, so performance is lost there. Secondly, if you constantly need to fix-down a pointer (using a fixed statement), it'll obviously result in a slight loss of performance.
Generally speaking, and depending on what your using it for, malloc() (in msvcrt.dll) will do a better job than AllocHGlobal will (in kernel32.dll).
If you need a small (we're talking like, under 255-bytes) temporary pointer-variable until the end of your method, I'd use stackalloc.
You should look at string.ctor(sbyte* ptr, int offset, int length) btw
|
|
|
08/30/2011, 00:50
|
#5
|
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
|
Quote:
Originally Posted by Korvacs
Blockcopy's alternative should be memcpy, not a loop, pretty sure blockcopy and arraycopy both use memcpy within the methods.
For converting to a string you could do something like this within a for loop:
Code:
client.Username += ((char)*((char*)(ptr + 4 + i)));
Marshal.AllocHGlobal... i guess you could call LocalAlloc directly from kernel32, although i dont believe theres really much difference between the 2 methods, it just nicely wraps the call for you, possibly with some additional checks, i havent looked at the source.
|
Code:
newstring += (char)*((char*)(lpBuffer + x);
I tried it already. It returns: "慆湡杮g" instead of "Fang"
The only thing that I found that worked with unsafe code was
"client.Username += System.Convert.ToChar(*(ptr + 4 + i));"
I'm guessing it's slightly better (I hope) than Encoding.ASCII.
edit: looking at string.ctor(sbyte* ptr, int offset, int length) now..
|
|
|
08/30/2011, 01:05
|
#6
|
elite*gold: 20
Join Date: Jan 2008
Posts: 2,012
Received Thanks: 2,882
|
Quote:
Originally Posted by Fаng
Code:
newstring += (char)*((char*)(lpBuffer + x);
I tried it already. It returns: "慆湡杮g" instead of "Fang"
The only thing that I found that worked with unsafe code was
"client.Username += System.Convert.ToChar(*(ptr + 4 + i));"
I'm guessing it's slightly better (I hope) than Encoding.ASCII.
|
A character in C# is 2-bytes (a wchar_t) in C++
A 'char' in C++ is a single-byte value (equivalent to a sbyte in C#)
The string send is a multi-byte string meaning, each character has a value of 1 byte. Therefore, by making a pointer type of C#'s 'char' type (2 bytes), you get these odd unicode characters.
Code:
string result = new string((sbyte*)ptr, offset, length);
|
|
|
08/30/2011, 01:31
|
#7
|
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
|
Quote:
Originally Posted by InfamousNoone
A character in C# is 2-bytes (a wchar_t) in C++
A 'char' in C++ is a single-byte value (equivalent to a sbyte in C#)
The string send is a multi-byte string meaning, each character has a value of 1 byte. Therefore, by making a pointer type of C#'s 'char' type (2 bytes), you get these odd unicode characters.
Code:
string result = new string((sbyte*)ptr, offset, length);
|
Just saw your post.
Thanks for the C++ lesson =p
Any other tips on pointers? I'd really like to use them more.
|
|
|
08/30/2011, 06:26
|
#8
|
elite*gold: 20
Join Date: Jan 2008
Posts: 2,012
Received Thanks: 2,882
|
Not really, I could give you an example on how I handle packets. For example,
Code:
public unsafe struct MsgWalk
{
public static readonly short[] DeltaX = { +0, -1, -1, -1, +0, +1, +1, +1, +0 };
public static readonly short[] DeltaY = { +1, +1, +0, -1, -1, -1, +0, +1, +0 };
public short Size;
public MsgTypeId Type;
public int Direction;
public int ObjectId;
public int MovementId;
public int TimeStamp;
public int MapId;
public void Init(int ObjectId, int Direction, int Id)
{
this.Size = (short)sizeof(MsgWalk);
this.Type = MsgTypeId.Walk;
this.Direction = Direction;
this.ObjectId = ObjectId;
this.MovementId = Id;
this.TimeStamp = DBCore.GetTime();
}
public static void Process(User user, void* pMsg)
{
MsgWalk* msg = (MsgWalk*)pMsg;
if (msg->ObjectId != user.Entity.ObjectId)
return;
msg->Direction %= 8;
int x = user.Entity.X, y = user.Entity.Y;
if (msg->MovementId == 9)
{
user.Socket.Disconnect("MsgWalk::Process steed walking not supported");
return;
}
else
{
x += DeltaX[msg->Direction];
y += DeltaY[msg->Direction];
}
user.SendRoom(msg, msg->Size);
user.Move(x, y);
}
}
|
|
|
08/30/2011, 07:09
|
#9
|
elite*gold: 12
Join Date: Jul 2011
Posts: 8,211
Received Thanks: 4,114
|
That's how i code packets too (kind of).
What do u think of a packet queue at the receive void?
|
|
|
All times are GMT +2. The time now is 06:02.
|
|