[Tutorial] Player Variables vs Normal Variables.
#1

Introduction

Hey, i'm going to start a quick experiment to see what's faster, using normal variables, or PVars. Here's a example of each.

pawn Код:
// Normal.
new
       GSystem[MAX_PLAYERS];
pawn Код:
// PVars
SetPVarInt(playerid, "GSystem", 0);
Player variables are new to most scripters. Some prefer it for reasons. This tutorial is split up into several useful information. After talking with my friend krisk about z-Andreas we somehow drifted to a discussion of variables and speed, etc. Quoted from krisk:

Quote:
Originally Posted by IRC
<krisk> PVars are convinient but still variables are twice as fast
I decided actually to check if this is true, by the end of this experiment you will find out of course. We're going to use this code for testing.

pawn Код:
new
       string[70],
       pname[24];

GetPlayerName(playerid, pname, 24);
format(string, 70, "SELECT * FROM Accounts WHERE Username = '%s'", name);
mysql_query(string); mysql_store_result();
if(mysql_num_rows() > 0) {
     // Variable information we're experimenting.
}
else {

}
mysql_free_result();
Speed-O-Krisk

Lets test krisk's opinion, here's what he would do for proof or whatever.

pawn Код:
new
       string[70],
       pname[24],
       bool:HasAccount[MAX_PLAYERS];

GetPlayerName(playerid, pname, 24);
format(string, 70, "SELECT * FROM Accounts WHERE Username = '%s'", name);
mysql_query(string); mysql_store_result();
if(mysql_num_rows() > 0) HasAccount[playerid] = true;
else HasAccount[playerid] = false;
mysql_free_result();
Ok, fine, lets now test the outcome.

pawn Код:
new
       string[70],
       pname[24],
       bool:HasAccount[MAX_PLAYERS],
       StartTest, EndTest;

GetPlayerName(playerid, pname, 24);
format(string, 70, "SELECT * FROM Accounts WHERE Username = '%s'", name);
mysql_query(string); mysql_store_result();
StartTest = GetTickCount();
if(mysql_num_rows() > 0) HasAccount[playerid] = true;
else HasAccount[playerid] = false;
EndTest = GetTickCount();
printf("krisk's varable method: %i", EndTest - StartTest);
mysql_free_result();
Speed-O-Carlton

Ok, it's my turn, this is my code I would use.

pawn Код:
new
       string[70],
       pname[24];
GetPlayerName(playerid, pname, 24);
format(string, 70, "SELECT * FROM Accounts WHERE Username = '%s'", name);
mysql_query(string); mysql_store_result();
if(mysql_num_rows() > 0) SetPVarInt(playerid, "HasAccount", true);
else SetPVarInt(playerid, "HasAccount", false);
mysql_free_result();
Ok, now it's time to test the speed.

pawn Код:
new
       string[70],
       pname[24],
       StartTest, EndTest;

GetPlayerName(playerid, pname, 24);
format(string, 70, "SELECT * FROM Accounts WHERE Username = '%s'", name);
mysql_query(string); mysql_store_result();
StartTest = GetTickCount();
if(mysql_num_rows() > 0) SetPVarInt(playerid, "HasAccount", true);
else SetPVarInt(playerid, "HasAccount", false);
EndTest = GetTickCount();
printf("Carlton's varable method: %i", EndTest - StartTest);
mysql_free_result();

Before the results.

Before the results i'd like to type a little note explaining that SetPVarInt and GetPVarInt calls the function and does what it needs but on the other hand variables does the opposite, it just does what it needs. But then again variables create more cells which means longer compiling.

RAM speed can also do something about the results.

Results #1

Ok, they both came out to be zero. "Oh WTF?". No one ever said variables are faster than a milliseconds even bring to "nanoseconds"!

Quote:

krisk's varable method: 0
Carlton's varable method: 0

Results #2

I tried something different.

pawn Код:
for(new gg = 0; gg < 100000; gg ++ ) SetPVarInt(playerid, "HasAccount", true);
for(new gg = 0; gg < 100000; gg ++ ) HasAccount[playerid] = true;
Results came in.

Quote:
Originally Posted by Server
[22:42:25] Krisk's test took: 14
[22:42:25] Carlton's test took: 40
Oh look we're getting somewhere.

Conclusion

Ok, looks like krisk beat me, and was right, i'll buy him a stack of beer or something. The outcome of this experiment and a summary:
  • 1: Create the code.
  • 2: Get how fast it's without setting it about 100k times
  • 3: Conclude
Normal Variables are faster than player variables!

Thank you for reading this, I hope people who didn't know learned something today, because I did.
Reply
#2

Oi, you actually did benchmark it - nice, anyways yeah PVars aren't meant to be faster, but it gives a better overview plus is tons easier to work with than variables, don't have to reset them, AMX size gets smaller, less memory usage and you gotta put some serious effort into getting SetPVarString to crash the GM for overflow/OOB.

Anyways there are cases I'd use PVar over variables to speed up, like when you'd have to do IsPlayerConnected() as well as using the variable it'd be just as fast or even faster getting the PVar as that would both check that he's still connected and get what you're looking for.

Great work tho, I love it when people actually benchmark their code! Thumbs up
Reply
#3

PVars are much more convinient with auto-resetting on connect and less AMX size. If you already have normal variables there would be not much point in changing.
Reply
#4

Despite the fact that PVars are slower, I find them a lot more convenient, cross-script communication along with the fact that they're reset when a player connects to the server. Nice find though.
Reply
#5

Thank you three, yet I did figure out it's slower though.
Reply
#6

*bump* Interesting, I thought PVars were faster, guess I were wrong, just like you, Carlton.
It would be interesting with a speed test using strings too.

Nice "tutorial" btw
Reply
#7

Both methods is same for usual scripters.

When you start to loop something like in this tutor for 100k times, than you need to start worry about what is faster or no.

Anyway im glad that someone actualy made a test for Pvars.
Reply
#8

An update testing the 0.3b PVar speed increase?
Reply
#9

I don't think that they will ever be faster then the normal variables. Maybe on same level, but not faster, can't imagine so.
*My Opinion* ^^

PS: Good tutorial, now I know why I stay at the normal ones.
Reply
#10

Код:
CMD:testunit(playerid, params[])
{
    new
        HasAccount[MAX_PLAYERS],
        test[2][2],
		playerName[MAX_PLAYER_NAME];

	GetPlayerName(playerid, playerName, MAX_PLAYER_NAME);

	test[0][0] = GetTickCount();
	
	for(new gg = 0; gg < 100000; gg ++ ) SetPVarInt(playerid, "HasAccount", 1);
	
	test[0][1] = GetTickCount();
	
	test[1][0] = GetTickCount();
	for(new gg = 0; gg < 100000; gg ++ ) HasAccount[playerid] = true;
	
	test[1][1] = GetTickCount();
	
	printf("[PVARS TEST] Test Start: %d | Test End: %d | Test Duration: %d", test[0][0], test[0][1], test[0][1] - test[0][0]);
	printf("[VARIABLE TEST] Test Start: %d | Test End: %d | Test Duration: %d", test[1][0], test[1][1], test[1][1] - test[1][0]);
	
	return 1;
}
Just tested, with my own code this time:

[20:54:47] [PVARS TEST] Test Start: 98331 | Test End: 98354 | Test Duration: 23
[20:54:47] [VARIABLE TEST] Test Start: 98354 | Test End: 98357 | Test Duration: 3
Reply
#11

Quote:
Originally Posted by Calgon
View Post
Code:
CMD:testunit(playerid, params[])
{
    new
        HasAccount[MAX_PLAYERS],
        test[2][2],
		playerName[MAX_PLAYER_NAME];

	GetPlayerName(playerid, playerName, MAX_PLAYER_NAME);

	test[0][0] = GetTickCount();
	
	for(new gg = 0; gg < 100000; gg ++ ) SetPVarInt(playerid, "HasAccount", 1);
	
	test[0][1] = GetTickCount();
	
	test[1][0] = GetTickCount();
	for(new gg = 0; gg < 100000; gg ++ ) HasAccount[playerid] = true;
	
	test[1][1] = GetTickCount();
	
	printf("[PVARS TEST] Test Start: %d | Test End: %d | Test Duration: %d", test[0][0], test[0][1], test[0][1] - test[0][0]);
	printf("[VARIABLE TEST] Test Start: %d | Test End: %d | Test Duration: %d", test[1][0], test[1][1], test[1][1] - test[1][0]);
	
	return 1;
}
Just tested, with my own code this time:

[20:54:47] [PVARS TEST] Test Start: 98331 | Test End: 98354 | Test Duration: 23
[20:54:47] [VARIABLE TEST] Test Start: 98354 | Test End: 98357 | Test Duration: 3
Good, once again PVars failed
Reply
#12

Quote:
Originally Posted by Carlton
View Post
Good, once again PVars failed
By .02 miliseconds? Who cares! I don't even think it matters all that much.

One of the main reasons I use PVars is to reduce my .amx size because I use serverFFS as my host and every time I upload my .amx file (approx. 3.22mb) it takes about 2mins (for some reason whenever I upload stuff to serverFFS it limits my kb/s to about 36 when I should get 150-160kb/s :/).
Reply
#13

I've been telling people its not worth modifying there scripts just because people ask to use PVar's if you already scripted standard arrays no point in having to change your script for a slower method, let the end user do that. I seen the speed test on PVar's a few times and granted they have gotten faster and sure for cross script usage they are a plus but that's about it for me. I don't have a hard time typing var[playerid] = 0; under OnPlayerConnect -.-' so the fact that they auto clear isn't really nothing imo.
Reply
#14

Quote:
Originally Posted by xxxDunecatxxx
View Post
By .02 miliseconds? Who cares! I don't even think it matters all that much.

One of the main reasons I use PVars is to reduce my .amx size because I use serverFFS as my host and every time I upload my .amx file (approx. 3.22mb) it takes about 2mins (for some reason whenever I upload stuff to serverFFS it limits my kb/s to about 36 when I should get 150-160kb/s :/).
Yes, and if you think about it, that's gonna come back and bite you later on, when you have a bunch of slow PVars for your script to continuously process.

I use PVars in certain cases, as it seems more practical and more efficient, say for example I have a variable that really only has 1 use, no point creating a normal player variable for it, waste of 500 cells (or whatever MAX_PLAYERS is defined as).
Reply
#15

Quote:
Originally Posted by Carlton
View Post
Good, once again PVars failed
Failed? Well obviously they fail when you're not using them properly. With that logic, I can say gas fails because it can't run my diesel boat.

Quote:
Originally Posted by Calgon
View Post
Yes, and if you think about it, that's gonna come back and bite you later on, when you have a bunch of slow PVars for your script to continuously process.

I use PVars in certain cases, as it seems more practical and more efficient, say for example I have a variable that really only has 1 use, no point creating a normal player variable for it, waste of 500 cells (or whatever MAX_PLAYERS is defined as).
Consider utilizing bit manipulation aswell as using the "char" keyword (arrays with the char keyword will contain only 1 byte per slot; however, only capable of carrying 8 bits (value 0-255)).
If you, for example, have a variable that tells you whether a player is in a race or not, you could store 1 value per bit; thus, using only 16 cells for 500 players.
Reply
#16

I have tested it too;
This are my results:

Code:
[07:12:28] PVARS: Starting: 261648027 | Ending: 261648609 | Duration: 582
[07:12:28] NORMAL: Starting: 261648609 | Ending: 261648768 | Duration: 159

[07:12:29] PVARS: Starting: 261649319 | Ending: 261649753 | Duration: 434
[07:12:29] NORMAL: Starting: 261649753 | Ending: 261649909 | Duration: 156

[07:12:30] PVARS: Starting: 261650285 | Ending: 261650839 | Duration: 554
[07:12:30] NORMAL: Starting: 261650839 | Ending: 261650996 | Duration: 157

[07:12:31] PVARS: Starting: 261650997 | Ending: 261651309 | Duration: 312
[07:12:31] NORMAL: Starting: 261651309 | Ending: 261651465 | Duration: 156

[07:12:01] PVARS: Starting: 261620817 | Ending: 261621305 | Duration: 488
[07:12:01] NORMAL: Starting: 261621305 | Ending: 261621463 | Duration: 158
I've tested it more then once; it IS faster
Reply
#17

read my post above yours..
Reply
#18

*edit* holy bump! I forgot I was in search and that this thread was so old.

So then what do you guys think the implications of using PVar for user information storage on login when you are storing 20+ variables that will be called in several different situations.

I read above that people are using PVars sparingly, then I read that some people swear by them. My gamemode is a conglomerate at the moment but I have been moving my variables to PVar so that I can hypothetically move my login scripts to a filterscript in the near future.

Can I get a few more opinions on the matter so I can make a more educated decision. I'll be in the search function while I wait
Reply
#19

Quote:
Originally Posted by Y_Less
View Post
How many more opinions do you want? All the evidence CLEARLY shows that normal variables are better - it's not even close!
You're wrong. It shows that normal variables are faster, but that doesn't neccesarry mean that they're better.

Personally I would go with a mix between both normal variables and player variables.
Reply
#20

Well lets say THERE CANNOT BE COMPETITION between variables and functions to SET variables..
ofcourse just using variables without PVars is more than 2 times faster. But which geek is ggoing to set milion variables in one function/public?

IT IS YOUR TASTE OF WHAT YOU PREFER!

I personally prefer using normal variables and something like this code below. amx size etc don't matter for me:
pawn Code:
#define MAX_VARIABLES 50
new globalinterger[MAX_PLAYERS][MAX_VARIABLES];
#define GlobalInt(%1,%2,%3) globalinterger[%1][%2]=%3
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)