[Include] dini2.inc - Improved dini file processor with amazing benchmarks (aka. gini)!
#1

dini2.inc
Updated: v3.1 (10 March, 201
Improved version of "dini.inc" with high performance and same syntax!
INI is mostly used for initializing data to your server. But i have seen many gamemodes/filterscripts still use this old library which is very slow/inefficient in today's time, so i though of making an improved version.

How this works?
Well it works with arrays. The files' data is read once when you use any "Set" function of dini. A timer starts which will free the memory of that file later after 'n' milliseconds. So unlike original dini, this one don't open and close a file everytime we use a Set/Get function. It works exactly like SII but with the ability to operate multiple files at a time.

Benchmark
Quote:

* Dini2.inc
Writing 100 files with 64 fields, 3 times takes: 333 ms
Reading 100 files with 64 fields, 3 times takes: 132 ms


* Dini.inc (old version)
Writing 100 files with 64 fields, 3 times takes: 36485 ms
Reading 100 files with 64 fields, 3 times takes: 1835 ms
Its like saving 100 players data 3 times all at once (64 fields each file)!

Benchmark Source-Code
You can use this code to perform tests with other INI processors to compare results!

How to compare results with original Dini.inc and Dini2.inc?
First compile the script with "#include <Dini2.inc>" and then run the samp-server.exe.
Second test, replace "#include <Dini2.inc>" to "#include <Dini.inc>" and compile. Run samp-server.exe.

You have result for both. Dini is way way slower than new one. Don't run test on 500 files for Dini.inc, it will hang up or you have to wait for hours to get results lol!

PHP Code:
#include <a_samp>
#include <Dini2>
main() {
    const 
ITERATIONS 3;
    const 
NUM_FILES 100;
    const 
NUM_FIELDS 64;
    
    new 
se;
    new 
fileName[54];
    new 
fieldName[64];
    
// START
    
GetTickCount();
    
//
    
for (new aITERATIONSa++) {
        for (new 
bNUM_FILESb++) {
            
format(fileNamesizeof fileName"file_%i.ini"b);
            
#if !defined dini2_included
            
dini_Create(fileName);
            
#endif
            
            
for (new cNUM_FIELDSc++) {
                
format(fieldNamesizeof fieldName"field_%i"c);
                
dini_Set(fileNamefieldName"value");
            }
        }
    }
    
#if defined dini2_included
    
for (new aNUM_FILESa++) {
        
format(fileNamesizeof fileName"file_%i.ini"a);
        
dini_Timeout(fileName);
    }
    
#endif
    //
    
GetTickCount();
    
printf("Writing %i files with %i fields, %i times takes: %i ms"NUM_FILESNUM_FIELDSITERATIONS, (s));
    
// END
    // START
    
GetTickCount();
    
//
    
for (new aITERATIONSa++) {
        for (new 
bNUM_FILESb++) {
            
format(fileNamesizeof fileName"file_%i.ini"b);
            
#if !defined dini2_included
            
dini_Create(fileName);
            
#endif
            
            
for (new cNUM_FIELDSc++) {
                
format(fieldNamesizeof fieldName"field_%i"c);
                
dini_Get(fileNamefieldName);
            }
        }
    }
    
#if defined dini2_included
    
for (new aNUM_FILESa++) {
        
format(fileNamesizeof fileName"file_%i.ini"a);
        
dini_Timeout(fileName);
    }
    
#endif
    //
    
GetTickCount();
    
printf("Reading %i files with %i fields, %i times takes: %i ms"NUM_FILESNUM_FIELDSITERATIONS, (s));
    
// END
    
for (new aNUM_FILESa++) {
        
format(fileNamesizeof fileName"file_%i.ini"a);
        
dini_Remove(fileName);
    }

Functions
PHP Code:
dini_Exists(const filename[]);
dini_Remove(const filename[]);
dini_Create(const filename[]);
dini_Set(const filename[], const key[], const value[]);
dini_IntSet(const filename[], const key[], value);
dini_FloatSet(const filename[], const key[], Float:value);
dini_BoolSet(const filename[], const key[], bool:value);
dini_Get(const filename[], const key[]);
dini_Int(const filename[], const key[]);
Float:dini_Float(const filename[], const key[]);
bool:dini_Bool(const filename[], const key[]);
dini_Unset(const filename[], const key[]);
dini_Isset(const filename[], const key[]);
DINI_StripNewLine(const string[]);
DINI_fcopytextfile(const filename[], const newfilename[]);
// New function from v1.0+
dini_Timeout(const filename[]);
// New functions from v3.0+
dini_NumKeys(const filename[]);
dini_GetKeyName(const filename[], keyid);
// New function from v3.1+
DINI_frenametextfile(const filename[], const newfilename[]); 
Download
https://github.com/Agneese-Saini/SA-...lude/dini2.inc
Reply
#2

Any bench?
I suggest you put suport for sections ^^
Good work ^^
Reply
#3

Quote:
Originally Posted by Day_
View Post
Any bench?
The way this works is pretty different, if you benchmark functions, they will be like "1ms" for 1000 iterations or even more. Because the operation of writing the file is done in a timer which gets executed after defined seconds.

I'll try to make up some by editing the include; probably by using 2ms for timer's interval.

Quote:
Originally Posted by Day_
View Post
I suggest you put suport for sections ^^
What do you mean ?
Reply
#4

Wow Gammix, you've made a lot of contributions to the community! Keep up the good work man.
+rep
Reply
#5

Amazing, man. I did a test on my server and found out that GINI is faster than Y_INI and DINI.

Edit: On another script (NGRP), I got some errors. Mind if help ya?
pawn Code:
./includess/commands.pwn(23306) : error 017: undefined symbol "dini_Exists"
./includess/mysql.pwn(5653) : error 017: undefined symbol "dini_Create"
./includess/mysql.pwn(5654) : error 017: undefined symbol "dini_Remove"
./includess/mysql.pwn(5655) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5656) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5657) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5658) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5659) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5660) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5661) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5662) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5663) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5664) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(6) : error 017: undefined symbol "dini_Exists"
./includess/OnPlayerLoad.pwn(8) : error 017: undefined symbol "dini_Create"
./includess/OnPlayerLoad.pwn(9) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(10) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(11) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(12) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(13) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(14) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(15) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(16) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(17) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(18) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(19) : error 017: undefined symbol "dini_IntSet"

Compilation aborted.Pawn compiler 3.2.3664          Copyright (c) 1997-2006, ITB CompuPhase


26 Errors.
Reply
#6

Quote:
Originally Posted by ShadyEG
View Post
Amazing, man. I did a test on my server and found out that GINI is faster than Y_INI and DINI.

Edit: On another script (NGRP), I got some errors. Mind if help ya?
pawn Code:
./includess/commands.pwn(23306) : error 017: undefined symbol "dini_Exists"
./includess/mysql.pwn(5653) : error 017: undefined symbol "dini_Create"
./includess/mysql.pwn(5654) : error 017: undefined symbol "dini_Remove"
./includess/mysql.pwn(5655) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5656) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5657) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5658) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5659) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5660) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5661) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5662) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5663) : error 017: undefined symbol "dini_IntSet"
./includess/mysql.pwn(5664) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(6) : error 017: undefined symbol "dini_Exists"
./includess/OnPlayerLoad.pwn(8) : error 017: undefined symbol "dini_Create"
./includess/OnPlayerLoad.pwn(9) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(10) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(11) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(12) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(13) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(14) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(15) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(16) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(17) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(18) : error 017: undefined symbol "dini_IntSet"
./includess/OnPlayerLoad.pwn(19) : error 017: undefined symbol "dini_IntSet"

Compilation aborted.Pawn compiler 3.2.3664          Copyright (c) 1997-2006, ITB CompuPhase


26 Errors.
v1.1.1 creates all DINI functions when INI_CONVERT_DINI is defined. Checkout the thread once again for instructions.
Reply
#7

Updated again to v1.1.2 due to another bug in the new conversation.
Reply
#8

Quote:
Originally Posted by Uberanwar
View Post
Wow Gammix, you've made a lot of contributions to the community! Keep up the good work man.
+rep
Ikr imagine if he were to have a server it would be awesome.
Anyways GoodJob You got my rep even before this.
Reply
#9

Thanks all.

I realized most of the scripts use INI as a database and taking that in mind, we cannot execute so many timers at once (max is maybe 30). So in next update, i'll use on global timer to run and work on tick counts.
Reply
#10

Amazing as always budd'
+repp
Reply
#11

Wooooooo!! Good work there!
Reply
#12

Give me reasons why someone would prefer to use gini over other INI processors which have WAY WAY WAY more features and is WAY WAY WAY faster.

Quote:
Originally Posted by Gammix
This is faster, a lot than DINI
You are competing in the wrong world. Start bench-marking with y_ini or eINI. Your include provides far less features and is slower. You MUST beat y_ini in performance if you want to keep the include this simple if you WANT people to use it.

By just looking at your code, I can guarantee you that gini is AT LEAST 10 times slower than y_ini.

The only interesting feature I see is the timeout feature.

You'd do better if you would have forked the existing INI Processors and added new features to it.

strunpack? Why even save memory? Just give it away or at least keep it optional. Most servers have many GBs of memory and the memory saved by packing strings is insignificant.
Reply
#13

how can it be faster than Yini im pretty sure its slower than you claim to be 1 star from me
Reply
#14

Quote:
Originally Posted by Yashas
View Post
Give me reasons why someone would prefer to use gini over other INI processors which have WAY WAY WAY more features and is WAY WAY WAY faster.
For this:
"Only for the sake of those who still use DINI, switch your gamemodes to this."

INI is not preferred for database, i suggest using SQL and my EasyDB is pretty powerful. I only use INI for initializing data or configuration files.



Quote:
Originally Posted by Yashas
View Post
You are competing in the wrong world. Start bench-marking with y_ini or eINI. Your include provides far less features and is slower. You MUST beat y_ini in performance if you want to keep the include this simple if you WANT people to use it.
I haven't even performed any speed tests until now and this an old library of mine just polished a bit.
(I take my statement back about its speed, dini2 is really fast)



Quote:
Originally Posted by Yashas
View Post
The only interesting feature I see is the timeout feature.
If you want a syntax as of DINI and want no script changes but to switch to a faster one, this is the best way i can think of.



Quote:
Originally Posted by Yashas
View Post
You'd do better if you would have forked the existing INI Processors and added new features to it.
New features to INI processor is just a waste of time, your eINI is having load features but they are useless to have, just get an idea from the number of users. SQL is much easier option for that.




Update v1.2:
- Fixed reading file bug (file was closed before actually reading data!)
- One global timer to handle instances/opened INI files
- Removed INI_CONVERT_DINI, the script auto converts DINI functions



EDIT: The thread will be renamed to DINI improved.
Reply
#15

Quote:
Originally Posted by Yashas
View Post
Give me reasons why someone would prefer to use gini over other INI processors which have WAY WAY WAY more features and is WAY WAY WAY faster.



You are competing in the wrong world. Start bench-marking with y_ini or eINI. Your include provides far less features and is slower. You MUST beat y_ini in performance if you want to keep the include this simple if you WANT people to use it.

By just looking at your code, I can guarantee you that gini is AT LEAST 10 times slower than y_ini.

The only interesting feature I see is the timeout feature.

You'd do better if you would have forked the existing INI Processors and added new features to it.

strunpack? Why even save memory? Just give it away or at least keep it optional. Most servers have many GBs of memory and the memory saved by packing strings is insignificant.
Theres nothing wrong with this concept, ALOT of scripts out there still use dini, people can just include this instead of dini and speed up their file functions.

Everything must be criticized in this place.. lmao.
Reply
#16

Quote:
Originally Posted by Kar
View Post
Theres nothing wrong with this concept, ALOT of scripts out there still use dini, people can just include this instead of dini and speed up their file functions.
That's exactly what this include is all about. In the next update, i'll rename it to Improved DINI and also restructure a bit.

There's no point in inventing another INI processor with useless features.
Reply
#17

Well done, great!

I created theme in Russian forum: link (This is not advertising!), don't you mind?
Reply
#18

Quote:
Originally Posted by Kolstin
View Post
Well done, great!

I created theme in Russian forum: link (This is not advertising!), don't you mind?
You might want to update it.


Update v2.3:
- Thread name changed to
Quote:

dini2.inc - Improved DINI processor with multi file support and faster

- All dini functions included (there are no new functions, you can now actually use DINI functions to manage INI files)
- Removed packed strings
- Speed improvements
Reply
#19

Y_INI vs. eINI vs. DINI2
If the benchmarks are wrong, you may share yours or correct them, i haven't really used Y_INI or any INI processor.

Benchmarks code:
pawn Code:
#include <a_samp>

#include <YSI\y_ini>

#include <eini>

#define INI_FILE_TIMEOUT (3000)
#include <dini2>

main()
{
    new s, e;

    // Y_INI
    // Writing
    s = GetTickCount();

    new INI:handle = INI_Open("Test.ini");
    for (new i; i < 100000; i++)
    {
        INI_WriteString(handle, "Set1", "Gammix_Changed");
        INI_WriteString(handle, "Set2", "Gammix_Changed");
        INI_WriteString(handle, "Set3", "Gammix_Changed");
        INI_WriteString(handle, "Set4", "Gammix_Changed");
        INI_WriteString(handle, "Set5", "Gammix_Changed");
        INI_WriteString(handle, "Set6", "Gammix_Changed");
        INI_WriteString(handle, "Set7", "Gammix_Changed");
        INI_WriteString(handle, "Set8", "Gammix_Changed");
        INI_WriteString(handle, "Set9", "Gammix_Changed");
        INI_WriteString(handle, "Set10", "Gammix_Changed");
    }
    INI_Close(handle);

    e = GetTickCount();
    printf("[Y_INI] Write string to 10 fields 100000 times -> %i ms", e - s);

    // Reading
    s = GetTickCount();

    for (new i; i < 100000; i++)
    {
        INI_ParseFile("Test.ini", "LoadFile");
    }

    e = GetTickCount();
    printf("[Y_INI] Read string from 10 fields 100000 times -> %i ms", e - s);



    // eINI
    // Writing
    s = GetTickCount();

    handle = INI::OpenINI("Test2.ini", INI_WRITE);
    for (new i; i < 100000; i++)
    {
        INI::WriteString(handle, "Gammix_Changed", "Set1", "");
        INI::WriteString(handle, "Gammix_Changed", "Set2", "");
        INI::WriteString(handle, "Gammix_Changed", "Set3", "");
        INI::WriteString(handle, "Gammix_Changed", "Set4", "");
        INI::WriteString(handle, "Gammix_Changed", "Set5", "");
        INI::WriteString(handle, "Gammix_Changed", "Set6", "");
        INI::WriteString(handle, "Gammix_Changed", "Set7", "");
        INI::WriteString(handle, "Gammix_Changed", "Set8", "");
        INI::WriteString(handle, "Gammix_Changed", "Set9", "");
        INI::WriteString(handle, "Gammix_Changed", "Set10", "");
    }
    INI::CloseINI(handle);

    e = GetTickCount();
    printf("[eINI] Write string to 10 fields 100000 times -> %i ms", e - s);

    // Reading
    s = GetTickCount();

    handle = INI::OpenINI("Test2.ini", INI_READ);
    for (new i; i < 100000; i++)
    {
        INI::ReadString(handle, "", "Set1", "");
        INI::ReadString(handle, "", "Set2", "");
        INI::ReadString(handle, "", "Set3", "");
        INI::ReadString(handle, "", "Set4", "");
        INI::ReadString(handle, "", "Set5", "");
        INI::ReadString(handle, "", "Set6", "");
        INI::ReadString(handle, "", "Set7", "");
        INI::ReadString(handle, "", "Set8", "");
        INI::ReadString(handle, "", "Set9", "");
        INI::ReadString(handle, "", "Set10", "");
    }

    e = GetTickCount();
    printf("[eINI] Read string from 10 fields 100000 times -> %i ms", e - s);
   


    // DINI2
    // Writing
    s = GetTickCount();

    dini_Create("Test3.ini");
    for (new i; i < 100000; i++)
    {
        dini_Set("Test3.ini", "Set1", "Gammix_Changed");
        dini_Set("Test3.ini", "Set2", "Gammix_Changed");
        dini_Set("Test3.ini", "Set3", "Gammix_Changed");
        dini_Set("Test3.ini", "Set4", "Gammix_Changed");
        dini_Set("Test3.ini", "Set5", "Gammix_Changed");
        dini_Set("Test3.ini", "Set6", "Gammix_Changed");
        dini_Set("Test3.ini", "Set7", "Gammix_Changed");
        dini_Set("Test3.ini", "Set8", "Gammix_Changed");
        dini_Set("Test3.ini", "Set9", "Gammix_Changed");
        dini_Set("Test3.ini", "Set10", "Gammix_Changed");
    }
    dini_Timeout("Test3.ini");

    e = GetTickCount();
    printf("[DINI2] Write string to 10 fields 100000 times -> %i ms", e - s);
   
    // Reading
    s = GetTickCount();

    dini_Create("Test3.ini");
    for (new i; i < 100000; i++)
    {
        dini_Get("Test3.ini", "Set1");
        dini_Get("Test3.ini", "Set2");
        dini_Get("Test3.ini", "Set3");
        dini_Get("Test3.ini", "Set4");
        dini_Get("Test3.ini", "Set5");
        dini_Get("Test3.ini", "Set6");
        dini_Get("Test3.ini", "Set7");
        dini_Get("Test3.ini", "Set8");
        dini_Get("Test3.ini", "Set9");
        dini_Get("Test3.ini", "Set10");
    }
    dini_Timeout("Test3.ini");

    e = GetTickCount();
    printf("[DINI2] Read string from 10 fields 100000 times -> %i ms", e - s);
}

forward LoadFile(tag[],key[],value[]);
public LoadFile(tag[],key[],value[])
{
}
Results:
Code:
[15:59:11] [Y_INI] Write string to 10 fields 100000 times -> 2944 ms
[15:59:19] [Y_INI] Read string from 10 fields 100000 times -> 8173 ms

[15:59:20] [eINI] Write string to 10 fields 100000 times -> 965 ms
[15:59:21] [eINI] Read string from 10 fields 100000 times -> 838 ms

[15:59:21] [DINI2] Write string to 10 fields 100000 times -> 833 ms
[15:59:22] [DINI2] Read string from 10 fields 100000 times -> 870 ms


@Yashas: I guess you were wrong on you claiming this WAY WAY WAY slower. Its alot faster than YINI and step further than eINI even with such syntax it supports.
Reply
#20

dini_IntSet does not work
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)