Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Apple Silicon, M1] Low database (MariaDB) performance, projects feel generally sluggish and slow #5389

Closed
3 tasks done
slashrsm opened this issue Feb 24, 2021 · 31 comments
Closed
3 tasks done

Comments

@slashrsm
Copy link

slashrsm commented Feb 24, 2021

  • I have tried with the latest version of Docker Desktop
  • I have tried disabling enabled experimental features
  • I have uploaded Diagnostics
  • Diagnostics ID: 7aae96b3-4f1a-4e04-8b94-c6f9e5ff0ca5/20210224131759

Information

I have a bunch of client projects (PHP, mostly Drupal, some Laravel and Symfony) are we standardized on DDEV local environment. After switching from 2018 i7 MBP to M1 MacBook Air I noticed that my projects feel generally slower than before. I noticed that database imports take way longer than they used to, so I decided to investigate and compare performance between the two machines. I did make sure that M1 runs arm64 images. Here are the benchmarks that I performed:

  1. Database import: in order to remove any potential DDEV issues from the equation I tested using mariadb:latest image. Since I can't share client databases, I found an employees sample database online (with some unit tests) and created fresh Drupal install with some generated content and exported the database. EDIT: Added benchmarks for imports of Drupal 9 Umami dump.
  2. CPU-heavy PHP script: https://gist.github.com/slashrsm/e3c3b44458d16f41033fd3ab10a1beb4
  3. Memory-heavy PHP script: https://gist.github.com/slashrsm/13e0f4290788dc1d8c22a77eb1a5f2b0
  4. Bonnie++: https://gist.github.com/slashrsm/ea0e5f05f4620d50ace1e8b85599af69
  5. Drupal install: inside ddev environment
  6. Drupal cache rebuild: inside ddev environment
  7. Laravel fresh migration: this is a client project with ~50 migrations, no data just table creation and modifications.
  8. Gzip: Downloaded Docker.dmg of latest Apple Silicon preview and gzipped it: gzip -c Docker.dmg > /dev/null

M1 is not always slower. For single-threaded CPU and memory heavy tasks it is consistently twice as fast as Intel. But it can get slow in more complex situations. I suspect the database, but even there the results are not consistent. For some datasets it performs very well and for some it gets very slow.

In two cases where database performance was much slower on M1 I tried to do the same operation using the database server running on host machine. In both cases it was significantly faster.

EDIT: I tried Drupal 9 Umami import (benchmark 3.) on Intel with experimental virtualization.framework and was able to reproduce performance regression that I see on M1.

EDIT 2: It seems that the problem is indeed in the virtualization.framework and not in Docker. See this comment for more info.

Apple Silicon MacBook Air (latest docker - build 60984, DDEV 1.17.0-alpha6)

  1. Database import (client project):
    • import, in container: 2m 53.436s
    • import, on host/bare metal: 13.822s
  2. Database import (Drupal with generated content): 3m 30.16s
  3. Database import (Drupal 9 Umami): 1m 19.77s
  4. Database (Employees sample database):
    • Import: 35.673s
    • test_employees_md5.sql: 6.117s
    • test_employees_sha.sql: 4.606s
  5. CPU-heavy PHP script (PHP 7.4.15): 0.367s
  6. Memory-heavy PHP script:
    • Allocation: 2.89s
    • Access: 0.70s
    • Rewrite: 9.17s
    • Access: 0.71s
  7. Drupal install: 1m 35s
  8. Drupal cache rebuild: 7.845s
  9. Laravel fresh migration:
    • running inside DDEV: 29.172s
    • running inside DDEV, pointed to MariaDB running on host/bare metal: 4.149s
  10. Gzip: 13.830s
  11. Bonnie++:
Using uid:0, gid:0.
Writing a byte at a time...done
Writing intelligently...done
Rewriting...done
Reading a byte at a time...done
Reading intelligently...done
start 'em...done...done...done...done...done...
Create files in sequential order...done.
Stat files in sequential order...done.
Delete files in sequential order...done.
Create files in random order...done.
Stat files in random order...done.
Delete files in random order...done.
Version  1.98       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Name:Size etc        /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
f72414203882 32008M 1009k  97  602m  62  153m  11 3698k  94  264m  10  7352 207
Latency              8285us     440ms    3372ms    4674us   91627us   29839us
Version  1.98       ------Sequential Create------ --------Random Create--------
f72414203882        -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                 16 -40238896  66 +++++ +++ +++++ +++ +++++ +++ +++++ +++ +++++ +++
Latency              5254us     339us     697us    4229us      39us     730us
1.98,1.98,f72414203882,1,1614105274,32008M,,8192,5,1009,97,616723,62,156340,11,3698,94,270266,10,7352,207,16,,,,,31510,66,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,8285us,440ms,3372ms,4674us,91627us,29839us,5254us,339us,697us,4229us,39us,730us

2015 MBP, i7 2,6Ghz, hexa-core (latest docker - build 51484, DDEV 1.17.0-alpha6):

  1. Database import (client project): 21.130s
  2. Database import (Drupal with generated content): 1m 27.98s
  3. Database import (Drupal 9 Umami):
    • Using hypervisor.framework: 3.129s
    • Using virtualization.framework: 1m 41.14s
  4. Database (Employees sample database):
    • Import: 46.952s
    • test_employees_md5.sql: 55.343s
    • test_employees_sha.sql: 49.379s
  5. CPU-heavy PHP script (PHP 7.4.15): 0.616s
  6. Memory-heavy PHP script:
    • Allocation: 33.15s
    • Access: 1.48s
    • Rewrite: 92.15s
    • Access: 1.38s
  7. Drupal install: 29s
  8. Drupal cache rebuild: 2.916s
  9. Laravel fresh migration:
    • Running inside DDEV: 3.093s
  10. Gzip: 14.899s
  11. Bonnie++:
Using uid:0, gid:0.
Writing a byte at a time...done
Writing intelligently...done
Rewriting...done
Reading a byte at a time...done
Reading intelligently...done
start 'em...done...done...done...done...done...
Create files in sequential order...done.
Stat files in sequential order...done.
Delete files in sequential order...done.
Create files in random order...done.
Stat files in random order...done.
Delete files in random order...done.
Version  1.98       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Name:Size etc        /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
a21f94cfbb28 32024M  652k  99  297m  92  200m  74 2100k  99  330m  92 10282 276
Latency             14781us    2060ms    2692ms   25775us   95868us    3784us
Version  1.98       ------Sequential Create------ --------Random Create--------
a21f94cfbb28        -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                 16     0  88 +++++ +++ 724249376  93     0  93 +++++ +++ 724249376  91
Latency              7858us     418us    3617us    1481us     249us    3287us
1.98,1.98,a21f94cfbb28,1,1614105338,32024M,,8192,5,652,99,304386,92,204552,74,2100,99,337517,92,10282,276,16,,,,,20580,88,+++++,+++,31722,93,25323,93,+++++,+++,30195,91,14781us,2060ms,2692ms,25775us,95868us,3784us,7858us,418us,3617us,1481us,249us,3287us

Steps to reproduce the behavior

There are some tests that are not reproducible as they related to the specific client projects. But I did manage to create a few benchmarks where the scripts and datasets are available to everyone. Those are items nr. 2, 3, 4, 5, 6, 10 and 11.

@stephen-turner stephen-turner added the area/m1 M1 preview builds label Feb 24, 2021
@slashrsm slashrsm changed the title Low database (MariaDB) performance, projects feel generally sluggish and slow [Apple Silicon, M1] Low database (MariaDB) performance, projects feel generally sluggish and slow Feb 24, 2021
@stephen-turner
Copy link
Contributor

stephen-turner commented Feb 24, 2021

Thank you for the report, @slashrsm. There are known issues with disk speed on write-heavy workloads, which we are already talking to Apple about.

There are two more things that would be interesting to test if you are so inclined.

  1. Can you reproduce the slowness inside a VM created using https://github.com/evansm7/vftool, without any Docker code?
  2. We posted an experimental Intel build to the dev preview channel last week that supported switching between the new virtualization.framework and the old hypervisor.framework. Do you see much worse performance in the former than the latter?

Both of these would suggest that it is a MacOS problem rather than a Docker problem.

@slashrsm
Copy link
Author

@stephen-turner Thank you.

  1. Can you reproduce the slowness inside a VM created using https://github.com/evansm7/vftool, without any Docker code?

I will try and report back.

  1. We posted an experimental Intel build to the dev preview channel last week that supported switching between the new virtualization.framework and the old hypervisor.framework. Do you see much worse performance in the former than the latter?

I did try it for some of the benchmarks (Gzip and database import) and the performance was comparable to hypervisor.framework build.

@slashrsm
Copy link
Author

@rfay Suggested to add benchmark for Drupal 9 Umami database dump (also publicly available), so I added that.

@slashrsm
Copy link
Author

@stephen-turner Excuse me, but it turns out that I didn't enable the experimental virtualization.framework feature when I was testing last time. Tried it again with Drupal 9 Umami import (benchmark 3.) and I was able to see similar regression on Intel as I am seeing on M1:

  • Intel hypervisor.framework: 3.129s
  • Intel virtualization.framework: 1m 41.14s
  • M1: 1m 19.77s

@slashrsm
Copy link
Author

I managed to test the database import in a bare virtualization.framework VM (followed these steps). I imported Drupal D9 Umami database, which took 3.129s on Intel Docker and 1m 19.77s on M1 Docker. I got the following results:

Import into MariaDB: 2m15.416s
Import into MySQL: 10m 19.303s

Ubuntu 20.04 comes with MariaDB 10.3, while I used 10.5 in my previous benchmarks. I am not sure why it is even slower, but it could be to the older version.

It does seem that the problem is in the virtualization.framework itself though.

@stephen-turner
Copy link
Contributor

Thanks for that, @slashrsm, that's really helpful. I think that confirms our suspicions. As I said above, we've talked to Apple about this too. We're also wondering if we can speed it up by flushing less often: there would be a slight risk of lost data if there was a power cut or something, but in a development context that might be an acceptable trade-off.

cc @djs55 for visibility

@rfay
Copy link

rfay commented Mar 16, 2021

This is really quite an amazing slowness on a system that in most ways is way faster than anything else. Such a surprise every time I import a database to see it run about 10x slower than amd64.

@Elycin
Copy link

Elycin commented Mar 21, 2021

I don't think this is specific to database performance, Just experienced this myself where it took 484 seconds to chmod a NodeJS + PHP project consisting of 450 MB in extracted packages.

Pinging a static webpage running inside of the docker container using wrk resulted in the following benchmarks on my MBP M1.

elycin@Elys-MacBook-Pro wrk % ./wrk -t8 -c1k -d30s http://localhost:80/
Running 30s test @ http://localhost:80/
  8 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.33s   331.76ms   2.00s    73.96%
    Req/Sec    13.99     10.17    70.00     80.65%
  2820 requests in 30.11s, 578.32KB read
  Socket errors: connect 0, read 3241, write 0, timeout 2313
  Non-2xx or 3xx responses: 2820
Requests/sec:     93.67
Transfer/sec:     19.21KB

@slashrsm
Copy link
Author

It seems to be related to slow I/O in some cases. It is listed under known issues for the latest preview.

@dwsteele
Copy link

Using tmpfs helps a lot, which may be useful for development purposes at least.

Here is a comparison of running a pgBackRest integration test (which runs Postgres instances) on Intel (2020 iMac) and M1 (2020 Air):

test/test.pl --vm=co7 --module=real --clean --log-level-test-file=off

normal:

Intel VirtualBox: 224s
Intel Docker: 136s
M1 Docker: 980s-1600s (sometimes hangs)

tmpfs:

Intel VirtualBox: 120s
Intel Docker: 124s
M1 Docker: 130s

@rfay
Copy link

rfay commented Mar 25, 2021

Just a happy note that @djs55 's current experimental build seems to have a huge effect on this issue as well. Massively faster to do a db import. See #5476 (comment)

@stephen-turner
Copy link
Contributor

Thanks, @rfay, that's very interesting.

@stephen-turner
Copy link
Contributor

Everyone watching this thread, please try the new RC2 build at https://docs.docker.com/docker-for-mac/apple-m1/ and give us feedback whether it solves this problem (and whether it causes any new problems!). Thank you.

@tommoor
Copy link

tommoor commented Mar 26, 2021

Just tried the RC2 and first impressions are very good – test suite now runs faster than on Intel, previously it was 10x slower or more. Will report back if any other problems become apparent!

@dwsteele
Copy link

Yes, that helps a lot.

Here is the updated comparison of running a pgBackRest integration test (which runs Postgres instances) on Intel (2020 iMac) and M1 (2020 Air):

test/test.pl --vm=co7 --module=real --clean --log-level-test-file=off

normal:

Intel VirtualBox: 224s
Intel Docker: 136s
M1 Docker: 135s

tmpfs:

Intel VirtualBox: 120s
Intel Docker: 124s
M1 Docker: 125s

There is one problem I noticed however. /dev/null is being created as read/write only for root:

docker@pgbackrest-test:~$ ls -lah /dev/null
crw-rw---- 1 root root 1, 3 Mar 26 17:59 /dev/null

I had to fix this before I could run our tests with:

rm /dev/null
mknod /dev/null c 1 3
chmod 666 /dev/null

Presumably this has something to do with qemu but it certainly represents a behavioral change from Intel Docker or prior M1 versions. Not a Docker expert so perhaps there is something I am missing here.

@stephen-turner
Copy link
Contributor

Thanks @dwsteele, we'll look into the /dev/null issue.

@alxndrbauer
Copy link

alxndrbauer commented Mar 26, 2021

RC2 is way faster for me.

Apple M1 MacBook Pro 16GB RAM

Resources

CPU: 2
RAM: 6 GB

Import of an 2GB Database:

RC1: ~120 Min
RC2: ~53 Min

This is a huge improvement for me.
I'm still stuck with MySQL 5.7, so Rosetta 2 is probably the reason why its still 50 min. On lInux its about 10 Min.

Edit:
MariaDB 10.5 takes only 5 min 😁

PHPUnit tests with a lot I/O (sqlite Fixtures) in an not mounted folder

RC1: ~30 Min
RC2: ~3 Min

Again big improvement.

thx alot

@Tenzer
Copy link

Tenzer commented Mar 26, 2021

Thanks for the new release, it's a massive improvement. The time taken for a Python test suite to run is equivalent between using tmpfs and a volume with RC2, whereas using a volume on prior versions would take perhaps 10 times as long to run.

@slashrsm
Copy link
Author

I can also confirm that I saw a massive improvement with RC2 on qemu.

@djs55
Copy link
Contributor

djs55 commented Mar 29, 2021

@dwsteele thanks for your report. I'm perplexed by the /dev/null problem -- could you share a small repro example to demonstrate the issue? For me whenever I run a container I see normal permissions e.g.:

% docker run -it alpine sh
/ # ls -l /dev/null
crw-rw-rw-    1 root     root        1,   3 Mar 29 13:21 /dev/null

The strange thing is that the choice of hypervisor (qemu vs virtualization.framework vs hyperkit) should not affect the filesystem presented to containers. Perhaps different timing has exposed a race condition somewhere?

@dwsteele
Copy link

@djs55 I have attached the Dockerfile. We are testing this for dev purposes on Intel/M1 Macs (currently we use Vagrant/VirtualBox on Intel). It's pretty unconventional but worked OK until the issue with the qemu-based M1 Docker.

Dockerfile.txt

@rovo79
Copy link

rovo79 commented Mar 31, 2021

Everyone watching this thread, please try the new RC2 build at https://docs.docker.com/docker-for-mac/apple-m1/ and give us feedback whether it solves this problem (and whether it causes any new problems!). Thank you.

Is this considered a hybrid emulation approach? Is there a potential future release that would try to utilize BigSur's virtualization.framework?

@stephen-turner
Copy link
Contributor

@rovo79 The previous builds all used virtualization.framework: this build allows you to swap between qemu and virtualization.framework.

@crbelaus
Copy link

crbelaus commented Apr 1, 2021

Everyone watching this thread, please try the new RC2 build at https://docs.docker.com/docker-for-mac/apple-m1/ and give us feedback whether it solves this problem (and whether it causes any new problems!). Thank you.

I've updated my Docker installation to RC2 and database performance has improved drastically.
With RC1 restoring a Postgres backup clocked about 1 hour, with RC2 it clocks under 3 minutes 🎉

@giannoug
Copy link

giannoug commented Apr 1, 2021

Overall this feels snappier, but applying Postgres migrations is still really slow to the point that my project doesn't even boot (it boots after all migrations are applied, but I manually stop it at 30m since there is no point waiting more than a couple of minutes). Migrations create more than 140 tables, they also add and remove some columns.

I have tried both with "Use new virtualization framework" option enabled and disabled. I also completely uninstalled Docker (using the Uninstall option from the menu, then dragging the app to the trash can) before installing RC2.

@MrThePlague
Copy link

Overall this feels snappier, but applying Postgres migrations is still really slow to the point that my project doesn't even boot (it boots after all migrations are applied, but I manually stop it at 30m since there is no point waiting more than a couple of minutes). Migrations create more than 140 tables, they also add and remove some columns.

I have to say that my experience has been quite the opposite with regards to Postgres, although I don't have anywhere near as many tables as that (only 35). Prior to RC2, the migrations would take 1-2 minutes, but now it's 1-2 seconds.

One thing I have noticed though, is that RC2 has a much more significant impact on battery life. I assume this is because virtualization.framework is well optimized in this regard vs QEMU?

@stephen-turner
Copy link
Contributor

Probably, yes. We have noticed slightly higher CPU with qemu.

@josepernia8
Copy link

I just downloaded Preview RC3 and I have still issues running migrations in apple silicon.

@dwsteele
Copy link

@stephen-turner GA 3.3.1 fixed the issue I had with /dev/null permissions. I see it in the release notes but just wanted to report that it worked in my case as well. Thanks!

@stephen-turner
Copy link
Contributor

I'm going to close this ticket now. The original issue is fixed by making virtualization framework no longer the default.

@docker-robott
Copy link
Collaborator

Closed issues are locked after 30 days of inactivity.
This helps our team focus on active issues.

If you have found a problem that seems similar to this, please open a new issue.

Send feedback to Docker Community Slack channels #docker-for-mac or #docker-for-windows.
/lifecycle locked

@docker docker locked and limited conversation to collaborators Jun 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests