No more needed in Python 3. Following commit 72e1511d ("globals: Fix a
race condition in namedtuple_to_dict"), the dynamic view on the keys is
as well transformed into a list.
Related to #3181
Commit 445d20dc ("plugins: containers: Refactor") changed update() so
that, stats are added if any of is_key_in_container_and_not_hidden()
or is_key_absent_in_container() is true.
This could be replaced by the negation of is_key_in_container_and_hidden()
Part-of: #2801
Suggested-by: Jasmin Blackshaw <105jassen@gmail.com>
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>
In catch_other_actions_maybe_return_to_browser(), replaced if-statements
by a dict. If no key is found, a null function is executed.
Part-of: #2801
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>
namedtuple_to_dict() loops over a dynamic view of the dict of processes;
other threads might be editing the same dict.
For instance in webserver mode, when a race condition happens, the
following error shows up in the console:
> File "C:\Users\ryabtsev\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\glances\processes.py", line 628, in update_list
> return list_of_namedtuple_to_list_of_dict(processlist)
> File "C:\Users\ryabtsev\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\site-packages\glances\globals.py", line 495, in list_of_namedtuple_to_list_of_dict
> return [namedtuple_to_dict(d) for d in data]
> ^^^^^^^^^^^^^^^^^^^^^
> File "/app/glances/globals.py", line 490, in namedtuple_to_dict
> return {k: (v._asdict() if hasattr(v, '_asdict') else v) for k, v in data.items()}
> ^^^^^^^^^^^^
> RuntimeError: dictionary changed size during iteration
Instead of a dict view, namedtuple_to_dict() will use a list of tuples.
Performances are unchanged: on average, for 100 runs, namedtuple_to_dict()
completes in 0.2ms
GH issue: #3097
Link: https://docs.python.org/3/library/stdtypes.html#dictionary-view-objects
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>
1. update()
Two branches share the same logic for updating stats. Moreover, intermediate
values where used in nested loops: for filtering keys, and for extending stats.
This could be done at once with chain.from_iterable().
Therefore four helpers are introduced:
- add_engine_into_container
- is_key_in_container_and_not_hidden
- is_key_absent_in_container
- get_containers_from_updated_watcher
A profiling shows the stats build time is the same after the refactor,
$ sudo make run-webserver 2>&1 | grep primitive
31631 function calls (31566 primitive calls) in 0.028 seconds
23537 function calls (23487 primitive calls) in 0.025 seconds
23559 function calls (23509 primitive calls) in 0.014 seconds
23549 function calls (23499 primitive calls) in 0.024 seconds
23549 function calls (23499 primitive calls) in 0.026 seconds
23559 function calls (23509 primitive calls) in 0.016 seconds
23559 function calls (23509 primitive calls) in 0.022 seconds
23544 function calls (23494 primitive calls) in 0.015 seconds
23549 function calls (23499 primitive calls) in 0.023 seconds
23544 function calls (23494 primitive calls) in 0.018 seconds
[snapshot of top three calls]
31881 function calls (31816 primitive calls) in 0.029 seconds
Ordered by: cumulative time
List reduced from 536 to 3 due to restriction <3>
ncalls tottime percall cumtime percall filename:lineno(function)
3 0.000 0.000 0.029 0.010 __init__.py:250(<genexpr>)
2 0.000 0.000 0.029 0.015 __init__.py:242(get_containers_from_updated_watcher)
1 0.000 0.000 0.029 0.029 docker.py:248(update)
And before,
$ sudo make run-webserver 2>&1 | grep primitive
31620 function calls (31555 primitive calls) in 0.021 seconds
23526 function calls (23476 primitive calls) in 0.019 seconds
23533 function calls (23483 primitive calls) in 0.024 seconds
23538 function calls (23488 primitive calls) in 0.015 seconds
23528 function calls (23478 primitive calls) in 0.023 seconds
23528 function calls (23478 primitive calls) in 0.022 seconds
23533 function calls (23483 primitive calls) in 0.016 seconds
23538 function calls (23488 primitive calls) in 0.025 seconds
23538 function calls (23488 primitive calls) in 0.029 seconds
23538 function calls (23488 primitive calls) in 0.013 seconds
[snapshot of top three calls]
31865 function calls (31800 primitive calls) in 0.024 seconds
Ordered by: cumulative time
List reduced from 531 to 3 due to restriction <3>
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.024 0.024 docker.py:248(update)
13 0.000 0.000 0.022 0.002 decorators.py:38(inner)
13 0.000 0.000 0.022 0.002 client.py:244(_get)
2. msg_curse()
The conditions are directly used in any().
3. exit()
Minimum supported version is Python 3.9; loops use iterators by default.
itervalues() was introduced for compatility with Python 2. Commit 76ea71f2
("Remove Python 2 in docs and README files") removed Python 2 support.
Part-of: #2801
Link: https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable
Link: https://docs.python.org/3/library/profile.html#profile.Profile
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>
All the if-statements do the same actions:
- check the key is not disabled
- and add the corresponding callback to the building steps.
There could be done with a list comprehension on a dict.
Part-of: #2801
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>
sort_keys() uses sort_by_these_keys() on the stats. So doing, one of the
retrieved values might be absent; and sort_keys() will fall back to the
default sorting method, which is the alphabetical order.
This is the case for dead or exited containers.
Instead of a key lookup, the get method of dict could be used.
GH issue: #3098
Signed-off-by: Ariel Otilibili <otilibil@eurecom.fr>