Closed Bug 264456 Opened 20 years ago Closed 20 years ago

do_GetService causes unnecessary bloat

Categories

(Core :: XPCOM, defect, P2)

defect

Tracking

()

RESOLVED FIXED
mozilla1.8alpha5

People

(Reporter: dbaron, Assigned: dbaron)

References

Details

(Keywords: memory-footprint, Whiteboard: [patch])

Attachments

(4 files, 1 obsolete file)

do_GetService causes unnecessary code bloat due to having an nsCOMPtr member on nsGetServiceBy*, and doing a do_QueryInterface to initialize that member.
Attached patch patchSplinter Review
Attachment #162147 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Priority: -- → P2
Whiteboard: [patch]
Target Milestone: --- → mozilla1.8alpha5
unrelated, but please note that do_GetInterface also has unnecessary bloat: http://lxr.mozilla.org/seamonkey/source/xpcom/glue/nsIInterfaceRequestorUtils.h#71 nsGetInterface::operator() can be modified to use raw mSource XPCOM pointer It would also save one implicit AddRef()/Release() call for every use of do_GetInterface
Comment on attachment 162148 [details] [diff] [review] patch r=darin
Attachment #162148 - Flags: review?(darin) → review+
Comment on attachment 162203 [details] [diff] [review] patch for nsIInterfaceRequestorUtils r=darin
Attachment #162203 - Flags: review?(darin) → review+
Fixes checked in to trunk, 2004-10-15 10:44/11:03 -0700.
Status: ASSIGNED → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
These together seem to have improved Tp by about 1.5% - 2% on btek.
From luna (Suite Linux), for both patches: Z:17.93MB Zdiff:-202816 (+859/-203675) mZ:11.27MB mZdiff:-95724 (+223/-95947) From imola (Firefox Mac), for the first patch only, but with some of jst's changes as well: Z:15.53MB Zdiff:-82096 (+34644/-116740)
I think that second patch is more about performance (less refcounting). I think that most compilers will inline the nsGetInterface constructor after the second patch was checked in (I don't think it was inlined before because of the nsCOMPtr<> constructor, at least at -O1). So overall it is not evident that there's some code reduction with the second patch. I have another patch (almost ready) that does remove do_GetInterface() code bloat at all call sites by removing the inline error pointer assignment in nsGetInterface ctor. I think I'll file a new bug about that.
From egg (minimo tinderbox): first patch: mZ:7.506MB mZdiff:-51196 (+177/-51373) second patch: mZ:7.500MB mZdiff:-6840 (+2/-6842)
great stuff!
Comment on attachment 162148 [details] [diff] [review] patch >+ nsCOMPtr<nsIServiceManager> serviceManager = >+ do_QueryInterface(mServiceManager); >+ if ( serviceManager ) { >+ status = serviceManager->GetService(mCID, aIID, (void**)aInstancePtr); > } else { > nsCOMPtr<nsIServiceManager> mgr; > NS_GetServiceManager(getter_AddRefs(mgr)); > if (mgr) > status = mgr->GetService(mCID, aIID, (void**)aInstancePtr); > } Is the compiler is smart enough to optimize this as follows? nsCOMPtr<nsIServiceManager> mgr(do_QueryInterface(mServiceManager)); if (!mgr) NS_GetServiceManager(getter_AddRefs(mgr)); if (mgr) status = mgr->GetService(mCID, aIID, (void**)aInstancePtr);
Perhaps. But what's really meant is: nsCOMPtr<nsIServiceManager> mgr = do_QueryInterface(mServiceManager); if (mgr || (NS_GetServiceManager(getter_AddRefs(mgr)), mgr)) status = mgr->GetService(mCID, aIID, (void**)aInstancePtr);
We never actually pass a non-null service manager to do_GetService().
Comment on attachment 162345 [details] [diff] [review] remove nsIServiceManager parameter >- nsCOMPtr<nsICategoryManager> catman = >- do_GetService(kCategoryManagerCID, &rv); >- if (NS_FAILED(rv)) goto error; >+ nsCOMPtr<nsICategoryManager> catman; This is wrong.
Attachment #162345 - Flags: review-
(In reply to comment #16) > (From update of attachment 162345 [details] [diff] [review]) > >- nsCOMPtr<nsICategoryManager> catman = > >- do_GetService(kCategoryManagerCID, &rv); > >- if (NS_FAILED(rv)) goto error; > >+ nsCOMPtr<nsICategoryManager> catman; > > This is wrong. > What, exactly?
Comment on attachment 162345 [details] [diff] [review] remove nsIServiceManager parameter Oh, I see. But still, having to write NS_GET_IID() with an argument that's something other than a template parameter is evil.
Attachment #162345 - Flags: review-
(In reply to comment #18) > (From update of attachment 162345 [details] [diff] [review]) > Oh, I see. But still, having to write NS_GET_IID() with an argument that's > something other than a template parameter is evil. > Are you referring to using it in conjunction with getter_AddRefs() ? If so, I'm ok with making catman a raw pointer there, though I don't see what it gains us.
No, I'm referring to having to type "nsICategoryManager" twice for the same variable rather than using do_GetService or CallGetService. If you think reusing the service manager pointer rather than calling NS_GetServiceManager twice is that useful here, then you probably shouldn't remove the functionality... :-)
Now it is clear that do_GetService() relies heavily on NS_GetServiceManager() http://lxr.mozilla.org/seamonkey/source/xpcom/components/nsComponentManager.cpp#3722 Could it be possible to add a special NS_GetServiceManager function that doesn't addref ? It would save a lot of AddRef/Release calls. There's more than 3000 occurrences of do_GetService().
I'm not just removing the functionality for the fun of it; passing the extra parameter to nsGetServiceBy* makes extra work for the caller, and most callers aren't able to reuse the service manager because they're only interested in a single service. Here inside the do_GetServiceFromCategory() implementation, I think it makes sense to be as efficient as we can be, even if it means typing nsICategoryManager twice. It's not going to be a big deal either way though, do_GetServiceFromCategory has exactly one caller, and it's not all that performance sensitive.
(In reply to comment #21) > Could it be possible to add a special NS_GetServiceManager function that doesn't > addref ? It would save a lot of AddRef/Release calls. There's more than 3000 > occurrences of do_GetService(). I thought about that as well.. seems like a good idea.
After the removal of mServiceManager, it is now possible to consider specializing nsGetServiceXX for the case where mErrorPtr is null, I mean doing what has been done with nsQueryInterface/nsQueryInterfaceWithError(but operator() would still be virtual here): http://lxr.mozilla.org/seamonkey/source/xpcom/glue/nsCOMPtr.h#359 It would remove another extra member for some (most ?) callers, simplify the inline constructor, possibly remove some more bloat. (3000 do_GetService is less than 8000 do_QueryInterface but still...)
Comment on attachment 162345 [details] [diff] [review] remove nsIServiceManager parameter So can we go ahead and do this? iirc this saved about 30KB code size on Linux.
Attachment #162345 - Flags: review?(darin)
bryner: you might want to take a look at my patch in bug 263360. we might want to use the same approach for both of these bugs.
Blocks: 239088
Comment on attachment 162345 [details] [diff] [review] remove nsIServiceManager parameter This needs to be revised now that the patch for bug 239088 has landed. Removing from my review queue.
Attachment #162345 - Flags: review?(darin)
grr.. copy/paste error. i meant bug 263360 ;-)
reopening for new patch.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Attachment #166953 - Flags: review?(darin)
I like it ! Some remarks: 1) all "operator()" in nscomptr.h could be simplified by changing the signature from nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; to void* NS_FASTCALL operator()( const nsIID& ) const; assuming that the implementations return NULL when an error occurs then (for instance) void +nsCOMPtr_base::assign_from_gs_cid( const nsGetServiceByCID gs, const nsIID& iid ) + { + nsISupports* newRawPtr; + if ( NS_FAILED( gs(iid, NS_REINTERPRET_CAST(void**, &newRawPtr)) ) ) + newRawPtr = 0; + assign_assuming_AddRef(newRawPtr); + } would be void +nsCOMPtr_base::assign_from_gs_cid( const nsGetServiceByCID gs, const nsIID& iid ) + { + nsISupports* newRawPtr; + newRawPtr = gs(iid); + assign_assuming_AddRef(newRawPtr); + } or simply void +nsCOMPtr_base::assign_from_gs_cid( const nsGetServiceByCID gs, const nsIID& iid ) + { + assign_assuming_AddRef(gs(iid)); + } it will result in less call parameters overhead (push/pop, etc...) 2) the same "WithError" trick could be used with nsGetInterface http://lxr.mozilla.org/seamonkey/source/xpcom/glue/nsIInterfaceRequestorUtils.h#58 but it is probably another bug though it could be done easily There are about 1000 do_GetInterface() calls iirc 3) + void assign_from_gs_cid( const nsGetServiceByCID, const nsIID& ); + void assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError&, const nsIID& ); + void assign_from_gs_contractid( const nsGetServiceByContractID, const nsIID& ); + void assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError&, const nsIID& ); they all could be called "assigned_from_helper" because the parameters type are different : no need to find new names and it is shorter to write 4) it looks like bug that bug 264710 is fixed by this patch too.
Comment on attachment 166953 [details] [diff] [review] revised patch >Index: xpcom/components/nsComponentManager.cpp >+ rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID, >+ NS_GET_IID(nsICategoryManager), >+ getter_AddRefs(catman)); nit: indentation r=darin
Attachment #166953 - Flags: review?(darin) → review+
> 1) > all "operator()" in nscomptr.h could be simplified by changing the signature > from > nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; > to > void* NS_FASTCALL operator()( const nsIID& ) const; > > assuming that the implementations return NULL when an error occurs Let's hold off on that; I don't think we can say for sure that NULL will be returned when an error occurs. > 2) > the same "WithError" trick could be used with nsGetInterface > http://lxr.mozilla.org/seamonkey/source/xpcom/glue/nsIInterfaceRequestorUtils.h#58 > but it is probably another bug though it could be done easily > There are about 1000 do_GetInterface() calls iirc Sure, separate bug. > 3) > + void assign_from_gs_cid( const nsGetServiceByCID, const nsIID& ); > + void assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError&, > const nsIID& ); > + void assign_from_gs_contractid( const nsGetServiceByContractID, const > nsIID& ); > + void assign_from_gs_contractid_with_error( const > nsGetServiceByContractIDWithError&, const nsIID& ); > > they all could be called "assigned_from_helper" because the parameters type are > different : no need to find new names and it is shorter to write True, but I actually like it being explicit so it's clear whether the error parameter is present.
checked in.
Status: REOPENED → RESOLVED
Closed: 20 years ago20 years ago
Resolution: --- → FIXED
I've submitted several bugs with patches to consider applying the same tricks with do_GetInterface (bug 271845), do_GetIOService (bug 271823), do_GetFastLoadService (bug 271824), do_CreateInstance (bug 271817)
Keywords: footprint
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: