LCOV - code coverage report
Current view: directory - js/src - MemoryMetrics.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 122 118 96.7 %
Date: 2012-06-02 Functions: 9 9 100.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is about:memory glue.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Ms2ger <ms2ger@gmail.com>.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "js/MemoryMetrics.h"
      38                 : 
      39                 : #include "mozilla/Assertions.h"
      40                 : 
      41                 : #include "jsapi.h"
      42                 : #include "jscntxt.h"
      43                 : #include "jscompartment.h"
      44                 : #include "jsgc.h"
      45                 : #include "jsobj.h"
      46                 : #include "jsscope.h"
      47                 : #include "jsscript.h"
      48                 : 
      49                 : #include "jsobjinlines.h"
      50                 : 
      51                 : #ifdef JS_THREADSAFE
      52                 : 
      53                 : namespace JS {
      54                 : 
      55                 : using namespace js;
      56                 : 
      57                 : static void
      58               9 : StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
      59                 : {
      60                 :     // Append a new CompartmentStats to the vector.
      61               9 :     RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
      62                 : 
      63                 :     // CollectRuntimeStats reserves enough space.
      64               9 :     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
      65               9 :     CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
      66               9 :     rtStats->initExtraCompartmentStats(compartment, &cStats);
      67               9 :     rtStats->currCompartmentStats = &cStats;
      68                 : 
      69                 :     // Get the compartment-level numbers.
      70                 : #ifdef JS_METHODJIT
      71               9 :     cStats.mjitCode = compartment->sizeOfMjitCode();
      72                 : #endif
      73               9 :     compartment->sizeOfTypeInferenceData(&cStats.typeInferenceSizes, rtStats->mallocSizeOf);
      74               9 :     cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
      75               9 : }
      76                 : 
      77                 : static void
      78               9 : StatsChunkCallback(JSRuntime *rt, void *data, gc::Chunk *chunk)
      79                 : {
      80                 :     // Nb: This function is only called for dirty chunks, which is why we
      81                 :     // increment gcHeapChunkDirtyDecommitted.
      82               9 :     RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
      83            2277 :     for (size_t i = 0; i < gc::ArenasPerChunk; i++)
      84            2268 :         if (chunk->decommittedArenas.get(i))
      85               0 :             rtStats->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
      86               9 : }
      87                 : 
      88                 : static void
      89            1089 : StatsArenaCallback(JSRuntime *rt, void *data, gc::Arena *arena,
      90                 :                    JSGCTraceKind traceKind, size_t thingSize)
      91                 : {
      92            1089 :     RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
      93                 : 
      94            1089 :     rtStats->currCompartmentStats->gcHeapArenaHeaders += sizeof(gc::ArenaHeader);
      95            1089 :     size_t allocationSpace = arena->thingsSpan(thingSize);
      96                 :     rtStats->currCompartmentStats->gcHeapArenaPadding +=
      97            1089 :         gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
      98                 :     // We don't call the callback on unused things.  So we compute the
      99                 :     // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
     100                 :     // We do this by setting arenaUnused to maxArenaUnused here, and then
     101                 :     // subtracting thingSize for every used cell, in StatsCellCallback().
     102            1089 :     rtStats->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
     103            1089 : }
     104                 : 
     105                 : static void
     106          142578 : StatsCellCallback(JSRuntime *rt, void *data, void *thing, JSGCTraceKind traceKind,
     107                 :                   size_t thingSize)
     108                 : {
     109          142578 :     RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
     110          142578 :     CompartmentStats *cStats = rtStats->currCompartmentStats;
     111          142578 :     switch (traceKind) {
     112                 :     case JSTRACE_OBJECT:
     113                 :     {
     114           25914 :         JSObject *obj = static_cast<JSObject *>(thing);
     115           25914 :         if (obj->isFunction()) {
     116           16046 :             cStats->gcHeapObjectsFunction += thingSize;
     117                 :         } else {
     118            9868 :             cStats->gcHeapObjectsNonFunction += thingSize;
     119                 :         }
     120                 :         size_t slotsSize, elementsSize, miscSize;
     121                 :         obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize,
     122           25914 :                                  &elementsSize, &miscSize);
     123           25914 :         cStats->objectSlots += slotsSize;
     124           25914 :         cStats->objectElements += elementsSize;
     125           25914 :         cStats->objectMisc += miscSize;
     126           25914 :         break;
     127                 :     }
     128                 :     case JSTRACE_STRING:
     129                 :     {
     130           61918 :         JSString *str = static_cast<JSString *>(thing);
     131           61918 :         cStats->gcHeapStrings += thingSize;
     132           61918 :         cStats->stringChars += str->sizeOfExcludingThis(rtStats->mallocSizeOf);
     133           61918 :         break;
     134                 :     }
     135                 :     case JSTRACE_SHAPE:
     136                 :     {
     137           43133 :         Shape *shape = static_cast<Shape*>(thing);
     138                 :         size_t propTableSize, kidsSize;
     139           43133 :         shape->sizeOfExcludingThis(rtStats->mallocSizeOf, &propTableSize, &kidsSize);
     140           43133 :         if (shape->inDictionary()) {
     141           14112 :             cStats->gcHeapShapesDict += thingSize;
     142           14112 :             cStats->shapesExtraDictTables += propTableSize;
     143           14112 :             JS_ASSERT(kidsSize == 0);
     144                 :         } else {
     145           29021 :             cStats->gcHeapShapesTree += thingSize;
     146           29021 :             cStats->shapesExtraTreeTables += propTableSize;
     147           29021 :             cStats->shapesExtraTreeShapeKids += kidsSize;
     148                 :         }
     149           43133 :         break;
     150                 :     }
     151                 :     case JSTRACE_BASE_SHAPE:
     152                 :     {
     153            6944 :         cStats->gcHeapShapesBase += thingSize;
     154            6944 :         break;
     155                 :     }
     156                 :     case JSTRACE_SCRIPT:
     157                 :     {
     158            3818 :         JSScript *script = static_cast<JSScript *>(thing);
     159            3818 :         cStats->gcHeapScripts += thingSize;
     160            3818 :         cStats->scriptData += script->sizeOfData(rtStats->mallocSizeOf);
     161                 : #ifdef JS_METHODJIT
     162            3818 :         cStats->mjitData += script->sizeOfJitScripts(rtStats->mallocSizeOf);
     163                 : #endif
     164            3818 :         break;
     165                 :     }
     166                 :     case JSTRACE_TYPE_OBJECT:
     167                 :     {
     168             851 :         types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
     169             851 :         cStats->gcHeapTypeObjects += thingSize;
     170             851 :         obj->sizeOfExcludingThis(&cStats->typeInferenceSizes, rtStats->mallocSizeOf);
     171             851 :         break;
     172                 :     }
     173                 :     case JSTRACE_XML:
     174                 :     {
     175               0 :         cStats->gcHeapXML += thingSize;
     176               0 :         break;
     177                 :     }
     178                 :     }
     179                 :     // Yes, this is a subtraction:  see StatsArenaCallback() for details.
     180          142578 :     cStats->gcHeapArenaUnused -= thingSize;
     181          142578 : }
     182                 : 
     183                 : JS_PUBLIC_API(bool)
     184               3 : CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
     185                 : {
     186               3 :     if (!rtStats->compartmentStatsVector.reserve(rt->compartments.length()))
     187               0 :         return false;
     188                 :     
     189                 :     rtStats->gcHeapChunkCleanDecommitted =
     190               3 :         rt->gcChunkPool.countCleanDecommittedArenas(rt) * gc::ArenaSize;
     191                 :     rtStats->gcHeapChunkCleanUnused =
     192               3 :         size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize -
     193               3 :         rtStats->gcHeapChunkCleanDecommitted;
     194                 :     rtStats->gcHeapChunkTotal =
     195               3 :         size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
     196                 :     
     197                 :     IterateCompartmentsArenasCells(rt, rtStats, StatsCompartmentCallback,
     198               3 :                                    StatsArenaCallback, StatsCellCallback);
     199               3 :     IterateChunks(rt, rtStats, StatsChunkCallback);
     200                 :     
     201               3 :     rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
     202                 :     
     203                 :     rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
     204                 :                             &rtStats->runtimeNormal,
     205                 :                             &rtStats->runtimeTemporary,
     206                 :                             &rtStats->runtimeRegexpCode,
     207                 :                             &rtStats->runtimeStackCommitted,
     208               3 :                             &rtStats->runtimeGCMarker);
     209                 :     
     210                 :     rtStats->runtimeAtomsTable =
     211               3 :         rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf);
     212                 :     
     213              12 :     for (ContextIter acx(rt); !acx.done(); acx.next())
     214               9 :         rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf);
     215                 : 
     216                 :     // This is initialized to all bytes stored in used chunks, and then we
     217                 :     // subtract used space from it each time around the loop.
     218                 :     rtStats->gcHeapChunkDirtyUnused = rtStats->gcHeapChunkTotal -
     219                 :                                       rtStats->gcHeapChunkCleanUnused -
     220                 :                                       rtStats->gcHeapChunkCleanDecommitted -
     221               3 :                                       rtStats->gcHeapChunkDirtyDecommitted;
     222                 : 
     223              24 :     for (size_t index = 0;
     224              12 :          index < rtStats->compartmentStatsVector.length();
     225                 :          index++) {
     226               9 :         CompartmentStats &cStats = rtStats->compartmentStatsVector[index];
     227                 : 
     228                 :         size_t used = cStats.gcHeapArenaHeaders +
     229                 :                       cStats.gcHeapArenaPadding +
     230                 :                       cStats.gcHeapArenaUnused +
     231                 :                       cStats.gcHeapObjectsNonFunction +
     232                 :                       cStats.gcHeapObjectsFunction +
     233                 :                       cStats.gcHeapStrings +
     234                 :                       cStats.gcHeapShapesTree +
     235                 :                       cStats.gcHeapShapesDict +
     236                 :                       cStats.gcHeapShapesBase +
     237                 :                       cStats.gcHeapScripts +
     238                 :                       cStats.gcHeapTypeObjects +
     239               9 :                       cStats.gcHeapXML;
     240                 : 
     241               9 :         rtStats->gcHeapChunkDirtyUnused -= used;
     242               9 :         rtStats->gcHeapArenaUnused += cStats.gcHeapArenaUnused;
     243                 :         rtStats->totalObjects += cStats.gcHeapObjectsNonFunction +
     244                 :                                  cStats.gcHeapObjectsFunction +
     245                 :                                  cStats.objectSlots +
     246                 :                                  cStats.objectElements +
     247               9 :                                  cStats.objectMisc;
     248                 :         rtStats->totalShapes  += cStats.gcHeapShapesTree +
     249                 :                                  cStats.gcHeapShapesDict +
     250                 :                                  cStats.gcHeapShapesBase +
     251                 :                                  cStats.shapesExtraTreeTables +
     252                 :                                  cStats.shapesExtraDictTables +
     253               9 :                                  cStats.shapesCompartmentTables;
     254                 :         rtStats->totalScripts += cStats.gcHeapScripts +
     255               9 :                                  cStats.scriptData;
     256                 :         rtStats->totalStrings += cStats.gcHeapStrings +
     257               9 :                                  cStats.stringChars;
     258                 : #ifdef JS_METHODJIT
     259                 :         rtStats->totalMjit    += cStats.mjitCode +
     260               9 :                                  cStats.mjitData;
     261                 : #endif
     262                 :         rtStats->totalTypeInference += cStats.gcHeapTypeObjects +
     263                 :                                        cStats.typeInferenceSizes.objects +
     264                 :                                        cStats.typeInferenceSizes.scripts +
     265               9 :                                        cStats.typeInferenceSizes.tables;
     266               9 :         rtStats->totalAnalysisTemp  += cStats.typeInferenceSizes.temporary;
     267                 :     }
     268                 : 
     269                 :     size_t numDirtyChunks = (rtStats->gcHeapChunkTotal -
     270                 :                              rtStats->gcHeapChunkCleanUnused) /
     271               3 :                             gc::ChunkSize;
     272                 :     size_t perChunkAdmin =
     273               3 :         sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
     274               3 :     rtStats->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
     275               3 :     rtStats->gcHeapChunkDirtyUnused -= rtStats->gcHeapChunkAdmin;
     276                 : 
     277                 :     // Why 10000x?  100x because it's a percentage, and another 100x
     278                 :     // because nsIMemoryReporter requires that for percentage amounts so
     279                 :     // they can be fractional.
     280                 :     rtStats->gcHeapUnusedPercentage = (rtStats->gcHeapChunkCleanUnused +
     281                 :                                        rtStats->gcHeapChunkDirtyUnused +
     282                 :                                        rtStats->gcHeapChunkCleanDecommitted +
     283                 :                                        rtStats->gcHeapChunkDirtyDecommitted +
     284                 :                                        rtStats->gcHeapArenaUnused) * 10000 /
     285               3 :                                        rtStats->gcHeapChunkTotal;
     286                 : 
     287               3 :     return true;
     288                 : }
     289                 : 
     290                 : static void
     291               9 : ExplicitNonHeapCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
     292                 : {
     293                 : #ifdef JS_METHODJIT
     294               9 :     size_t *n = static_cast<size_t *>(data);
     295               9 :     *n += compartment->sizeOfMjitCode();
     296                 : #endif
     297               9 : }
     298                 : 
     299                 : JS_PUBLIC_API(int64_t)
     300               3 : GetExplicitNonHeapForRuntime(JSRuntime *rt, JSMallocSizeOfFun mallocSizeOf)
     301                 : {
     302                 :     // explicit/<compartment>/gc-heap/*
     303               3 :     size_t n = size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
     304                 : 
     305                 :     // explicit/<compartment>/mjit-code
     306               3 :     JS_IterateCompartments(rt, &n, ExplicitNonHeapCompartmentCallback);
     307                 :     
     308                 :     // explicit/runtime/regexp-code
     309                 :     // explicit/runtime/stack-committed
     310                 :     size_t regexpCode, stackCommitted;
     311                 :     rt->sizeOfExcludingThis(mallocSizeOf,
     312                 :                             NULL,
     313                 :                             NULL,
     314                 :                             &regexpCode,
     315                 :                             &stackCommitted,
     316               3 :                             NULL);
     317                 :     
     318               3 :     n += regexpCode;
     319               3 :     n += stackCommitted;
     320                 : 
     321               3 :     return int64_t(n);
     322                 : }
     323                 : 
     324                 : JS_PUBLIC_API(size_t)
     325               3 : SystemCompartmentCount(const JSRuntime *rt)
     326                 : {
     327               3 :     size_t n = 0;
     328              12 :     for (size_t i = 0; i < rt->compartments.length(); i++) {
     329               9 :         if (rt->compartments[i]->isSystemCompartment)
     330               6 :             ++n;
     331                 :     }
     332               3 :     return n;
     333                 : }
     334                 : 
     335                 : JS_PUBLIC_API(size_t)
     336               3 : UserCompartmentCount(const JSRuntime *rt)
     337                 : {
     338               3 :     size_t n = 0;
     339              12 :     for (size_t i = 0; i < rt->compartments.length(); i++) {
     340               9 :         if (!rt->compartments[i]->isSystemCompartment)
     341               3 :             ++n;
     342                 :     }
     343               3 :     return n;
     344                 : }
     345                 : 
     346                 : } // namespace JS
     347                 : 
     348                 : #endif // JS_THREADSAFE

Generated by: LCOV version 1.7