Skip to content

Tweak tool memory use and optimize shared memory when using preload - #16536

Merged
jmchilton merged 28 commits into
galaxyproject:devfrom
mvdbeek:tool_mem_tweaks
Aug 23, 2023
Merged

Tweak tool memory use and optimize shared memory when using preload#16536
jmchilton merged 28 commits into
galaxyproject:devfrom
mvdbeek:tool_mem_tweaks

Conversation

@mvdbeek

@mvdbeek mvdbeek commented Aug 10, 2023

Copy link
Copy Markdown
Member

The first and most effective change is to drop the ElementTree objects after we're done parsing the tool inputs (5e90cfe, 5d9b010).
This means we have to really be sure to have parsed everything. In particular that means we need to parse help and tests (I've limited this to the webapp) and the change_format tags.

We're only partially parsing the tool help, since rst_to_html is relatively slow (~ 30 seconds for 5620 help sections prior to fc8543b, but even then it is 21 seconds, or 13 with the lru_cache). Instead we're lazily converting from the raw help string to rst, where we cache the rst_to_html function.

How to test the changes?

(Select all options that apply)

  • I've included appropriate automated tests.
  • This is a refactoring of components with existing test coverage.
  • Instructions for manual testing are as follows:
    1. [add testing steps and prerequisites here if you didn't write automated tests covering all your changes]

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

@mvdbeek mvdbeek changed the title Tool mem tweaks Tweak memory consumption by tools and optimize shared memory when using preload Aug 17, 2023
@mvdbeek mvdbeek changed the title Tweak memory consumption by tools and optimize shared memory when using preload Tweak tool memory use and optimize shared memory when using preload Aug 17, 2023
Comparing each element of the static options with each incoming element
is very inefficient. Since dictionaries are ordered this can be
simplified to a simple key value insert.

Prior to this change:
```
parse_static_options (/Users/mvandenb/src/galaxy/lib/galaxy/tool_util/parser/xml.py:1207)
function called 7183 times

         313317 function calls in 11.318 seconds

   Ordered by: cumulative time, internal time, call count

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     7183   11.281    0.002   11.318    0.002 xml.py:1207(parse_static_options)
    99675    0.029    0.000    0.033    0.000 __init__.py:1004(string_as_bool)
    99675    0.004    0.000    0.004    0.000 {method 'lower' of 'str' objects}
    99601    0.004    0.000    0.004    0.000 {method 'append' of 'list' objects}
     7183    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        0    0.000             0.000          profile:0(profiler)
```
after:
```
*** PROFILER RESULTS ***
parse_static_options (/Users/mvandenb/src/galaxy/lib/galaxy/tool_util/parser/xml.py:1207)
function called 7183 times

         220899 function calls in 0.260 seconds

   Ordered by: cumulative time, internal time, call count

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     7183    0.230    0.000    0.259    0.000 xml.py:1207(parse_static_options)
    99675    0.026    0.000    0.029    0.000 __init__.py:1004(string_as_bool)
    99675    0.004    0.000    0.004    0.000 {method 'lower' of 'str' objects}
     7183    0.000    0.000    0.000    0.000 {method 'values' of 'dict' objects}
     7183    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        0    0.000             0.000          profile:0(profiler)
```

This is most due to openms_idfilter, which has 2928 static options.
functools.cache is new in python 3.9
For details see benoitc/gunicorn#1640 and
https://instagram-engineering.com/copy-on-write-friendly-python-garbage-collection-ad6ed5233ddf

I think this is the most subtle to test change. I believe this is
working.

I started a gunicorn instance with 4 workers:

```
GALAXY_CONFIG_FILE="config/galaxy.yml" gunicorn 'galaxy.webapps.galaxy.fast_factory:factory()' -k galaxy.webapps.galaxy.workers.Worker --pythonpath lib --bind=localhost:8080 --config lib/galaxy/web_stack/gunicorn_config.py --preload -w 4
```

Then i use the following script against that instance

```
import threading
import requests

def req():
    for i in range(10000):
        requests.get('http://localhost:8080/history/current_history_json')

for i in range(10):
    threading.Thread(target=req).start()
```

I see that the memory consumption increases much more *during* requests
without this commit. It eventually decreases again, but I think not to
the same baseline level (hard to tell without more elaborate testing). I
attribute the higher memory load during requests to the fact that the
garbage collection requiring to inspect more objects, taking more time
to run and therefor not running as fast? I'm really not sure, I think we
should just roll this out and see, it should be fairly obvious from the
grafana dashboards.
@jmchilton

Copy link
Copy Markdown
Member

Really cool fixes!

@mvdbeek
mvdbeek marked this pull request as ready for review August 17, 2023 17:29
@github-actions github-actions Bot added this to the 23.2 milestone Aug 17, 2023
@mvdbeek

mvdbeek commented Aug 17, 2023

Copy link
Copy Markdown
Member Author

I've tested this against tools-iuc. There are some issues with tmpdir mounting, which I can fix with locally

diff --git a/lib/galaxy/tool_util/deps/docker_util.py b/lib/galaxy/tool_util/deps/docker_util.py
index 1cb3b8f1d5..2b0d2988ab 100644
--- a/lib/galaxy/tool_util/deps/docker_util.py
+++ b/lib/galaxy/tool_util/deps/docker_util.py
@@ -150,16 +150,16 @@ def build_docker_run_command(
         command_parts.append("--rm")
     if run_extra_arguments:
         command_parts.append(run_extra_arguments)
-    if set_user:
-        user = set_user
-        if set_user == DEFAULT_SET_USER:
-            # If future-us is ever in here and fixing this for docker-machine just
-            # use cwltool.docker_id - it takes care of this default nicely.
-            euid = os.geteuid()
-            egid = os.getgid()
-
-            user = "%d:%d" % (euid, egid)
-        command_parts.extend(["--user", user])
+    # if set_user:
+    #     user = set_user
+    #     if set_user == DEFAULT_SET_USER:
+    #         # If future-us is ever in here and fixing this for docker-machine just
+    #         # use cwltool.docker_id - it takes care of this default nicely.
+    #         euid = os.geteuid()
+    #         egid = os.getgid()
+
+    #         user = "%d:%d" % (euid, egid)
+    #     command_parts.extend(["--user", user])
     full_image = image
     if tag:
         full_image = f"{full_image}:{tag}"

I was ready to attribute this to OSX (with the 5? different ways you can run docker) , but why would that be a problem for the IUC CI tests ? Unless something has fundamentally changed in docker ?

Comment thread lib/galaxy/tools/__init__.py Outdated
Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com>
@mvdbeek

mvdbeek commented Aug 18, 2023

Copy link
Copy Markdown
Member Author

I re-ran one of the failing tests in https://github.com/mvdbeek/tools-iuc/actions/runs/5900317393/job/16004762060?pr=23 and it passed, I guess at the time of running I didn't include #16533 in the branch. So this should be ready to go.

@mvdbeek
mvdbeek requested a review from a team August 22, 2023 15:05
@jmchilton
jmchilton merged commit 152c802 into galaxyproject:dev Aug 23, 2023
@jmchilton

Copy link
Copy Markdown
Member

Thanks for the fixes! I really appreciate the added typing too!

@github-actions

Copy link
Copy Markdown

This PR was merged without a "kind/" label, please correct.

@nsoranzo nsoranzo added kind/enhancement kind/refactoring cleanup or refactoring of existing code, no functional changes labels Aug 26, 2023
@mvdbeek mvdbeek mentioned this pull request Aug 26, 2023
4 tasks
@mvdbeek mvdbeek added the highlight/admin Included in admin/dev release notes label Jan 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/tool-framework area/util highlight/admin Included in admin/dev release notes kind/enhancement kind/refactoring cleanup or refactoring of existing code, no functional changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants