Readspeed Test Tool. Test HD/OS and chunksize speeds.

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Readspeed Test Tool. Test HD/OS and chunksize speeds.

Post by Rescator »

This tool is obsoleted.

Please use v2 of the Readspeed tool instead.
http://www.purebasic.fr/english/viewtopic.php?t=37518

It is overly simplified, no writing of results to disk, it's all in memory.
I've stripped out as much code as possible to make this really tight.
It's also way simpler and less confusing to use. (I hope).

Anyway, fool around with v2 instead, simple yes but way better. :)



This "tool" was born from the following thread: http://www.purebasic.fr/english/viewtopic.php?t=37438

Curious which chunksize is fastest?,
and indirectly what the best filebuffersize might be?,
or want to compare Hard Drive?
or which OS or Operating Filesystem has best speeds?

Then this tool might be of interest!

Make sure you compile the tool with threadsafe enabled, and without the debugger. Or just create and executable.

The source should be cross platform, although on Windows the multimedia API is used to help the measurement accuracy, Mac and Linux "should" have 1ms accuracy as far as I know.

When you run the test tool it will pop up a savefile requester,
choose where and what name it should have, if you leave out the .csv it will be automatically added.
The CSV file is a "standard" CSV file, or as close as one can get, I choose the "standard" that Wikipedia describe as the most common CSV filetype.
Next simply select 1 or more files to test, a progress window will pop up showing, er... progress. When done a select file(s) to test requester appears again, if you choose to test more files the results will be added to the current test run. To quit choose cancel.
You can also abort the whole test while the progress window is up by hitting the closebutton on it.
Note! An existing CSV file will be overwritten by the savefile requester.

There are 4 columns of data stored in the savefile,
the latter two are usefull on the test system only.
However the two first columns, the chunksize and the normalized speed is not tied to the test system and can be used to compare across HD's, OS and other machines.

The normalized speed column is normalized with the 1MB chunksize as the base line.
Any values that are smaller means they are slower/took longer,
any values above 100 means they are faster/took less time.
For example, a speed result of 8 for the 512 byte chunksize test means it was 92% slower than the 1MB test (eek).

Please post your results "as is" in this thread, put them in a code block.

This way I (and anyone else interested) can simply copy and paste the results into CSV files, load them into a spread sheet program (like OpenOffice.org Scalc.) and merge the test result files, and apply some nice spreadsheet magic to get overall stats of the results, or maybe make a PHP script, unless you want to roll your own result analysis tool in PureBasic that is ;)

The source is Public Domain, although I request that if you intend to post results in this thread that the way the speed measurement done and CSV format used is not changed, this is just to avoid the pain of mixed filetypes and different ways to measure things, and make it easy to merge test results into spreadsheets or otherwise analyze it.

As usual with "my" code I do some odd or interesting things,
like the independent progressmeter window that is in it's own thread.
You could easily just remove the Main_Window() and any references to the procedure and the test tool would would still work without any issues.

It's loosely commented, but hopefully still easy to see what is going on.
Hopefully no silly bug/mistakes snuck in, it's not the prettiest code but should be fast and stable "knock on wood" despite a lack of extensive testing.

The progress meter will jump around erratically (or seem to), this is due to the fact it's in a independent "passive" thread, it updates the progressbar at 50fps, don't be surprised if small files barely register on it though.

My advise is to test with files around the 500MB size, too small files barely give enough time difference for conclusive results, and really large files, though interesting to test just takes too damn long. *laughs*
Also note that smaller chunksizes and smaller files use more CPU than large chunksizes and large files. (more on this in my next post below)

Have fun, and let's get lots of test results, just compiler/run (without debugger) and threadsafe on, and copy'n'paste the results in this thread, stats/speed tests are fun :P

Code: Select all

;Test Readspeed v1.0, Public Domain.
DisableDebugger ;Even this is here I still advise compiling without the debugger.
EnableExplicit ;Why isn't this default yet Fred? :P
;And don't forget to compile this with threadsafe on folks!

#File1=1
#File2=2
#Window1=1
#Gadget1=1
#Gadget2=2
#Gadget3=3

Global filenum.i,filesize.q,filepos.q,chunksize.i,quitprogram.i

Procedure.i Window_Main(create.i=#False)
 Static quit.i
 Protected event.i,result=#False,filepercent.d,start.l,stop.l,pos.d,size.d,num.i
 If create
  quit=#False
  If OpenWindow(#Window1,0,0,200,60,"Test Readspeed",#PB_Window_TitleBar|#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
   result=#True
   ProgressBarGadget(#Gadget1,0,0,200,20,0,100)
   TextGadget(#Gadget2,0,20,200,20,"File: ")
   TextGadget(#Gadget3,0,40,200,20,"Chunksize: ")
   If Not IsGadget(#Gadget1) Or Not IsGadget(#Gadget2) Or Not IsGadget(#Gadget3)
    result=#False
   EndIf
   If result
    CompilerIf #PB_Compiler_OS=#PB_OS_Windows
     start=timeGetTime_()
    CompilerElse
     start=ElapsedMilliseconds()
    CompilerEndIf
    stop=start
    Repeat
     event=WaitWindowEvent(1)
     CompilerIf #PB_Compiler_OS=#PB_OS_Windows
      stop=timeGetTime_()
     CompilerElse
      stop=ElapsedMilliseconds()
     CompilerEndIf
     If (stop-start)>=20
      CompilerIf #PB_Compiler_OS=#PB_OS_Windows
       start=timeGetTime_()
      CompilerElse
       start=ElapsedMilliseconds()
      CompilerEndIf
      num=filenum
      pos=filepos
      size=filesize
      If num And pos And size
       filepercent=(pos/size)*100.0
       SetGadgetState(#Gadget1,Int(filepercent))
       SetGadgetText(#Gadget2,"File: "+Str(filenum))
       SetGadgetText(#Gadget3,"Chunksize: "+Str(chunksize))
      EndIf
     EndIf
     If event=#PB_Event_CloseWindow
      quit=#True
      quitprogram=#True
     EndIf
    Until quit
   EndIf
   CloseWindow(#Window1)
  Else
   result=#False
  EndIf
 Else
  quit=#True
  result=#True
 EndIf
 ProcedureReturn result
EndProcedure

CompilerIf #PB_Compiler_OS=#PB_OS_Windows
 timeBeginPeriod_(1)
CompilerEndIf

Define *mem,file$,text$,savefile$,i.i,start.l,stop.l,readlen.i,thread1.i,base.d,time.d,percentage.d

*mem=AllocateMemory(1048576) ;1MB, 1024*1024 KB, 1048576 bytes, also our largest/starting chunksize.
If *mem

 savefile$=SaveFileRequester("Choose savefile for results:","","Comma Seperated Values (CSV)|.csv",0)
 If savefile$
  If ".csv"<>LCase(Right(savefile$,4))
   savefile$+".csv"
  EndIf
  If CreateFile(#File2,savefile$)
   text$=#DQUOTE$+"Chunksize"+#DQUOTE$+","+#DQUOTE$+"Normalized speed (100%=1MB speed)"+#DQUOTE$+","+#DQUOTE$+"Native speed (ms)"+#DQUOTE$+","+#DQUOTE$+"Native size (Bytes)"+#DQUOTE$+#CRLF$
   WriteString(#File2,text$)
   Repeat
    filenum=0 ;reset filecounter for main loop.
    If IsThread(thread1)
     WaitThread(thread1)
    EndIf
    thread1=CreateThread(@Window_Main(),#True)
    chunksize=0
    filesize=0
    filepos=0
  
    file$=OpenFileRequester("Choose file(s) for readspeed test:",file$,"All (*.*)|*.*",0,#PB_Requester_MultiSelection)
    While file$
     If ReadFile(#File1,file$)
      filenum+1 ;File counter for main/outermost loop check.
      filesize=Lof(#File1)
      FileBuffersSize(#File1,0) ;We're gonna test readspeed and optimal buffer size with ReadData,
      ;so it would only complicate the results if we used filebuffers in this case as well.
      text$=""
      chunksize=MemorySize(*mem)

      Repeat
       CompilerIf #PB_Compiler_OS=#PB_OS_Windows
        start=timeGetTime_()
       CompilerElse
        start=ElapsedMilliseconds()
       CompilerEndIf
       FileSeek(#File1,0)
       filepos=0
       While Eof(#File1)=#False
        readlen=ReadData(#File1,*mem,chunksize)
        filepos+readlen
        If quitprogram
         Break
        EndIf
       Wend
       CompilerIf #PB_Compiler_OS=#PB_OS_Windows
        stop=timeGetTime_()
       CompilerElse
        stop=ElapsedMilliseconds()
       CompilerEndIf
       If Not quitprogram
        time=stop-start
        If chunksize=MemorySize(*mem)
         base=time
        EndIf
        If base=0 Or time=0
         percentage=0.0
        Else
         percentage=(base/time)*100.0
        EndIf
        text$+Str(chunksize)+","+Str(Int(percentage))+","+Str(stop-start)+","+Str(filesize)+#CRLF$
        chunksize>>1 ;chunksize/2, our next chunksize to test.
        If chunksize<512 ;The smallest chunksize we'll test. (512 is NTFS blocksize if I recall correctly)
         ;the smallest value you can use is 0, which means test all chunksizes including 1 byte.
         chunksize=0 ;You could also use a Break instead here, I prefer to run the full loop though.
        EndIf
       Else
        chunksize=0
       EndIf
      Until chunksize=0 ;Make sure the loop ends, we could also use <1 but not sure if that's a faster check.

      text$+#CRLF$
      WriteString(#File2,text$)
      CloseFile(#File1)
      file$=NextSelectedFileName()
     Else
      MessageRequester("Test Readspeed","Unable to open file(s) for reading(!)")
      file$=""
     EndIf
     If quitprogram
      filenum=0
     EndIf
    Wend
  
    Window_Main(#False)
    If IsThread(thread1)
     WaitThread(thread1)
    EndIf
   Until filenum=0 ;If cancel was chosen in OpenFileRequester or no files, we'll quit the program.

   CloseFile(#File2)
  Else
   MessageRequester("Test Readspeed","Unable to create results file(!)")
  EndIf
 Else
  ;Cancel chosen in savefile requester.
 EndIf
 FreeMemory(*mem) : *mem=#Null
Else
 MessageRequester("Test Readspeed","Unable to allocate 1MB memory(!)")
EndIf

CompilerIf #PB_Compiler_OS=#PB_OS_Windows
 timeEndPeriod_(1)
CompilerEndIf
EDIT: Some spelling stuff, and explained the filerequesters better, no code change.
Last edited by Rescator on Sun May 24, 2009 2:15 am, edited 2 times in total.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

1st set of results.

Post by Rescator »

My test results with various files.

For some reason the smaller files uses more CPU than the larger files.
Not sure why this is, but it is possible that Vista in my case (or it's Filesystem code) is able to pre-read data in the background while it's reading (if that makes sense),
the smaller files are read so fast it's probably not able to buffer ahead. (don't remember the buffersize of my HD either, but it's a few MB as well)
So for some reasons sequential reads using large chunksizes (buffers) and large files is what my system (or Vista) seems optimized for...

The other interesting, but more logical thing is that the larger chunksizes uses less CPU than the smaller ones, this is due to less OS/filesystem and HD overhead with multiple reads, larger chunksizes let the CPU breathe a little during the reading from the disk. (modern systems and HD's use DMA, Direct Memory Access so the cpu is barely used to read stuff into the memory, it's the read loop code itself that eats most of the CPU)

What I find intriguing and creepy is the somewhat erratic speed results on the files after the first 3, they have some truly high read speeds.
Is it possible that their physical block placements on the Hard Drive platter is causing these "abnormally" high read speeds? *scratches head*

The first 3 files and the last two files in these results are more consistent.
What is interesting as well is that on my system/setup it seems 128MB is the ideal chunksize to use for datareading, I always assumed 64KB (a number I guestimated many years ago as a general buffersize for my software) luckily 64KB is not that much slower.

PureBasic's FileBufferSizes defaults to 4096 bytes, as sen in my results I definitely benefit from setting those higher. (I've used 64KB a lot as I mention).

I am interested to see what results the rest of you folks get, as I'm guessing that some systems out there will have wildly different behavior than this.

Have fun comparing folks! ;)

Vista SP1, x86 OS and x86 compile.

Code: Select all

"Chunksize","Normalized speed (100%=1MB speed)","Native speed (ms)","Native size (Bytes)"
1048576,100,284,367087616
524288,111,255,367087616
262144,110,257,367087616
131072,112,253,367087616
65536,108,261,367087616
32768,96,294,367087616
16384,93,305,367087616
8192,69,407,367087616
4096,46,606,367087616
2048,27,1033,367087616
1024,15,1864,367087616
512,8,3541,367087616

1048576,100,277,367087616
524288,109,253,367087616
262144,112,247,367087616
131072,112,246,367087616
65536,105,262,367087616
32768,95,291,367087616
16384,92,301,367087616
8192,68,404,367087616
4096,45,613,367087616
2048,26,1026,367087616
1024,14,1865,367087616
512,7,3531,367087616

1048576,100,271,363081615
524288,111,244,363081615
262144,112,240,363081615
131072,113,238,363081615
65536,106,255,363081615
32768,95,284,363081615
16384,92,294,363081615
8192,68,395,363081615
4096,45,593,363081615
2048,26,1006,363081615
1024,14,1819,363081615
512,7,3454,363081615

1048576,100,6562,362813790
524288,142,4598,362813790
262144,2700,243,362813790
131072,2689,244,362813790
65536,2553,257,362813790
32768,2278,288,362813790
16384,2202,298,362813790
8192,1657,396,362813790
4096,1091,601,362813790
2048,652,1006,362813790
1024,359,1823,362813790
512,189,3465,362813790

1048576,100,6122,363003904
524288,128,4750,363003904
262144,2458,249,363003904
131072,2540,241,363003904
65536,2410,254,363003904
32768,2155,284,363003904
16384,1542,397,363003904
8192,1557,393,363003904
4096,1023,598,363003904
2048,607,1008,363003904
1024,335,1825,363003904
512,176,3459,363003904

1048576,100,6603,367081472
524288,1557,424,367081472
262144,2684,246,367081472
131072,2706,244,367081472
65536,2539,260,367081472
32768,2284,289,367081472
16384,2186,302,367081472
8192,1646,401,367081472
4096,1086,608,367081472
2048,644,1025,367081472
1024,355,1858,367081472
512,187,3516,367081472

1048576,100,24995,1385899141
524288,138,18008,1385899141
262144,2746,910,1385899141
131072,2737,913,1385899141
65536,2574,971,1385899141
32768,2299,1087,1385899141
16384,2206,1133,1385899141
8192,1659,1506,1385899141
4096,1100,2271,1385899141
2048,651,3838,1385899141
1024,357,6993,1385899141
512,188,13295,1385899141

1048576,100,77099,4504387584
524288,129,59694,4504387584
262144,128,60165,4504387584
131072,128,60030,4504387584
65536,128,59815,4504387584
32768,128,60200,4504387584
16384,131,58712,4504387584
8192,130,59063,4504387584
4096,130,58880,4504387584
2048,130,59191,4504387584
1024,130,59231,4504387584
512,128,59843,4504387584
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

I assume lower is better?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Please use v2 of the Readspeed tool instead.
http://www.purebasic.fr/english/viewtopic.php?t=37518

It is overly simplified, no writing of results to disk, it's all in memory.
I've stripped out as much code as possible to make this really tight.
It's also way simpler and less confusing to use. (I hope).

No idea what the issue with v1 was but it's results was way to varying, I can't see any issues with the old code either, did I screw up a var? Hmmm.

Anyway, fool around with v2 instead, simple yes but way better. :)
cxAlex
User
User
Posts: 88
Joined: Fri Oct 24, 2008 11:29 pm
Location: Austria
Contact:

Post by cxAlex »

Results:
Test wrote:---------------------------
Readspeed Test v2.0
---------------------------
1048576 chunksize is the baseline, and = 1.0x
Data based on 1 files and 10 loops per chunksize.
The test took 1 minutes to complete.

524288 chunksize speed = 6.03x
262144 chunksize speed = 5.97x
131072 chunksize speed = 5.93x
65536 chunksize speed = 5.88x
32768 chunksize speed = 5.67x
16384 chunksize speed = 5.32x
8192 chunksize speed = 4.88x
4096 chunksize speed = 4.06x
2048 chunksize speed = 3.07x
1024 chunksize speed = 2.04x
512 chunksize speed = 1.23x
Post Reply