From: Ilpo Järvinen <hidden> Date: 2008-02-20 13:47:41
Hi all,
I run some lengthy tests to measure cost of inlines in headers under
include/, simple coverage calculations yields to 89% but most of the
failed compiles are due to preprocessor cutting the tested block away
anyway. Test setup: v2.6.24-mm1, make allyesconfig, 32-bit x86,
gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13). Because one inline was
tested (function uninlined) at a time, the actual benefits of removing
multiple inlines may well be below what the sum of those individually
is (especially when something calls __-func with equal name).
Ok, here's the top of the list (10000+ bytes):
-110805 869 f, 198 +, 111003 -, diff: -110805 skb_put
-41525 2066 f, 3370 +, 44895 -, diff: -41525 IS_ERR
-36290 42 f, 197 +, 36487 -, diff: -36290 cfi_build_cmd
-35698 1234 f, 2391 +, 38089 -, diff: -35698 atomic_dec_and_test
-28162 354 f, 3005 +, 31167 -, diff: -28162 skb_pull
-23668 392 f, 104 +, 23772 -, diff: -23668 dev_alloc_skb
-22212 415 f, 130 +, 22342 -, diff: -22212 __dev_alloc_skb
-21593 356 f, 2418 +, 24011 -, diff: -21593 skb_push
-19036 478 f, 259 +, 19295 -, diff: -19036 netif_wake_queue
-18409 396 f, 6447 +, 24856 -, diff: -18409 __skb_pull
-16420 187 f, 103 +, 16523 -, diff: -16420 dst_release
-16025 13 f, 280 +, 16305 -, diff: -16025 cfi_send_gen_cmd
-14925 486 f, 978 +, 15903 -, diff: -14925 add_timer
-14896 199 f, 558 +, 15454 -, diff: -14896 sg_page
-12870 36 f, 121 +, 12991 -, diff: -12870 le_key_k_type
-12310 692 f, 7215 +, 19525 -, diff: -12310 signal_pending
-11640 251 f, 118 +, 11758 -, diff: -11640 __skb_trim
-11059 111 f, 293 +, 11352 -, diff: -11059 __nlmsg_put
-10976 209 f, 123 +, 11099 -, diff: -10976 skb_trim
-10344 125 f, 462 +, 10806 -, diff: -10344 pskb_may_pull
-10061 300 f, 1163 +, 11224 -, diff: -10061 try_module_get
-10008 75 f, 341 +, 10349 -, diff: -10008 nlmsg_put
~250 are in 1000+ bytes category and ~440 in 500+. Full list
has some entries without number because given config doesn't
build them, and therefore nothing got uninlined, and the missing
entries consists solely of compile failures, available here:
http://www.cs.helsinki.fi/u/ijjarvin/inlines/sorted
I made some patches to uninline couple of them (picked mostly
net related) to stir up some discussion, however, some of them
are not ready for inclusion as is (see patch descriptions).
The cases don't represent all top 8 cases because some of the
cases require a bit more analysis (e.g., config dependant,
comments about gcc optimizations).
The tools I used are available here except the site-specific
distribute machinery (in addition one needs pretty late
codiff from Arnaldo's toolset because there were some inline
related bugs fixed lately):
http://www.cs.helsinki.fi/u/ijjarvin/inline-tools.git/
I'm planning to run similar tests also on inlines in headers that
are not under include/ but it requires minor modifications to
those tools.
--
i.
ps. I'm sorry about the duplicates, old git-send-email's
8-bit-header problem bit me again. :-(
From: Ilpo Järvinen <hidden> Date: 2008-02-20 13:48:09
~500 files changed
...
kernel/uninlined.c:
skb_put | +104
1 function changed, 104 bytes added, diff: +104
vmlinux.o:
869 functions changed, 198 bytes added, 111003 bytes removed, diff: -110805
This change is INCOMPLETE, I think that the call to current_text_addr()
should be rethought but I don't have a clue how to do that.
Signed-off-by: Ilpo Järvinen <redacted>
---
include/linux/skbuff.h | 20 +-------------------
net/core/skbuff.c | 21 +++++++++++++++++++++
2 files changed, 22 insertions(+), 19 deletions(-)
@@ -857,6 +857,27 @@ free_skb:returnerr;}+/**+*skb_put-adddatatoabuffer+*@skb:buffertouse+*@len:amountofdatatoadd+*+*Thisfunctionextendstheuseddataareaofthebuffer.Ifthiswould+*exceedthetotalbuffersizethekernelwillpanic.Apointertothe+*firstbyteoftheextradataisreturned.+*/+unsignedchar*skb_put(structsk_buff*skb,unsignedintlen)+{+unsignedchar*tmp=skb_tail_pointer(skb);+SKB_LINEAR_ASSERT(skb);+skb->tail+=len;+skb->len+=len;+if(unlikely(skb->tail>skb->end))+skb_over_panic(skb,len,current_text_addr());+returntmp;+}+EXPORT_SYMBOL(skb_put);+/* Trims skb to length len. It can change skb pointers.*/
@@ -158,15 +158,7 @@ struct dst_entry * dst_clone(struct dst_entry * dst)returndst;}-staticinline-voiddst_release(structdst_entry*dst)-{-if(dst){-WARN_ON(atomic_read(&dst->__refcnt)<1);-smp_mb__before_atomic_dec();-atomic_dec(&dst->__refcnt);-}-}+externvoiddst_release(structdst_entry*dst);/* Children define the path of the packet through the*Linuxnetworking.Thus,destinationsarestackable.
@@ -259,6 +259,16 @@ again:returnNULL;}+voiddst_release(structdst_entry*dst)+{+if(dst){+WARN_ON(atomic_read(&dst->__refcnt)<1);+smp_mb__before_atomic_dec();+atomic_dec(&dst->__refcnt);+}+}+EXPORT_SYMBOL(dst_release);+/* Dirty hack. We did it in 2.2 (in __dst_free),*wehave_very_goodreasonsnottorepeat*thismistakein2.3,butwehavenochoice
@@ -385,13 +385,9 @@ static inline int ADDIP_SERIAL_gte(__u16 s, __u16 t)return(((s)==(t))||(((t)-(s))&ADDIP_SERIAL_SIGN_BIT));}-/* Run sctp_add_cmd() generating a BUG() if there is a failure. */-staticinlinevoidsctp_add_cmd_sf(sctp_cmd_seq_t*seq,sctp_verb_tverb,sctp_arg_tobj)-{-if(unlikely(!sctp_add_cmd(seq,verb,obj)))-BUG();-}+externvoidsctp_add_cmd_sf(sctp_cmd_seq_t*seq,sctp_verb_tverb,+sctp_arg_tobj);/* Check VTAG of the packet matches the sender's own tag. */staticinlineint
@@ -51,8 +51,11 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)/* Add a command to a sctp_cmd_seq_t.*Return0ifthecommandsequenceisfull.+*+*Inlinehereisnotamistake,thiswaysctp_add_cmd_sfdoesn'tneedextra+*calls,sizepenaltyisofinsignificantmagnitudehere*/-intsctp_add_cmd(sctp_cmd_seq_t*seq,sctp_verb_tverb,sctp_arg_tobj)+inlineintsctp_add_cmd(sctp_cmd_seq_t*seq,sctp_verb_tverb,sctp_arg_tobj){if(seq->next_free_slot>=SCTP_MAX_NUM_COMMANDS)gotofail;
@@ -66,6 +69,13 @@ fail:return0;}+/* Run sctp_add_cmd() generating a BUG() if there is a failure. */+voidsctp_add_cmd_sf(sctp_cmd_seq_t*seq,sctp_verb_tverb,sctp_arg_tobj)+{+if(unlikely(!sctp_add_cmd(seq,verb,obj)))+BUG();+}+/* Return the next command structure in a sctp_cmd_seq.*ReturnsNULLattheendofthesequence.*/
@@ -1,25 +1,6 @@#ifndef _LINUX_JHASH_H#define _LINUX_JHASH_H-/* jhash.h: Jenkins hash support.-*-*Copyright(C)1996BobJenkins(bob_jenkins@burtleburtle.net)-*-*http://burtleburtle.net/bob/hash/-*-*ThesearethecreditsfromBob'ssources:-*-*lookup2.c,byBobJenkins,December1996,PublicDomain.-*hash(),hash2(),hash3,andmix()areexternallyusefulfunctions.-*RoutinestotestthehashareincludedifSELF_TESTisdefined.-*Youcanusethisfreeforanypurpose.Ithasnowarranty.-*-*Copyright(C)2003DavidS.Miller(davem@redhat.com)-*-*I'vemodifiedBob'shashtobeusefulintheLinuxkernel,and-*anybugspresentaresurelymyfault.-DaveM-*/-/* NOTE: Arguments are modified. */#define __jhash_mix(a, b, c) \{\
@@ -41,77 +22,12 @@*ofbytes.Noalignmentorlengthassumptionsaremadeabout*theinputkey.*/-staticinlineu32jhash(constvoid*key,u32length,u32initval)-{-u32a,b,c,len;-constu8*k=key;--len=length;-a=b=JHASH_GOLDEN_RATIO;-c=initval;--while(len>=12){-a+=(k[0]+((u32)k[1]<<8)+((u32)k[2]<<16)+((u32)k[3]<<24));-b+=(k[4]+((u32)k[5]<<8)+((u32)k[6]<<16)+((u32)k[7]<<24));-c+=(k[8]+((u32)k[9]<<8)+((u32)k[10]<<16)+((u32)k[11]<<24));--__jhash_mix(a,b,c);--k+=12;-len-=12;-}--c+=length;-switch(len){-case11:c+=((u32)k[10]<<24);-case10:c+=((u32)k[9]<<16);-case9:c+=((u32)k[8]<<8);-case8:b+=((u32)k[7]<<24);-case7:b+=((u32)k[6]<<16);-case6:b+=((u32)k[5]<<8);-case5:b+=k[4];-case4:a+=((u32)k[3]<<24);-case3:a+=((u32)k[2]<<16);-case2:a+=((u32)k[1]<<8);-case1:a+=k[0];-};--__jhash_mix(a,b,c);--returnc;-}+externu32jhash(constvoid*key,u32length,u32initval);/* A special optimized version that handles 1 or more of u32s.*Thelengthparameterhereisthenumberofu32sinthekey.*/-staticinlineu32jhash2(constu32*k,u32length,u32initval)-{-u32a,b,c,len;--a=b=JHASH_GOLDEN_RATIO;-c=initval;-len=length;--while(len>=3){-a+=k[0];-b+=k[1];-c+=k[2];-__jhash_mix(a,b,c);-k+=3;len-=3;-}--c+=length*4;--switch(len){-case2:b+=k[1];-case1:a+=k[0];-};--__jhash_mix(a,b,c);--returnc;-}-+externu32jhash2(constu32*k,u32length,u32initval);/* A special ultra-optimized versions that knows they are hashing exactly*3,2or1word(s).
@@ -85,6 +85,12 @@ config GENERIC_ALLOCATORboolean#+# Jenkins has support is selected if needed+#+configJHASH+boolean++## reed solomon support is select'ed if needed#configREED_SOLOMON
@@ -0,0 +1,116 @@+/* jhash.c: Jenkins hash support.+*+*Copyright(C)1996BobJenkins(bob_jenkins@burtleburtle.net)+*+*http://burtleburtle.net/bob/hash/+*+*ThesearethecreditsfromBob'ssources:+*+*lookup2.c,byBobJenkins,December1996,PublicDomain.+*hash(),hash2(),hash3,andmix()areexternallyusefulfunctions.+*RoutinestotestthehashareincludedifSELF_TESTisdefined.+*Youcanusethisfreeforanypurpose.Ithasnowarranty.+*+*Copyright(C)2003DavidS.Miller(davem@redhat.com)+*+*I'vemodifiedBob'shashtobeusefulintheLinuxkernel,and+*anybugspresentaresurelymyfault.-DaveM+*/+#include<linux/kernel.h>+#include<linux/jhash.h>+#include<linux/module.h>++/* The most generic version, hashes an arbitrary sequence+*ofbytes.Noalignmentorlengthassumptionsaremadeabout+*theinputkey.+*/+u32jhash(constvoid*key,u32length,u32initval)+{+u32a,b,c,len;+constu8*k=key;++len=length;+a=b=JHASH_GOLDEN_RATIO;+c=initval;++while(len>=12){+a+=(k[0]+((u32)k[1]<<8)+((u32)k[2]<<16)+((u32)k[3]<<24));+b+=(k[4]+((u32)k[5]<<8)+((u32)k[6]<<16)+((u32)k[7]<<24));+c+=(k[8]+((u32)k[9]<<8)+((u32)k[10]<<16)+((u32)k[11]<<24));++__jhash_mix(a,b,c);++k+=12;+len-=12;+}++c+=length;+switch(len){+case11:c+=((u32)k[10]<<24);+case10:c+=((u32)k[9]<<16);+case9:c+=((u32)k[8]<<8);+case8:b+=((u32)k[7]<<24);+case7:b+=((u32)k[6]<<16);+case6:b+=((u32)k[5]<<8);+case5:b+=k[4];+case4:a+=((u32)k[3]<<24);+case3:a+=((u32)k[2]<<16);+case2:a+=((u32)k[1]<<8);+case1:a+=k[0];+};++__jhash_mix(a,b,c);++returnc;+}+EXPORT_SYMBOL(jhash);++/* A special optimized version that handles 1 or more of u32s.+*Thelengthparameterhereisthenumberofu32sinthekey.+*/+u32jhash2(constu32*k,u32length,u32initval)+{+u32a,b,c,len;++a=b=JHASH_GOLDEN_RATIO;+c=initval;+len=length;++while(len>=3){+a+=k[0];+b+=k[1];+c+=k[2];+__jhash_mix(a,b,c);+k+=3;len-=3;+}++c+=length*4;++switch(len){+case2:b+=k[1];+case1:a+=k[0];+};++__jhash_mix(a,b,c);++returnc;+}+EXPORT_SYMBOL(jhash2);++/* A special ultra-optimized versions that knows they are hashing exactly+*3,2or1word(s).+*+*NOTE:Inpartilarthe"c += length; __jhash_mix(a,b,c);"normally+*doneattheendisnotdonehere.+*/+u32jhash_3words(u32a,u32b,u32c,u32initval)+{+a+=JHASH_GOLDEN_RATIO;+b+=JHASH_GOLDEN_RATIO;+c+=initval;++__jhash_mix(a,b,c);++returnc;+}+EXPORT_SYMBOL(jhash_3words);
From: Andrew Morton <akpm@linux-foundation.org> Date: 2008-02-23 08:03:54
On Wed, 20 Feb 2008 15:47:18 +0200 "Ilpo Järvinen" [off-list ref] wrote:
vmlinux.o:
62 functions changed, 66 bytes added, 10935 bytes removed, diff: -10869
...+ these to lib/jhash.o:
jhash_3words: 112
jhash2: 276
jhash: 475
select for networking code might need a more fine-grained approach.
It should be possible to use a modular jhash.ko. The things which you
have identified as clients of the jhash library are usually loaded as modules.
But in the case where someone does (say) NFSD=y we do need jhash.o linked into
vmlinux also. This is doable in Kconfig but I always forget how. Adrian, Sam
and Randy are the repositories of knowledge here ;)
From: Ilpo Järvinen <hidden> Date: 2008-02-23 10:05:57
On Sat, 23 Feb 2008, Andrew Morton wrote:
On Wed, 20 Feb 2008 15:47:18 +0200 "Ilpo Järvinen" [off-list ref] wrote:
quoted
vmlinux.o:
62 functions changed, 66 bytes added, 10935 bytes removed, diff: -10869
...+ these to lib/jhash.o:
jhash_3words: 112
jhash2: 276
jhash: 475
select for networking code might need a more fine-grained approach.
It should be possible to use a modular jhash.ko. The things which you
have identified as clients of the jhash library are usually loaded as modules.
But in the case where someone does (say) NFSD=y we do need jhash.o linked into
vmlinux also. This is doable in Kconfig but I always forget how.
Ok, even though its not that likely that one lives without e.g.
net/ipv4/inet_connection_sock.c or net/netlink/af_netlink.c? But maybe
some guys "really know what they are doing" and can come up with config
that would be able to build it as module (for other than proof-of-concept
uses I mean)... :-/
Adrian, Sam and Randy are the repositories of knowledge here ;)
Thanks, I'll consult them in this. I've never needed to do any Kconfig
stuff so far so it's no surprise I have very little clue... :-)
I've one question for you Andrew, how would you like this kind of
cross-subsys toucher to be merged, through you directly I suppose?
--
i.
From: Andrew Morton <akpm@linux-foundation.org> Date: 2008-02-23 18:23:00
On Sat, 23 Feb 2008 12:05:36 +0200 (EET) "Ilpo Järvinen" [off-list ref] wrote:
On Sat, 23 Feb 2008, Andrew Morton wrote:
quoted
On Wed, 20 Feb 2008 15:47:18 +0200 "Ilpo Järvinen" [off-list ref] wrote:
quoted
vmlinux.o:
62 functions changed, 66 bytes added, 10935 bytes removed, diff: -10869
...+ these to lib/jhash.o:
jhash_3words: 112
jhash2: 276
jhash: 475
select for networking code might need a more fine-grained approach.
It should be possible to use a modular jhash.ko. The things which you
have identified as clients of the jhash library are usually loaded as modules.
But in the case where someone does (say) NFSD=y we do need jhash.o linked into
vmlinux also. This is doable in Kconfig but I always forget how.
Ok, even though its not that likely that one lives without e.g.
net/ipv4/inet_connection_sock.c or net/netlink/af_netlink.c?
Sure, the number of people who will want CONFIG_JHASH=n is very small.
But maybe
some guys "really know what they are doing" and can come up with config
that would be able to build it as module (for other than proof-of-concept
uses I mean)... :-/
quoted
Adrian, Sam and Randy are the repositories of knowledge here ;)
Thanks, I'll consult them in this. I've never needed to do any Kconfig
stuff so far so it's no surprise I have very little clue... :-)
Thanks. If it gets messy I'd just put lib/jhash.o in obj-y. I assume it's
pretty small.
I've one question for you Andrew, how would you like this kind of
cross-subsys toucher to be merged, through you directly I suppose?
Sure, I can scrounge around for appropriate reviews and acks and can make
sure that nobody's pending work gets disrupted.
I added inline to sctp_add_cmd and appropriate comment there to
avoid adding another call into the call chain. This works at least
with "gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13)". Alternatively,
__sctp_add_cmd could be introduced to .h.
My only concern was performance regressions, but it looks like it
doesn't effect anything from the few quick runs I've made.
Since we are putting sctp_add_cmd_sf() on the call stack, we might
as well get rid of sctp_add_cmd() and reduce it a bit more.
-vlad
From: Ilpo Järvinen <hidden> Date: 2008-02-20 22:34:51
On Wed, 20 Feb 2008, Vlad Yasevich wrote:
Ilpo Järvinen wrote:
quoted
I added inline to sctp_add_cmd and appropriate comment there to
avoid adding another call into the call chain. This works at least
with "gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13)". Alternatively,
__sctp_add_cmd could be introduced to .h.
My only concern was performance regressions, but it looks like it
doesn't effect anything from the few quick runs I've made.
There was one call made anyway, it's a bit hard to see how it would hurt
to push that BUG() deeper down (in fact, this is one of the easiest case
in this respect, many other cases elsewhere that need uninlining don't
currently make any calls with inlines).
Since we are putting sctp_add_cmd_sf() on the call stack, we might
as well get rid of sctp_add_cmd() and reduce it a bit more.
IMHO it is definately better solution for archiving the size reduction,
I just didn't know before that the only sctp_add_cmd call could be
converted.
[...snip...]
@@ -51,19 +51,16 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)/* Add a command to a sctp_cmd_seq_t.*Return0ifthecommandsequenceisfull.+*+*Inlinehereisnotamistake,thiswaysctp_add_cmd_sfdoesn'tneedextra+*calls,sizepenaltyisofinsignificantmagnitudehere
This won't be a necessary note anymore. :-)
[...snip...]
--
i.
I added inline to sctp_add_cmd and appropriate comment there to
avoid adding another call into the call chain. This works at least
with "gcc (GCC) 4.1.2 20070626 (Red Hat 4.1.2-13)". Alternatively,
__sctp_add_cmd could be introduced to .h.
My only concern was performance regressions, but it looks like it
doesn't effect anything from the few quick runs I've made.
There was one call made anyway, it's a bit hard to see how it would hurt
to push that BUG() deeper down (in fact, this is one of the easiest case
in this respect, many other cases elsewhere that need uninlining don't
currently make any calls with inlines).
quoted
Since we are putting sctp_add_cmd_sf() on the call stack, we might
as well get rid of sctp_add_cmd() and reduce it a bit more.
IMHO it is definately better solution for archiving the size reduction,
I just didn't know before that the only sctp_add_cmd call could be
converted.
That one was a really silly one. The chance of not calling BUG() in
that one case was so small, that it didn't really make any sense from
the code robustness side.
@@ -51,19 +51,16 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)/* Add a command to a sctp_cmd_seq_t.*Return0ifthecommandsequenceisfull.+*+*Inlinehereisnotamistake,thiswaysctp_add_cmd_sfdoesn'tneedextra+*calls,sizepenaltyisofinsignificantmagnitudehere
This won't be a necessary note anymore. :-)
[...snip...]
Yeah. If you are going to resubmit, feel free to put my Signed-off-by line.
-vlad
Striking. How can this even happen? A callsite which calls
dev_alloc_skb(n)
is just equivalent to
__dev_alloc_skb(n, GFP_ATOMIC);
which means there's like 4 (or 8 if it's long) bytes more on the
stack. For a worst case, count in another 8 bytes for push and pop or mov on
the stack. But that still does not add up to 23 kb.
Striking. How can this even happen? A callsite which calls
dev_alloc_skb(n)
is just equivalent to
__dev_alloc_skb(n, GFP_ATOMIC);
which means there's like 4 (or 8 if it's long) bytes more on the
stack. For a worst case, count in another 8 bytes for push and pop or mov on
the stack. But that still does not add up to 23 kb.
__dev_alloc_skb() is also an inline function which performs
some extra work. Which raises the question - if dev_alloc_skb()
is uninlined, shouldn't __dev_alloc_skb() be uninline as well?
From: Jan Engelhardt <hidden> Date: 2008-02-20 16:39:50
On Feb 20 2008 17:27, Patrick McHardy wrote:
quoted
Striking. How can this even happen? A callsite which calls
dev_alloc_skb(n)
is just equivalent to
__dev_alloc_skb(n, GFP_ATOMIC);
which means there's like 4 (or 8 if it's long) bytes more on the
stack. For a worst case, count in another 8 bytes for push and pop or mov on
the stack. But that still does not add up to 23 kb.
__dev_alloc_skb() is also an inline function which performs
some extra work. Which raises the question - if dev_alloc_skb()
is uninlined, shouldn't __dev_alloc_skb() be uninline as well?
I'd like to see the results when {__dev_alloc_skb is externed
and dev_alloc_skb remains inlined}.
From: Ilpo Järvinen <hidden> Date: 2008-02-20 22:19:20
On Wed, 20 Feb 2008, Jan Engelhardt wrote:
On Feb 20 2008 17:27, Patrick McHardy wrote:
quoted
quoted
Striking. How can this even happen? A callsite which calls
dev_alloc_skb(n)
is just equivalent to
__dev_alloc_skb(n, GFP_ATOMIC);
which means there's like 4 (or 8 if it's long) bytes more on the
stack. For a worst case, count in another 8 bytes for push and pop or mov on
the stack. But that still does not add up to 23 kb.
I think you misunderstood the results, if I uninlined dev_alloc_skb(), it
_alone_ was uninlined which basically means that __dev_alloc_skb() that is
inline as well is included inside that uninlined function.
When both were inlined, they add up to everywhere, and uninlining
dev_alloc_skb alone mitigates that for both(!) of them in every place
where dev_alloc_skb is being called. Because __dev_alloc_skb call sites
are few, most benefits show up already with dev_alloc_skb uninlining
alone. On the other hand, if __dev_alloc_skb is uninlined, the size
reasoning you used above applies to dev_alloc_skb callsites, and that
is definately less than 23kB.
quoted
__dev_alloc_skb() is also an inline function which performs
some extra work. Which raises the question - if dev_alloc_skb()
is uninlined, shouldn't __dev_alloc_skb() be uninline as well?
Of course that could be done as well, however, I wouldn't be too keen to
deepen callchain by both of them, ie., uninlined dev_alloc_skb would just
contain few bytes which perform the call to __dev_alloc_skb which has the
bit larger content due to that "extra work". IMHO the best solution would
duplicate the "extra work" to both of them on binary level (obviously
not on the source level), e.g., by adding static inline ___dev_alloc_skb()
to .h which is inlined to both of the variants. I'm not too sure if inline
to __dev_alloc_skb() alone is enough in .c file to result in inlining of
__dev_alloc_skb to dev_alloc_skb (with all gcc versions and relevant
optimization settings).
I'd like to see the results when {__dev_alloc_skb is externed
and dev_alloc_skb remains inlined}.
The results are right under your nose already... ;-)
See from the list of the series introduction:
http://marc.info/?l=linux-netdev&m=120351526210711&w=2
IMHO more interesting number (which I currently don't have) is the
_remaining_ benefits of uninlining __dev_alloc_skb after
dev_alloc_skb was first uninlined.
--
i.
From: Ilpo Järvinen <hidden> Date: 2008-03-12 15:27:27
On Thu, 21 Feb 2008, Ilpo Järvinen wrote:
On Wed, 20 Feb 2008, Jan Engelhardt wrote:
quoted
On Feb 20 2008 17:27, Patrick McHardy wrote:
quoted
__dev_alloc_skb() is also an inline function which performs
some extra work. Which raises the question - if dev_alloc_skb()
I'd like to see the results when {__dev_alloc_skb is externed
and dev_alloc_skb remains inlined}.
The results are right under your nose already... ;-)
See from the list of the series introduction:
http://marc.info/?l=linux-netdev&m=120351526210711&w=2
IMHO more interesting number (which I currently don't have) is the
_remaining_ benefits of uninlining __dev_alloc_skb after
dev_alloc_skb was first uninlined.
I've measured this now... Without many debug CONFIGs (in v2.6.25-rc2-mm1),
the dev_alloc_skb is much less than 23kB:
382 funcs, 157 +, 12335 -, diff: -12178 --- dev_alloc_skb
dev_alloc_skb | +37
...and on top of that, I got only this:
48 funcs, 111 +, 836 -, diff: -725 --- __dev_alloc_skb
Not that impressive compared with many much worse cases (wasn't a big
surprise because there were fewer callsites for the latter).
Anyway, would I uninline it (or one some another function that has such
two variants that are good candidates for uninlining), should I try to
avoid deepening the call-chain by two functions? To me it seems that only
way to fool gcc to do that for sure would be using some trick like this:
Rename __dev_alloc_skb to ___dev_alloc_skb in the header (with appropriate
don't ever call this due to bloat comment added) and both __dev_alloc_skb
and dev_alloc_skb could then be made to call that one in .c file.
Otherwise I'm not that sure gcc wouldn't try to be too clever if I just
use inline in .c file.
--
i.
From: Patrick McHardy <hidden> Date: 2008-02-20 13:55:32
Ilpo Järvinen wrote:
~500 files changed
...
kernel/uninlined.c:
skb_put | +104
1 function changed, 104 bytes added, diff: +104
vmlinux.o:
869 functions changed, 198 bytes added, 111003 bytes removed, diff: -110805
This change is INCOMPLETE, I think that the call to current_text_addr()
should be rethought but I don't have a clue how to do that.
From: Eric Dumazet <hidden> Date: 2008-02-20 13:59:24
On Wed, 20 Feb 2008 15:47:11 +0200
"Ilpo Järvinen" [off-list ref] wrote:
~500 files changed
...
kernel/uninlined.c:
skb_put | +104
1 function changed, 104 bytes added, diff: +104
vmlinux.o:
869 functions changed, 198 bytes added, 111003 bytes removed, diff: -110805
This change is INCOMPLETE, I think that the call to current_text_addr()
should be rethought but I don't have a clue how to do that.
@@ -857,6 +857,27 @@ free_skb:returnerr;}+/**+*skb_put-adddatatoabuffer+*@skb:buffertouse+*@len:amountofdatatoadd+*+*Thisfunctionextendstheuseddataareaofthebuffer.Ifthiswould+*exceedthetotalbuffersizethekernelwillpanic.Apointertothe+*firstbyteoftheextradataisreturned.+*/+unsignedchar*skb_put(structsk_buff*skb,unsignedintlen)+{+unsignedchar*tmp=skb_tail_pointer(skb);+SKB_LINEAR_ASSERT(skb);+skb->tail+=len;+skb->len+=len;+if(unlikely(skb->tail>skb->end))+skb_over_panic(skb,len,current_text_addr());+returntmp;+}+EXPORT_SYMBOL(skb_put);+/* Trims skb to length len. It can change skb pointers.*/
--
1.5.2.2
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
This is a surprise. I expect that the -mm-only
profile-likely-unlikely-macros.patch is the cause of this and mainline
doesn't have this problem.
If true, then this likely/unlikely bloat has probably spread into a lot of
your other results and it all should be redone against mainline, sorry :(
(I'm not aware of anyone having used profile-likely-unlikely-macros.patch
in quite some time. That's unfortunate because it has turned up some
fairly flagrant code deoptimisations)
It surprised me as well, there were something like 10 bytes I just
couldn't explain in IS_ERR size (kernel/uninlined.c: IS_ERR | +25). I was
to look into it deeper but didn't have the .o's at hand right away, not so
trivial to store results of 5000+ build results except some carefully
picked textual output :-)... Hmm, I'll add logging for the disassembly of
the uninlined stuff into the next run, that won't cost too much...
I expect that the -mm-only
profile-likely-unlikely-macros.patch is the cause of this and mainline
doesn't have this problem.
Ahaa, this explain it, I suspected that there was something (un)likely
related elsewhere as well, no wonder why I couldn't reproduce the 25 bytes
result in my quick copy-pasted non-kernel test...
If true, then this likely/unlikely bloat has probably spread into a lot of
your other results and it all should be redone against mainline, sorry :(
It isn't that troublesome to redo them, it's mainly automatic combined
with impatient waiting from my behalf :-)... The spreading problem is
probably true, to some extent. I did some runs also with carefully
selected CONFIG.*DEBUG.* off under include/net/ earlier, in general it
made very little difference, if something bloats, it usually does that
regardless of .config. There are probably couple of exceptions when the
size is on the boundary where it's very close of being useful to uninline
it.
One interesting thing in there was that the largest offenders are quite
small per call-site but due to vast number of them even a small benefit
buys off a lot in kernel wide results. I suspect the differences due to
(un)likely will be negligle, because the IS_ERR with all its trivialness
is now mostly -15, so anything clearly larger than that will likely still
be a win x n (where n is quite large).
Anyway, I'll see when I get the new set of tests running... :-) I'd prefer
with CONFIG.*DEBUG off to get larger picture about non-debug builds too
(especially the scatterlist.h things interest me a lot), do you think that
would do as well?
Thanks for your comments, I found them very useful.
--
i.