Performance: Reading JCIFS file in Android is slow

First of all, I saw an existing question ( JCIFS: Finding files is too slow to be used ), but that was for Java, not Android, and none of the suggested answers.

I created an Android project for Android SDK 25 (7.1.1) in Android Studio 2.3, linked the library with compile 'jcifs:jcifs:1.3.17'

and typed in the following simple test code. The result is below the code.

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    jcifs.Config.setProperty("jcifs.util.loglevel", "3");
    //jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "false");
    //jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");

    try
    {
        NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("", ID, PASSWORD);
        final SmbFile smb = new SmbFile("smb://192.168.XX.XX/Share/FileName", auth);

        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                Log.d(TAG, "Test Start");

                for(int i = 1000; i<10000; i+=1000)
                    measure(i);

                Log.d(TAG, "Test End");
            }

            private void measure(int bufferSize)
            {
                Log.d(TAG, "=====Buffer: " + bufferSize + "============");
                try
                {
                    byte[] buffer = new byte[bufferSize];
                    int read = 0;
                    InputStream str = smb.getInputStream();
                    long start = System.nanoTime();

                    while(read < 1000000)
                        read += str.read(buffer);

                    long end = System.nanoTime();
                    str.close();
                    float time = (float) ((end - start) / 1000000000d);
                    float speed = (float) read / 1048576 / time;
                    Log.d(TAG, "Time:" + time + ", size =" + read);
                    Log.d(TAG, "Speed =  " + speed + "MB/s");
                }
                catch(IOException exc)
                {
                    exc.printStackTrace();
                }
            }
        });
        t.start();
    }
    catch(Exception exc)
    {
        Log.d(TAG, exc.toString());
    }
}

      

Result

Test Start
=====Buffer: 1000============
Time:2.210785, size =1000000
Speed =  0.43137363MB/s
=====Buffer: 2000============
Time:1.4158936, size =1000000
Speed =  0.6735495MB/s
=====Buffer: 3000============
Time:1.0556641, size =1002000
Speed =  0.9051948MB/s
=====Buffer: 4000============
Time:0.7543335, size =1000000
Speed =  1.2642609MB/s
=====Buffer: 5000============
Time:3.6557617, size =1000000
Speed =  0.26086885MB/s
=====Buffer: 6000============
Time:3.292389, size =1002000
Speed =  0.2902396MB/s
=====Buffer: 7000============
Time:2.9179688, size =1001000
Speed =  0.32715496MB/s
=====Buffer: 8000============
Time:2.462616, size =1000000
Speed =  0.38726068MB/s
=====Buffer: 9000============
Time:3.9379272, size =1008000
Speed =  0.24411413MB/s
Test End

      

The read speed is about 0.2MB / s ~ 1.2MB / s. The device is connected to Wi-Fi 150 Mbps, so in theory it can reach above 10 Mbps. The SMB server isn't slow either. When I copied the file to my laptop, the read speed was around 30MB / s.

Why is it so slow? What should I check? Why is the read speed about 5 times faster (1.2 MB / s) when the buffer size is 4000?

BTW, I've tested copying the same file with other commercial applications. File Commander, Asus File Manager showed similarly low speeds, ES File Explorer showed about 2 MB / s, and Solid Explorer showed about 5 MB / s. Since I'm pretty sure they all use JCIFS (although maybe slightly different versions), there should be a way to achieve at least 5MB / s like Solid Explorer does.

+3


source to share


3 answers


After using WireShark (a network analysis tool) on a Windows machine, I found that no matter what buffer size I set, the SMB read command always gives 4286 bytes for a Windows machine. Seems to be SmbFileInputStream.java

using the maximum buffer size from the server.

But when I saw the packages from Soild Explorer it was 32768 bytes. So I decompiled the Solid Explorer APK (it got confused of course) and saw a file inside it SmbFileInputStream.java

(this file belongs to JCIFS). It looks like the Solid Explorer developers changed this file and installed a larger one readSize

. So I tried something like this. And then I reached 5MB / s for the same code above.



Since JCIFS comes with the LGPL, the fact that Solid Explorer uses modified JCIFS without disclosing the source code is a violation of the JCIFS license. But, well, it seems like a lot of Android app developers are ignoring the library licenses they use anyway. They don't even credit the open source libraries they used.

+2


source


Have you tried: jcifs.Config.setProperty("jcifs.smb.client.dfs.disabled", "true");

In my case (Java though) it was useful for slow connections. By default it isfalse



The only problem for me is that I'm not sure if this property will "break" something else, which works great.

0


source


There is a patch for reading a large buffer size:

From the README:

This patch adds two SMBs that supposedly improve read and write performance significantly. Unfortunately, it is not clear that the entire implementation supports commands properly. Note that in addition to this patch, '& 0xFFFF' needs to be added to SmbTransport.java:doRecv:~437 will appear as:

int size = Encdec.dec_uint16be (BUF, 2) and 0xFFFF;

although this change was made in 1.2.7.

Not sure if this works with Android, but the solution might be similar.

0


source







All Articles