openstack team mailing list archive
-
openstack team
-
Mailing list archive
-
Message #10077
Re: profiling nova-api
Great work!
About a year ago I found out than config was in the very top of
profiling table. It is there again.
That time there was a small misprint that led to constant config
reloading. This time i tried to add caching since our config became so
dynamic.
My efforts can be found here: https://review.openstack.org/6534 . My
benchmark showed time loss up to 40% in 'nova list' case. All three
lines from cfg.py have disappeared from top-10 of pstats. As well as
from top-40 :)
Looking forward to reviews.
Kind regards, Yuriy.
On Thu, Apr 12, 2012 at 00:48, Yun Mao <yunmao@xxxxxxxxx> wrote:
> Hi Stackers, I spent some time looking at nova-api today.
>
> Setup: everything-on-one-node devstack, essex trunk. I setup 1 user
> with 10 tiny VMs.
> Client: 3 python threads each doing a loop of "nova list" equivalent
> for 100 times. So 300 API calls with concurrency=3.
> how to profile: python -m cProfile -s time
> /opt/stack/nova/bin/nova-api --flagfile=/etc/nova/nova.conf
> --logdir=/var/log/nova --nodebug
> The partial output is attached in the end.
>
> Observations:
> * It takes about 60 seconds to finish. CPU of nova-api is around 70% to 90%
>
> * Database access: Each "nova list" API call will issue 4 db APIs: 3
> instance_get_all_by_filters(), 1
> instance_fault_get_by_instance_uuids(), so 1200 db API calls total
> (note: not necessarily 1200 SQL statements, could be more). The 900
> instance_get_all_by_filters() calls took 30.2 seconds (i.e. 0.03s
> each)! The 300 instance_fault_get_by_instance_uuids() calls only took
> 1.129 seconds (0.004 each).
>
> You might think: MySQL sucks. Not so fast. Remember this is a tiny
> database with only 10 VMs. Profile also shows that the actual
> _mysql.connection.query() method only took 1.883 seconds in total. So,
> we pretty much spend 29 seconds out of 60 seconds doing either
> sqlalchemy stuff or our own wrapper. You can also see from the sheer
> volume of sqlalchemy library calls involved.
>
> * the cfg.py library inefficiency. During 300 API calls,
> common.cfg.ConfigOpts._get() is called 135005 times! and we paid 2.470
> sec for that.
>
> Hopefully this is useful for whoever wants to improve the performance
> of nova-api.
>
> Thanks,
> Yun
>
> =======
>
> 23355694 function calls (22575841 primitive calls) in 77.874 seconds
>
> Ordered by: internal time
>
> ncalls tottime percall cumtime percall filename:lineno(function)
> 812 25.725 0.032 25.725 0.032 {method 'poll' of
> 'select.epoll' objects}
> 2408 1.883 0.001 1.883 0.001 {method 'query' of
> '_mysql.connection' objects}
> 70380 1.667 0.000 7.187 0.000
> expression.py:2263(corresponding_column)
> 135005 1.254 0.000 2.470 0.000 cfg.py:1058(_get)
> 41027 1.043 0.000 1.907 0.000 schema.py:542(__init__)
> 38802 1.008 0.000 1.219 0.000 __init__.py:451(format)
> 162206 0.821 0.000 0.821 0.000 util.py:883(values)
> 1530666 0.773 0.000 0.774 0.000 {isinstance}
> 135046/134960 0.716 0.000 1.919 0.000 cfg.py:1107(_substitute)
> 1205 0.713 0.001 1.369 0.001 base.py:2106(__init__)
> 183600 0.690 0.000 0.796 0.000 interfaces.py:954(_reduce_path)
> 81002 0.687 0.000 2.492 0.000 compiler.py:312(visit_label)
> 38802 0.650 0.000 6.087 0.000 log.py:227(format)
> 319270 0.622 0.000 0.748 0.000 attributes.py:164(__get__)
> 890242/884229 0.608 0.000 1.885 0.000 {getattr}
> 40500 0.605 0.000 3.101 0.000 schema.py:955(_make_proxy)
> 120783/120738 0.603 0.000 0.605 0.000 {method 'sub' of
> '_sre.SRE_Pattern' objects}
> 81000 0.601 0.000 2.156 0.000
> interfaces.py:677(create_row_processor)
> 63000 0.590 0.000 0.707 0.000 times.py:44(DateTime_or_None)
> 98102 0.588 0.000 0.886 0.000 compiler.py:337(visit_column)
> 658098 0.580 0.000 0.581 0.000 {method 'intersection'
> of 'set' objects}
> 109802 0.562 0.000 0.562 0.000 expression.py:3625(_from_objects)
> 231610/1202 0.551 0.000 5.813 0.005
> visitors.py:58(_compiler_dispatch)
> 144002 0.510 0.000 0.693 0.000
> compiler.py:622(_truncated_identifier)
> 135005/134960 0.485 0.000 4.872 0.000 cfg.py:860(__getattr__)
> 2408 0.463 0.000 1.942 0.001 {built-in method fetch_row}
> 71100 0.460 0.000 0.580 0.000
> strategies.py:121(create_row_processor)
> 299031 0.437 0.000 0.437 0.000 {_codecs.utf_8_decode}
> 6000 0.437 0.000 1.799 0.000 models.py:93(iteritems)
> 36000/9000 0.409 0.000 4.791 0.001 mapper.py:2146(populate_state)
> 81002 0.393 0.000 1.104 0.000
> compiler.py:672(label_select_column)
> 45000/9000 0.390 0.000 5.148 0.001 mapper.py:2186(_instance)
> 1202 0.366 0.000 5.797 0.005 compiler.py:701(visit_select)
> 231610/1202 0.347 0.000 5.817 0.005 base.py:714(process)
> 172800 0.341 0.000 1.148 0.000
> interfaces.py:651(_get_context_strategy)
> 25868 0.339 0.000 0.339 0.000 {method 'write' of 'file' objects}
> 91800/52200 0.327 0.000 6.728 0.000 interfaces.py:673(setup)
>
> 22801 0.324 0.000 0.324 0.000 {method 'strftime' of
> 'datetime.date' objects}
> 78478 0.316 0.000 0.914 0.000
> expression.py:2143(contains_column)
> 25868 0.314 0.000 0.314 0.000 {method 'flush' of 'file' objects}
> 299033 0.309 0.000 0.930 0.000 {method 'decode' of 'str' objects}
> 118969/118924 0.305 0.000 0.930 0.000 string.py:174(safe_substitute)
> 143683/143658 0.304 0.000 4.518 0.000 util.py:1514(__get__)
> 135008 0.303 0.000 0.303 0.000 {sorted}
> 48495 0.295 0.000 0.307 0.000 util.py:928(__init__)
> 288598 0.292 0.000 0.298 0.000 {hasattr}
> 136567 0.292 0.000 0.435 0.000 {map}
> 34260 0.287 0.000 0.538 0.000 expression.py:3584(_label)
> 524700 0.285 0.000 0.285 0.000 strategies.py:129(new_execute)
> 300000 0.282 0.000 1.160 0.000 models.py:84(next)
> 27000/6000 0.280 0.000 0.280 0.000 model.py:31(__repr__)
> 12934 0.273 0.000 0.536 0.000 __init__.py:242(__init__)
> 31649 0.258 0.000 0.258 0.000 {posix.stat}
> 3302 0.256 0.000 0.256 0.000 decoder.py:372(raw_decode)
> 2408 0.241 0.000 0.241 0.000 {method 'store_result'
> of '_mysql.connection' objects}
> 287402 0.238 0.000 0.239 0.000 compiler.py:1541(quote)
> 38802 0.212 0.000 9.059 0.000 __init__.py:731(handle)
> 25868 0.210 0.000 4.979 0.000 __init__.py:830(emit)
> 645763 0.206 0.000 0.206 0.000 {method 'get' of 'dict' objects}
> 41432 0.196 0.000 0.358 0.000 threading.py:141(release)
> 41432 0.194 0.000 0.339 0.000 threading.py:121(acquire)
> 81000 0.190 0.000 5.349 0.000 strategies.py:100(setup_query)
> 3600 0.187 0.000 6.226 0.002 strategies.py:956(setup_query)
> 12934 0.187 0.000 2.630 0.000 handlers.py:784(emit)
> 299031 0.183 0.000 0.620 0.000 utf_8.py:15(decode)
> 162206 0.183 0.000 1.045 0.000 util.py:886(itervalues)
> 3600 0.176 0.000 0.413 0.000
> strategies.py:1161(create_row_processor)
> 13835 0.174 0.000 0.174 0.000 {method 'send' of
> '_socket.socket' objects}
> 12934 0.171 0.000 0.707 0.000 __init__.py:1218(makeRecord)
> 237032 0.169 0.000 0.169 0.000 {method 'split' of 'str' objects}
> 21493 0.167 0.000 0.232 0.000 posixpath.py:60(join)
> 3600 0.165 0.000 2.391 0.001 mapper.py:2329(_populators)
> 76353 0.164 0.000 0.280 0.000 expression.py:2138(__contains__)
> 1202 0.161 0.000 0.161 0.000 {method 'rollback' of
> '_mysql.connection' objects}
> 24000 0.159 0.000 0.166 0.000 model.py:24(ensure_string_keys)
> 852818 0.158 0.000 0.158 0.000 {method 'pop' of 'dict' objects}
> 111585 0.156 0.000 0.208 0.000 thread.py:17(get_ident)
> 4542 0.154 0.000 3.108 0.001
> visitors.py:241(replacement_traverse)
> 12934 0.151 0.000 9.213 0.001 __init__.py:1284(callHandlers)
> 158594 0.145 0.000 1.138 0.000 util.py:787(__iter__)
> 230769/224673 0.144 0.000 0.266 0.000 {iter}
> 253618 0.144 0.000 0.144 0.000 {method 'lower' of
> 'unicode' objects}
> 3000 0.144 0.000 5.696 0.002
> common.py:293(get_networks_for_instance_from_nw_info)
> 733671 0.141 0.000 0.141 0.000 {method 'append' of
> 'list' objects}
> 41029 0.141 0.000 0.189 0.000 expression.py:3570(__init__)
> 19840 0.141 0.000 0.214 0.000 corolocal.py:24(_patch)
> 4506/21 0.140 0.000 57.981 2.761 socket.py:406(readline)
> 133954 0.139 0.000 0.272 0.000
> cfg.py:440(_get_from_config_parser)
> 216531 0.139 0.000 0.772 0.000 connections.py:206(string_decoder)
> 45000 0.138 0.000 0.151 0.000 mapper.py:2139(identity_key)
> 13526 0.134 0.000 0.937 0.000 log.py:146(process)
> 135003 0.134 0.000 0.134 0.000 cfg.py:770(get)
> 50425/49225 0.129 0.000 0.986 0.000 {method 'join' of 'str' objects}
> 69300 0.129 0.000 7.303 0.000 util.py:621(_corresponding_column)
> 600 0.129 0.000 23.205 0.039 api.py:1045(get_all)
>
> _______________________________________________
> Mailing list: https://launchpad.net/~openstack
> Post to : openstack@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~openstack
> More help : https://help.launchpad.net/ListHelp
References