caseSensitiveFS=false (the default) scan performance penalty scales up, and it can be extreme

If I remember right, CI produces apks from PRs. So you can update the syncthing submodule with that patch and PR that to the android repo. Otherwise of you have docker, building is very simple.

The listdir cache is intended to prevent that behaviour, but I suspect the cache time is too low. I think I mentioned that as some point.

1 Like

Sorry for necromancing this thread, but I finally managed to resurrect my old PR:

Feel free to test the current main branch to see if it has a meaningful impact for case-insensitive scanning :slightly_smiling_face:

1 Like

Thanks a lot for thinking about me, I’ll give it a test performance-wise (I hope I manage somehow to find all the one-liners for the previous test…); given that the use-case I’m mostly interested in is Android (due to unbelievably bad performance for just walking the directory) I’m migrating a bunch of setups I have to syncthing-fork (as the official Android Syncthing is frozen quite a bit in the past) and as soon as I see some updated syncthing-fork version (presumably pulling the discussed fixes) I’ll re-test everything.

I recently got a Samsung Galaxy Android tablet and file scanning was brutally slow. I also have an Android phone where file scanning on the same folder was much faster, which I found weird since the tablet has a much faster CPU.

I decided to look into it and found this post after some time. The speedup from setting caseSensitiveFS to true was massive on the tablet. I’m not running Syncthing all the time on my Android devices because of the battery usage and have them set to sync while charging. But if I want to access a file between charging I start Syncthing manually causing a full file scan and it will not sync until that is done. That makes the slow file scanning especially annoying for me since this is a situation where I want to quickly sync some files and stop Syncthing again.

I think the potential performance hit should be more clearly documented. It would also benefit more people if it’s possible to detect if a folder is case sensitive and automatically disable the safety checks.

Here are the scanning times with caseSensitiveFS on and off. The folder has around 27000 files, 350 folders and is 120GB. Syncthing v2.0.11 (64-bit ARM).

Samsung Galaxy tablet:

  • 1230s (or about 20min) with caseSensitiveFS false
  • 10s with caseSensitiveFS true (123x faster!)

Android phone:

  • 21s with caseSensitiveFS false
  • 16s with caseSensitiveFS true

P.S. Thank you so much for making and maintaining Syncthing! :blue_heart:

That’s a massive difference, but please keep in mind that Android’s user storage is case-insensitive, so enabling this option will eventually very likely lead to data loss at some point.

1 Like

You are right. I thought that Androids storage was case sensitive unless external media like an SD card was used. But turns out that internal app storage is case sensitive, but the storage shared between apps (/storage/emulated) is case insensitive.

After reading more up on the issue I can also see why Syncthing doesn’t want to detect if a filesystem is case sensitive/insensitive.

I still wonder why the difference between the scanning time on my Android tablet and my Android phone is so big. The performance hit on my phone is totally acceptable, but on the tablet it’s a problem.

Since Syncthing v2.1.3 have now been posted to Google Play I did some new tests. I hoped that this version would improve the situation since it contains some performance improvements and changes to casefs.

What I found was that the scanning time on my Samsung Galaxy tablet is even worse now. Scanning time with caseSensitiveFS false is now about 1 hour and 2 minutes. Though this may be because the amount of files and folders changed. The folder has around 30000 files, 600 folders and 125GB data.

To narrow down what the problem could be, I looked at the metrics endpoint. What I did was:

  1. Set caseSensitiveFS true
  2. Restart Syncthing
  3. Wait until initial folder scan was done (took around 10s)
  4. Captured /metrics
  5. Set caseSensitiveFS false
  6. Wait until folder scan was done (took 1h and 2m)
  7. Captured /metrics

I have extracted the interesting findings below.

First capture:

syncthing_fs_operation_seconds_total{operation="dirnames",root="/storage/emulated/0"} 4.650544013999998
syncthing_fs_operation_seconds_total{operation="lstat",root="/storage/emulated/0"} 3.6341790729998857
syncthing_fs_operations_total{operation="dirnames",root="/storage/emulated/0"} 618
syncthing_fs_operations_total{operation="lstat",root="/storage/emulated/0"} 136937
syncthing_model_folder_scan_seconds_total{folder="xxxxx-xxxxx"} 13.994285307999998

Second capture:

syncthing_fs_operation_seconds_total{operation="dirnames",root="/storage/emulated/0"} 3295.4242555539654
syncthing_fs_operation_seconds_total{operation="lstat",root="/storage/emulated/0"} 35.56591888400749
syncthing_fs_operations_total{operation="dirnames",root="/storage/emulated/0"} 24992
syncthing_fs_operations_total{operation="lstat",root="/storage/emulated/0"} 273958
syncthing_model_folder_scan_seconds_total{folder="xxxxx-xxxxx"} 3373.0284832769903

So it seems most of the scanning time is spend on “dirnames” operations. This could also explain the increased scanning time since my last post, since there are more directories now.

Note that I am syncing my “home” folder /storage/emulated/0 but have excluded problematic folders like Android.

Are there anything I can do to help getting this fixed?

TL:DR: Syncthing spends a lot of time on “dirnames” operations on a Samsung Galaxy Android tablet when caseSensitiveFS is false.

Interesting. Is the hierarchy somewhat deep, in terms of directories in directories?

I suspect you just need a longer cache time, but it’s not adjustable from the outside at the moment. A single dir listing takes on average 1/8th of a second in your metrics, and we cache them for a second. I can see cases where that expires more or less before it has time to be useful given how slow these are.

No not really, the deepest directory I have is 6 deep. Most are less than that.

Using Termux I have measured how long it takes to run ls in all the synced folders. I created this ugly one-liner using AI to recursively measure how long time it took to run ls in all directories:

total=0; count=0; while read d; do s=$(date +%s%3N); ls "$d" >/dev/null; e=$(date +%s%3N); diff=$((e-s)); echo "$d $diff ms"; total=$((total+diff)); count=$((count+1)); done < <(find . -type d); echo "Average: $((total/count)) ms"

Most folders have few files and takes between 15-30ms to list.

But interestingly there are some outliers. The worst was a folder with 2202 files which took 673ms to list. There is one with 2021 files that took 148ms and about six other folders that also took around that time.

I’m not sure how useful this is, it could also be that ls just spends a lot of time printing all the filenames.