Slowness of extended protocol
Hi all. I know this has been discussed before, I'd like to know what's the
current position on this.
Comparing the performance of the simple vs. extended protocols with pgbench
yields some extreme results:
$ ./pgbench -T 10 -S -M simple -f /tmp/pgbench.sql pgbench
tps = 14739.803253 (excluding connections establishing)
$ ./pgbench -T 10 -S -M extended -f /tmp/pgbench.sql pgbench
tps = 11407.012679 (excluding connections establishing)
(pgbench.sql contains a minimal SELECT 1, I'm running against localhost)
I was aware that there's some overhead associated with the extended
protocol, but not that it was a 30% difference... My question is whether
there are good reasons why this should be so, or rather that this simply
hasn't been optimized yet. If it's the latter, are there plans to do so?
To give some context, I maintain Npgsql, the open-source .NET driver for
PostgreSQL. Since recent version Npgsql uses the extended protocol almost
exclusively, mainly because it does binary data rather than text. Even if
that weren't the case, imposing such a performance penalty on extended-only
features (parameters, prepared statements) seems problematic.
I'm aware that testing against localhost inflates the performance issue -
taking into account the latency of a remote server, the simple/extended
difference would be much less significant. But the issue still seems to be
relevant.
Hi all. I know this has been discussed before, I'd like to know what's the
current position on this.Comparing the performance of the simple vs. extended protocols with pgbench
yields some extreme results:$ ./pgbench -T 10 -S -M simple -f /tmp/pgbench.sql pgbench
tps = 14739.803253 (excluding connections establishing)$ ./pgbench -T 10 -S -M extended -f /tmp/pgbench.sql pgbench
tps = 11407.012679 (excluding connections establishing)(pgbench.sql contains a minimal SELECT 1, I'm running against localhost)
I was aware that there's some overhead associated with the extended
protocol, but not that it was a 30% difference... My question is whether
there are good reasons why this should be so, or rather that this simply
hasn't been optimized yet. If it's the latter, are there plans to do so?To give some context, I maintain Npgsql, the open-source .NET driver for
PostgreSQL. Since recent version Npgsql uses the extended protocol almost
exclusively, mainly because it does binary data rather than text. Even if
that weren't the case, imposing such a performance penalty on extended-only
features (parameters, prepared statements) seems problematic.I'm aware that testing against localhost inflates the performance issue -
taking into account the latency of a remote server, the simple/extended
difference would be much less significant. But the issue still seems to be
relevant.
Without re-using prepared statements or portals, extended protocol is
always slow because it requires more messages exchanges than simple
protocol. In pgbench case, it always sends parse, bind, describe,
execute and sync message in each transaction even if each transaction
involves identical statement ("SELECT 1" in your case).
See the manual for the protocol details.
Best regards,
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese:http://www.sraoss.co.jp
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Without re-using prepared statements or portals, extended protocol is
always slow because it requires more messages exchanges than simple
protocol. In pgbench case, it always sends parse, bind, describe,
execute and sync message in each transaction even if each transaction
involves identical statement ("SELECT 1" in your case).See the manual for the protocol details.
I'm well aware of how the extended protocol works, but it seems odd for a
30% increase in processing time to be the result exclusively of processing
5 messages instead of just 1 - it doesn't seem like that big a deal
(although I may be mistaken). I was imagining that there's something more
fundamental in how the protocol or PostgreSQL state is managed internally,
that would be responsible for the slowdown.
Shay Rojansky <roji@roji.org>:
I'm well aware of how the extended protocol works, but it seems odd for a
30% increase in processing time to be the result exclusively of processing
5 messages instead of just 1 - it doesn't seem like that big a deal
(although I may be mistaken). I was imagining that there's something more
fundamental in how the protocol or PostgreSQL state is managed internally,
that would be responsible for the slowdown.
Hi, have you tried to use a profiler to identify the _cause_ of the
difference in performance?
Here's relevant read:
https://shipilev.net/blog/2015/voltmeter/#_english_version
Vladimir
Shay Rojansky <roji@roji.org>:
I'm well aware of how the extended protocol works, but it seems odd for a
30% increase in processing time to be the result exclusively of processing
5 messages instead of just 1 - it doesn't seem like that big a deal
(although I may be mistaken). I was imagining that there's something more
fundamental in how the protocol or PostgreSQL state is managed internally,
that would be responsible for the slowdown.Hi, have you tried to use a profiler to identify the _cause_ of the
difference in performance?Here's relevant read:
https://shipilev.net/blog/2015/voltmeter/#_english_version
I'm definitely not a stage where I'm interested in the cause of the
difference. I'm not a PostgreSQL hacker, and I'm not going into the source
code to try and optimize anything (not yet anyway). For now, I'm just
looking to get a high-level picture of the situation and to inform people
that there may be an issue.
Or in terms of your article, I'm plugging a light bulb into the wall socket
and the light is dim, so I'm trying to ask the building electricity team if
they're aware of it, if if it's a fixable situation and if there are plans
to fix it - before pushing any fingers into some electricity cabinet I
don't know.
On Sun, Jul 31, 2016 at 4:05 PM, Shay Rojansky <roji@roji.org> wrote:
I'm well aware of how the extended protocol works, but it seems odd for a
30% increase in processing time to be the result exclusively of processing 5
messages instead of just 1 - it doesn't seem like that big a deal (although
I may be mistaken). I was imagining that there's something more fundamental
in how the protocol or PostgreSQL state is managed internally, that would be
responsible for the slowdown.
I think you're looking at this the wrong way around. 30% of what?
You're doing these simple read-only selects on a database that
obviously is entirely in RAM. If you do the math on the numbers you
gave above the simple protocol took 678 microseconds per transaction
and the extended protocol took 876 microseconds. The difference is 198
microseconds. I'm not sure exactly where those 200us are going and
perhaps it could be lower but in what real-world query is it going to
have a measurable impact on the total time?
The other danger in unrealistic test cases is that you're probably
measuring work that doesn't scale and in fact optimizing based on it
could impose a cost that *does* scale. For example if 150us of that
time is being spent in the prepare and we cut that down by a factor of
10 to 15us then it would be only a 10% penalty over the simple
protocol in your test. But if that optimization added any overhead to
the execute stage then when it's executed thousands of times that
could add milliseconds to the total runtime.
--
greg
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2016-07-31 22:26:00 +0100, Greg Stark wrote:
I think you're looking at this the wrong way around. 30% of what?
You're doing these simple read-only selects on a database that
obviously is entirely in RAM. If you do the math on the numbers you
gave above the simple protocol took 678 microseconds per transaction
and the extended protocol took 876 microseconds. The difference is 198
microseconds. I'm not sure exactly where those 200us are going and
perhaps it could be lower but in what real-world query is it going to
have a measurable impact on the total time?
FWIW, I've observed the same with (a bit) more complicated queries. A
part of this is that the extended protocol simply does
more. PQsendQueryGuts() sends Parse/Bind/Describe/Execute/Sync - that's
simply more work and data over the wire than a single Q message.
Whether that matters for a given workload or not, is a different
question, but I think it's pretty clear that it can for some.
Shay, are you using unnamed or named portals? There's already a shortcut
path for the former in some places.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund <andres@anarazel.de> writes:
FWIW, I've observed the same with (a bit) more complicated queries. A
part of this is that the extended protocol simply does
more. PQsendQueryGuts() sends Parse/Bind/Describe/Execute/Sync - that's
simply more work and data over the wire than a single Q message.
Yeah. The extended query protocol was designed to offer a lot of
functionality that people had asked for, like plan re-use and
introspection of the data types assigned to query parameters, but that
doesn't come at zero cost. I think the tie-in to the plan cache is a
significant part of the added overhead, and so is the fact that we have to
iterate the per-message loop in PostgresMain five times not once, with
overheads like updating the process title incurred several times in that.
In hindsight it seems clear that what a lot of apps want out of extended
protocol is only the ability to send parameter values out-of-line instead
of having to quote/escape them into SQL literals. Maybe an idea for the
fabled V4 protocol update is some compromise query type that corresponds
precisely to PQexecParams's feature set: you can send parameter values
out-of-line, and you can specify text or binary results, but there's no
notion of any persistent state being created and no feedback about
parameter data types.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Greg wrote:
I think you're looking at this the wrong way around. 30% of what?
You're doing these simple read-only selects on a database that
obviously is entirely in RAM. If you do the math on the numbers you
gave above the simple protocol took 678 microseconds per transaction
and the extended protocol took 876 microseconds. The difference is 198
microseconds. I'm not sure exactly where those 200us are going and
perhaps it could be lower but in what real-world query is it going to
have a measurable impact on the total time?
That's a valid question, but as Andres said, it may not matter for most
workloads but I think such a significant difference would matter to some...
Keep in mind that I'm writing from the point of view of a driver developer,
and not of a specific app - I know there are some point executing against a
local database and trying to get extremely high throughput, for RAM reading
queries or otherwise.
The other danger in unrealistic test cases is that you're probably
measuring work that doesn't scale and in fact optimizing based on it
could impose a cost that *does* scale. For example if 150us of that
time is being spent in the prepare and we cut that down by a factor of
10 to 15us then it would be only a 10% penalty over the simple
protocol in your test. But if that optimization added any overhead to
the execute stage then when it's executed thousands of times that
could add milliseconds to the total runtime.
I think it's a bit too early to say that... We're not discussing any
proposed optimizations yet, just discussing what may or may not be a
problem... Of course any proposed optimization would have to be carefully
studied to make sure it doesn't cause performance degradation elsewhere.
Andres wrote:
Shay, are you using unnamed or named portals? There's already a shortcut
path for the former in some places.
The benchmarks I posted are simply pgbench doing SELECT 1 with extended vs.
simple, so I'm assuming unnamed portals. Npgsql itself only uses the
unnamed portal, I think it's documented somewhere that this is better for
performance.
Tom wrote:
In hindsight it seems clear that what a lot of apps want out of extended
protocol is only the ability to send parameter values out-of-line instead
of having to quote/escape them into SQL literals. Maybe an idea for the
fabled V4 protocol update is some compromise query type that corresponds
precisely to PQexecParams's feature set: you can send parameter values
out-of-line, and you can specify text or binary results, but there's no
notion of any persistent state being created and no feedback about
parameter data types.
That seems like a good way forward. It may be possible to generalize this
into a more "pay-per-play" protocol. You currently have a binary choice
between a simple but fast protocol supporting very little, and an extended
but slow protocol supporting everything. Making things more "pick and
choose" could help here: if you want to actually use plan reuse, you pay
for that. If you actually send parameters, you pay for that. It would be a
pretty significant protocol change but it would make things more modular
that way.
I think the tie-in to the plan cache is a
significant part of the added overhead, and so is the fact that we have to
iterate the per-message loop in PostgresMain five times not once, with
overheads like updating the process title incurred several times in that.
I was thinking that something like that may be the cause. Is it worth
looking into the loop and trying to optimize? For example, updating the
process title doesn't seem to make sense for every single extended
message...
Tom> I think the tie-in to the plan cache is a
Tom> significant part of the added overhead, and so is the fact that we
have to
Tom> iterate the per-message loop in PostgresMain five times not once, with
Tom> overheads like updating the process title incurred several times in
that.
Shay>I was thinking that something like that may be the cause. Is it worth
looking into the loop and trying to optimize? For example, updating the
Shay>process title doesn't seem to make sense for every single extended
message...
Shay> just discussing what may or may not be a problem...
Shay, why don't you use a profiler? Seriously.
I'm afraid "iterate the per-message loop in PostgresMain five times not once"
/"just discussing what may or may not be a problem..." is just hand-waving.
Come on, it is not that hard.
Here's what I get with Instruments, OS X 10.11.5, Intel(R) Core(TM)
i7-4960HQ CPU @ 2.60GHz, running with power plugged in. There are lots of
applications running, however I believe it should not matter much since I'm
using just 1 load thread and the 5-second averages are consistent and CPU
is not overloaded.
test.sql:
SELECT 1;
PostgreSQL 9.5.3 on x86_64-apple-darwin15.4.0, compiled by Apple LLVM
version 7.0.2 (clang-700.1.81), 64-bit
Command line:
/opt/local/lib/postgresql95/bin/pgbench -M extended -f test.sql -j 1 -P 5
-T 120
Profiler is activated at seconds 30...60
It looks strange to see copyObject calls from within
BuildCachedPlan/CreateCachedPlan.
I would expect one-shot plan to be reused without copying,
however exec_parse_message does not seem to bother setting is_oneshot=true
flag on a CachedPlanSource.
It it a bug? It think exec_parse_message should set is_oneshot=true for
parse message with empty statement names.
[image: pg_extended_topdown.png]
Here's the detailed list for the run:
postgres$ /opt/local/lib/postgresql95/bin/pgbench -M extended -f test.sql
-j 1 -P 5 -T 120
starting vacuum...ERROR: relation "pgbench_branches" does not exist
(ignoring this error and continuing anyway)
ERROR: relation "pgbench_tellers" does not exist
(ignoring this error and continuing anyway)
ERROR: relation "pgbench_history" does not exist
(ignoring this error and continuing anyway)
end.
progress: 5.0 s, 30061.1 tps, lat 0.033 ms stddev 0.013
progress: 10.0 s, 31407.4 tps, lat 0.032 ms stddev 0.008
progress: 15.0 s, 31332.4 tps, lat 0.032 ms stddev 0.008
progress: 20.0 s, 31812.3 tps, lat 0.031 ms stddev 0.007
progress: 25.0 s, 31560.9 tps, lat 0.031 ms stddev 0.008
progress: 30.0 s, 31492.3 tps, lat 0.031 ms stddev 0.008
vvv profiler activated
progress: 35.0 s, 29972.2 tps, lat 0.033 ms stddev 0.011
progress: 40.0 s, 28965.8 tps, lat 0.034 ms stddev 0.010
progress: 45.0 s, 29127.0 tps, lat 0.034 ms stddev 0.011
progress: 50.0 s, 29464.0 tps, lat 0.034 ms stddev 0.008
progress: 55.0 s, 29072.2 tps, lat 0.034 ms stddev 0.011
progress: 60.0 s, 29405.2 tps, lat 0.034 ms stddev 0.008
^^^ profiler deactivated
progress: 65.0 s, 28848.0 tps, lat 0.034 ms stddev 0.013
progress: 70.0 s, 31175.8 tps, lat 0.032 ms stddev 0.010
progress: 75.0 s, 32042.8 tps, lat 0.031 ms stddev 0.007
progress: 80.0 s, 31277.8 tps, lat 0.032 ms stddev 0.008
progress: 85.0 s, 31373.3 tps, lat 0.032 ms stddev 0.009
progress: 90.0 s, 31171.0 tps, lat 0.032 ms stddev 0.008
Vladimir
Show quoted text
Attachments:
pg_extended_topdown.pngimage/png; name=pg_extended_topdown.pngDownload
�PNG
IHDR � � ��8 �iCCPICC Profile X��YTT[�>")%"!R2tK��H34H
5tH
CH)
�! ��H���C
������]�������w�������}��3g ����N �npMi:=}:� ����if��,���������,���
��ns�����i����;������� �����3�
�~ f�ts��� ���l��`�?x��-M�p�����������`k�
�-&����% `k�~/y��
�{�JVV�9 <��~���-��n����@|���������#����s�����6�� �
�� �p�P-Y�1`X��f��v�H���nkm�F'V������c:� ���?5���K����"0 ����Y�F P&��c* �A ��q6���Sy4�����S���68=4�=�p<*�"
bo�6�����te�����r�
Y�l?B�>d�d�g�a��r�s�qsq>|���������sKp��p��������u�k�� �O��uE�E�����<�`��2��������T�S�y���R�HeXu_O������s;-o�P��7z��N��BP*������I�i�Y�y��2������F�V�N����@�H���t�����r�skt/�����
�v�����S�
`
|���E�v�lH�������p��H�(��t�w���|A�~����L�xc���$��8�6��-���wi����Y#�9=��ym���k*
����KbJ_�y�;UX~0�T�����Y�PK^�_�����q��k�l������������]��9=i�I}��A��C��/FG�>I���3O�O���9�7�efl�k�n�d!�s�b���e�/^_�V\V�����9o�7����vBv#�����wY��G%���������eg�?���_�]6������~�q}���y���}�
;��� \t�N<_|���D�����$�dB�q���T���2t��[������KX:����m��p�rN=��*��s��h�r��}��pT�&!Y-s���]"DRQ��T�����L����\���DP}������"���F�N�A�����Y+I�I��.J0�1���C/����L��N����[�X�[������u�s��������]\<����n��q)�Y^��>5�M~��]=�=/;�Z�kCJ_e����;DF*F��On���5�hlc\A����7.��IZ�
)���oY�1�Q�SdPdRdQfS�����q���/P)T+R*�,�+e*#)�(�^��a�����:�c`�]�v�D=k�����;M��-e�o����;,:�w�t��0�������4�>83�?�0R<����1�q� �I�)�i��Y�9�y`�t�ym����������+��=k�����6>mNn�m/���n#�����n-��kOr����<s��|��L������q��A�bx`�cU`������#�� p#l��w���>3 )9&�!���n���T���4/hM�����������_� e���5��r|�<��
��M�������HL*��MK�y,�%� e*�\F^VX�]�Z���-���KJ���*i�!j���lW��5���kYi+�����������~��5
0~a�f*`Fg�k~f�f9f����:����?��f��
�"N���]H�����n+��]��^9��>���~���L����/����C^�rU����"&"���^;G��<F b��*����&�$�$�%o�����M�*�!]'C2�#�"/�V�������������EE�)%a��e�����+�U^W!��>��T���E��7�5�6 73��m����6���Q����m����Ik�����]�y�.I
�d7�5.1�6I:�6u0�438[?W0��������%�e�/r_%VDV������o�o�n9mG���6!��f�g�+�^��P�����f������N�� 0���O� + ~!�������n$ ��a����w�[^��FN���a?�.H��\^���?�W� S�N*����NX���n7�������!���������2�l[�(���p�[��_��b��)��i4�3m�T��`:*���>�Md���T+,����[�8+���Mmb�1�^:��r"�����Z,����0��.�$������$�����{q��'-���Xv���w��mt��|�zRC��U8|"@63�=a=��L��=�B��d�����\�`�6��dh�6��^�����0��5�n�v�����rc[B��b���-?��1Yh�FWZ�z�g����IL,��3J�7^��>G}����[��=����Kl�����7��u��|�g@�u����6�|t�g�Z��FxZ�H<"1�5��9����l�Z����Oz}}�3u�`�n�^0����:�����o�I� ���
U���t�K!�l��
�3_��r����;e�52���a�]z/x�������t3���
�������~���T�h���b�u�h�bp�D�G�����s^S�X��6�j���,P�]G�T�#�n
d���*�i�G�b9��S>M�}�i�;����q����L�-�g���\L��.
r�
L��O��lp0���m�Y'�H;L*{8
�M���;)� �"c8�59����a������:�5��C�C�=���a��;
���z>g�������u4�^z������}RI��(v�`U��2nN���C2j�����[zRBK�~��p[z��l����ugSq\��S+���:�����4~d^���0�v�H�������@t�G���I�f '����|���)H}�m�� ��K�,����|D(����x7U�M�)�����F��SQ3�}���L��~������\>"*T��t��cd�)�h���*0�#�g��?i��$t ��T�R�gRl�?��!�I�yj�:2��|�������$")�H?�P���V�z!���jy ��t����s����(���@k�-�}��+;�1fB��U�=_�zZWq��\��TV���63����(x4"��-��E�����JNjP�):�/�>���fi\'�
�2������ 8�B�2�����Sn�����G@�;�����U��`�A+�b���1y���::v.����:���z�T��������:K�l<6����fI�W[�'c
?V�Z��q��g��?�XF#�+_�������,%�ca�vQ�Z��*$�4�}�����@�k����l;��K�:��;������n"[��$%'�Z`3y�p�����#3c���ZEJ�*�H�|�������AZi
s��o�+��ER=@?����8�R�to�@ W{��^z�F����U>X��P��Tb��~�.�>��#�}~�K�Y���S�LA�-M�2e>o�(�U�E ~�2|���=�����w�O�PD /�'x��Wi��1F���3cye�����6���^�v��>���X
����C+��>�A�6l���u��*<����~�=�RS���C�
P������^��#�=��]�8��lI{2q E��NTQmu�b�F;+vOLo�!�W��)�S��F�q��;���5��'���a�6�0�����aU�t���6x�xh��Jm����e>cY�| ��J^���{Y��/�:�p%[�y�����E��~�T�(/��p"��c&x"W�����%)��������1"�%MP��5�6����Ag�����J*=��7=����Vr�ep��!�N���"`���8��2���)�m��p��T��=�2P�<;y�Wc��I��{49A�L
��.!.5n����� ���PG����PW,���Z�o��������oQ-�d7egR�w�V ��s��@<����a)�*D`G�Z?�A�H�7|M���^��n��LV��WE<�������9Ic�JgA���+zwQ6)�\,��]%�7������A�XZp��lt�O�$�[����������b>�{v���� q�w"��n\���O^?��=+�6O�����x�o�S�Lbt�EqH�a�������CoJe��A!z#m���U�@���h�UgvN���#��'���J"���b�P��,H��5}���P�J��E,�9�v��6��W{z�]?���FI��z��RP��fEIZ}{��
4��Ft� �C�C��1�S,Y��fP�V��?���x��9�wgE�r���})n��|V:�:���z8���Ni�T��f'6.��M�����Qc�����e���~fb]�t���'_�-cBK���mh�/�B�4�)�d������RzF"Hy���H�G�mx��H�����������$xs��T ���^�d�7��'�di#��4�0���7�HT�9/�h����V����rg��IT�Yo�V������!�x�-��X]Rd3!�B����"���w\��#�Q O�kp ��,}4��F�y����E5S��Z
��#��B�]M��g|��Fl�yh�}����Zt�3^���6�w���s��#n������:�]w?.6�����z7��/�M��t�3"�<*���$����+"���rI�j��E�Zh ��{�6�L�������a�Nem�G ]R�{BIh�v�uT�Rk�FCj�OFrGP ���� Wz���gX��H�t�_W���N�!��W�sB�}
6iOQj(���q��uX������|������S��v��Y ����
������&sX�����3���p���sp������x.(��`nO�%�������ZQGmT������^���IK�${�����-�hd(%e��a�������I�|u��w����n�@��m�$����;����)EC�gI�����:9�������[+W�Ys��II�L������6����[�dK���R�P�\��4������h>=+�aC�Sr��@�Y���#�Z���lrD� �L��o�}�E��g��?o*�9)�����j������Ch�����I%Bw#����L-�_��&�����leYi8����||��|��-t+?]�K�� *����+��~��p�e9>��HM;�Uz=O"��V8���~�]I�X������t����v��VEo�7e��w��3D�XC���d��HrT��������e�^�J��+r��?#�D��c�}e#)+�G���x������KQ&��=��i)^�����������s��aV��W���MZ���D�=0���#O�Y��~��AH�Z�)UK�n�����c�NB$��1�j�Gq�9���F�L�����e��C���`�
����"t�$����a[0)�p�<��o+���w��Q��$���l~��}S*���^.���,"k�1�Y���Zl�.FZ�������h
)���c@���b1,|��;Nl`��1��U9n�J�/h�+}KE�X�R�XPY�3�[�)�
��>���A
O=/���N�%'Z@�����|J� {��_9��������b��U\gT�����R��&�G|��|e(��3��5}t���>�!����~�
���&�G���;}�0�)���_H���!����������e��E���X2'
��&���������>�����6����-:B����B2��~�s%�q����q��S]A�O�����������,���?k�k�aO��������E��9�l��� b�]��������[� ������ �|C���_�f���_u����dZ���f�JFH�_��4��.X�#=�76:����C����%(��O7:m���[����e�2�
�=<�f�O$FW�����!}L}3���n��O5���~�m�Q�jR)���bH�n�Q��]���Z��&���u/���B�j��R������+�~�'�����2�������+�
�m�=�����yk]_?����#�.lJ:��j�6���������n��k��fa��p����V��2c��A�d���u���������p��Y4��S���������cC���t2����������4}�ru���i�������-3S.���\b5T&��<�sR=�oj�*i�^�����]������Rg�}] �n�):l��uR%S�p���l������}>OkB�����WEA�������w��)Yj~,���n�^��$����y�_-)���wr:��9���7��W7x���|�\ �4��E����z��E����c��x�q�f�5ZAa��7�����3?�I@
%�Z�Z�'~���T���P�����Jj���F�z�S�@�V�������^� 7�ZN���8P�+�p�+��t ���������6v���o��f�` � �9��Lp��7h�1�}��������� pHYs % %IR$� �iTXtXML:com.adobe.xmp <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:exif="http://ns.adobe.com/exif/1.0/">
<exif:PixelXDimension>972</exif:PixelXDimension>
<exif:PixelYDimension>1420</exif:PixelYDimension>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
E``6 iDOT � ( � � ����K @ IDATx�}|���/@x��["EEm4j��0���4����->���im��ZR��%�������\�i�)b��+���h�b� 0�C$�st����3��{v��=�p��[>a�����;�3���c�:::4��`F�`F�`F�`L�1a6��?F�`F�`F�`� fn� #�0� #�0� #�0��
L�m@�[� #�0� #�0� #�0� fn� #�0� #�0� #�0��
L�m@�[� #�0� #�0� #�0� fn� #�0� #�0� #�0��
L�m@�[� #�0� #�0� #�0� fn� #�0� #�0� #�0��
L�m@�[� #�0� #�0� #�0� fn� #�0� #�0� #�0��
� ��i���
����?�>�����OE����������A�`���0x�`HKK�I�o1� #�0� #�0� #�0���k�L�����=
0t�PA��I���3�h"�}�;v���
"�|0� #�0� #�0� #�0�W�����#G`���0v�Xh��i�jZ>�}�����@y���#�����WO�g�>���]"�|0*�w����v5j��1C}��� #�� 7���E��a����9 �����0qC "ankk��1c����!�����
����� �`�ya��.�xHJM���H������^R�?���a���Q���������("��8����'G��E�'��y�p�� �����d*9��d�
�#�7K�>,����t2��1<��
�� �??>8�,T���U<�R�D`���������!C��s������}������+x#G���+W�5N����@��/y���� �����d*9��d�
�#��p$��J���C�e���a�K��D�Ci�?.]���� �n��|?��������
�SN9&L�W �0�N�,IH�w�$��l$9����R${�S������ B��0��.Rc�0y\��v�$.��9�?�x�8��WH��qX���ac�&84p*\��2�4X"�
����a��q�������$��BL�4��{.0 n%d�l���m9�������D~7'��N������q����a��{C�����7� �����f�3��?���������JO�y�}���VQ���L�?����/�����4��m�[�J�>����&�2e�G������-p��M�����0r�I0m�f$o�Z���� ���f+<q}����2�����}�d��d�~��D6����:�-��I�D��W���0w���O��mz���d���y.�w�e����`���,�8�-�����[6n�v� �O|�����Q�[ M$u�$��qB���2�{����1���D!'�&�L<�o�C���p���0�J�����Jxj]-4vt�3O?.��W!���i��K%����� ��� F�_�� �yu�g:�ap�t�M��z�?�B�==4u�����P����#������~��a��t�~���k��?_�o�z��B��9I��N���X "�����kC��]�a�����]��+������z��O��h�|���h����/g���B5�������y)�e���%�~K.��p!�<���j_�/b`&��lf\H��5�!a� �1��6�������$gX��M�.i����l����� m����H���s�a{�O��%����55p���-p�Wl:�-�����M���9���}P8;^���N�_��nB��v� ��p;���q)�JB�=�Z��#O�|5�L����<�R1�^���L�0w�����n�+������I�E����gK�5����q�x
�)��������Z8[��g���ov�c��P�<���`���{7,�0hf�u�z�z�|=�T�0fZ�#��g>����aB�K�� Y�����t�����<�#i�i���[�|vB����y\��m��g���0�F[����^X0�x�
!�&������L�O�
�|���ie^\�-%iH�-��e~��u�����'����G��������.�^x�����?�Plav�g�����������2[�����+r`��z#��a�������P��U�A}T��
��D�����}#c���z�c�(����s��p}���#���nH�wcN����e� �C;T����N|%��7���-��D�3�q��o�1Y�D2�����u����9��S�]%����-�|;�hY 3,J~���`��ep������|���R�0�4����YoL������%�u�<�'����cf������,P� ���t�mv���yKE�Gw���Vd)p6f�]>z�(=f>�Q��D��<}�xz�V]2�I���a�3](eB��4��!9&�Qa��Ca�����|���f����#{`������Y!�sq�e�i����{������{
J�u�:x���b"2����s
)nlT-�Je�xd�x�=��x$�q�J6�f!=��������x�?���8��
8���,r+�iR����g����Y
��UB�����{-���Pk�p����o��������CH�w#S�v*��s8��C�������r7��0�����=9_��2yO��.��<���������0I�dO�0�������5��FU��*�X K�3�������
�n}�L�&8/��u���eS�R��zX�9GHf)��($����`w�-0kI��� ��L3��:w�u����w�VX�;���B$�k��_�1U.M����E��5M��x�"=Sl���;�������������7fg����acS7�/\?�E��������r���`�)���O�8��
a�-��'����/�������c
��\o�*�G������k-TCO�g�3�Y5/�����/�~%������X����?`4�ea��N��V#��0��N��z�t1�\:��'�������7��� �Q�G��3N�)��X���I���b���JB��3��@%���D]�T2��e5L����\�l�Kk3���w5;j����
���
�`���)Yr�����p���5<����S��!0i�2v�B��������S������v��Zr�~p7��� ����w��0cR��n'���v����a����086����%���c�a��������c0���+�(�yp���/��g���������������~�m��c��q��i3&���z��R�w���qN�i��N0:[[�(��
?��[�����M9����n��S����kv���g(�����1�H�����m-dY'U��!w���\��a"�V�5���Scf� �s���J�����a�.p�)=�0{!��=U�`�
B1�|���V=]���ga&�H��M����A-I���{��y�`��!����Q��$���:��`$��i��p�6|�a�wF�/^����H���r��<