B4J Question Help to make a DRIVE SPEED TESTER

max123

Well-Known Member
Licensed User
Longtime User
Hi developers,

I wanted to make something similar to CrystalDiskMark on B4J.
https://crystalmark.info/en/software/crystaldiskmark/

The problem here in my code is that the file is written in async way, so measure the time it took cannot work here.

Really this is a simple test, but my goal is to write on canvas the current average while the file transfer, instead of show a number at end of file transfer.
To do this I need to track current data write/read bytes number.

How to do it ?
Maybe using CountingOutputStream - CountingInputStream or something else that track current write/read bytes ?
What is a best approach to do this ?

I've attached my simple code and zip project, if someone want help to improve it or have suggestions I'm really happy.

Many thanks

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
 
    Private btnStart As Button
    Private lblReadSpeed As Label
    Private lblWriteSpeed As Label
    Private cmbDevices As ComboBox
    Private btnRefresh As Button
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
 
    For Each drive As String In ListRoots
        Log("Found drive: " & drive)
        cmbDevices.Items.Add(drive)
    Next
End Sub

Sub btnStart_Click
    TestFileIO(File.DirApp, "Test.dat")  ' JUST FOR TEST WE USE APPLICATION FOLDER HERE
End Sub

Public Sub TestFileIO(Dir As String, FileName As String) 'As Boolean
 
    If File.Exists(Dir, FileName) Then
        File.Delete(Dir, FileName)  ' Delete the file if already exists
    End If
 
    Log("Testing file I/O with " & File.Combine(Dir, FileName))

    File.OpenOutput(Dir, FileName, False)
 
    Dim len As Int = Power(1024, 2) * 10  '10MB = 10485760 Bytes   (1MB = 1.048.576,  10MB = 10.485.760,  100MB = 104.857.600)
 
    Dim start As Long
    Dim writeElaps As Long
    Dim writeAvg As Int
    Dim readElaps As Long
    Dim readAvg As Int
 
'    Dim sb As StringBuilder  ' JUST FOR TEST WE USE StringBuilder HERE, BUT B4XByteBuilder SHOULD BE USED INSTEAD
'    sb.Initialize
 
    Dim bb As B4XBytesBuilder
    bb.Initialize
 
    fx.Msgbox(MainForm, "We now write a buffer of " & len & " Bytes = " & (len/1024) & " MB, please press OK to write buffer.", "MESSAGE")   ' SPARTANO NON CORRETTO, DA CORREGGERE
 
    For i = 1 To len
        bb.Append(Array As Byte(1)) ' Should write a buffer instead of single byte at time
    Next
 
    fx.Msgbox(MainForm, "DONE. We now write a buffer of " & bb.Length & " Bytes to device. Press OK to start", "MESSAGE")

    start = DateTime.Now
    File.WriteBytes(Dir, FileName, bb.ToArray) ' PROBABLY HERE USE A LOOP TO WRITE FILE IN CHUNKS TO TEST DIFFERENT BUFFER SIZE, EG 4K, 8K, 16K ETC...
    writeElaps = DateTime.Now - start
 
    writeAvg = len / (writeElaps/1000)
    lblWriteSpeed.Text = NumberFormat2((writeAvg/1000), 0, 2, 2, False)
    fx.Msgbox(MainForm, "DONE." & CRLF & CRLF & bb.Length & " Bytes written to device in " & writeElaps & " Milliseconds = " & _
                                                 NumberFormat2((writeElaps/1000), 0, 1, 1, False) & " Seconds" & CRLF & CRLF & "AVG: " & _
                                                 writeAvg & " Bytes/s = " & NumberFormat2((writeAvg/1000), 0, 2, 2, False) & " MB/s" & CRLF & CRLF & _
                                                 "Press OK to read back and test read speed.", "MESSAGE")
 
    start = DateTime.Now
    Dim readBytes() As Byte = File.ReadBytes(Dir, FileName)  ' PROBABLY HERE USE A LOOP TO READ FILE IN CHUNKS TO TEST DIFFERENT BUFFER SIZE, EG 4K, 8K, 16K ETC...
    readElaps = DateTime.Now - start
 
    readAvg = len / (readElaps/1000)
    lblReadSpeed.Text = NumberFormat2((readAvg/1000), 0, 2, 2, False)
 
    If readBytes.Length = len Then
        fx.Msgbox(MainForm, "DONE." & CRLF & CRLF & readBytes.Length & " Bytes read from device in " & readElaps & " Milliseconds = " & _
                                                 NumberFormat2((readElaps/1000), 0, 1, 1, False) & " Seconds" & CRLF & CRLF & "AVG: " & _
                                                 readAvg & " Bytes/s = " & NumberFormat2((readAvg/1000), 0, 2, 2, False) & " MB/s" & CRLF & CRLF & _
                                                 "Press OK to read back and test read speed.", "MESSAGE")
    Else
        fx.Msgbox(MainForm, "OOOOPS. The number of read bytes do not match the written data." & CRLF & CRLF & "WRITE: " & len & " Bytes" & CRLF & "READ: " & readBytes.Length, "MESSAGE")
    End If
 
'    Return File.Delete(Dir, FileName) ' Finally delete the file
End Sub

Sub ListRoots As List
    Dim jo As JavaObject
    Dim o() As Object = jo.InitializeStatic("java.io.File").RunMethod("listRoots", Null)
    Return o
End Sub
 
Private Sub btnRefresh_Click
    cmbDevices.Items.Clear
    For Each drive As String In ListRoots
        Log("Found drive: " & drive)
        cmbDevices.Items.Add(drive)
    Next
End Sub
 

Attachments

  • Screen Shot 02-06-23 at 02.22 PM.PNG
    Screen Shot 02-06-23 at 02.22 PM.PNG
    12.4 KB · Views: 79
  • DISK_SPEED_TEST.zip
    3.9 KB · Views: 48
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
No people interested to this ?
 
Upvote 0

teddybear

Well-Known Member
Licensed User
The problem here in my code is that the file is written in async way, so measure the time it took cannot work here.
Why do you say that the file is written in async way, so measure the time it took cannot work here ?
As long as the file is large enough, you can measure the time which writting file takes.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Why do you say that the file is written in async way, so measure the time it took cannot work here ?
As long as the file is large enough, you can measure the time which writting file takes.
Thanks for reply @teddybear, please try the project, it do no wait, start write bytes in background and then just return to application even if not all bytes are written, so the resulting time is just milliseconds.

The resulting file is written right, it is the exact size, but I cannot measure the time it took.
 
Last edited:
Upvote 0

teddybear

Well-Known Member
Licensed User
Thanks for reply @teddybear, please try the project, it do no wait, start write bytes in background and then just return to application even if not all bytes are written, so the resulting time is just milliseconds.

The resulting file is written right, it is the exact size, but I cannot measure the time it took.
10M is too small, Try 1G size file
B4X:
Dim len As Int = Power(1024, 2) * 1000
 
Upvote 0
Top