Commit f5eea634 authored by Bill McCloskey's avatar Bill McCloskey
Browse files

Bug 745034 - Add page fault counts to GC statistics (r=terrence,dmandelin)

parent d9d9276c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2165,7 +2165,7 @@ ia64*-hpux*)
        # Use temp file for windres (bug 213281)
        RCFLAGS='-O coff --use-temp-file'
        # mingw doesn't require kernel32, user32, and advapi32 explicitly
        LIBS="$LIBS -lgdi32 -lwinmm -lwsock32"
        LIBS="$LIBS -lgdi32 -lwinmm -lwsock32 -lpsapi"
        MOZ_JS_LIBS='-L$(libdir) -lmozjs'
        MOZ_FIX_LINK_PATHS=
        DYNAMIC_XPCOM_LIBS='-L$(LIBXUL_DIST)/lib -lxpcom -lxpcom_core -lmozalloc'
@@ -2210,7 +2210,7 @@ ia64*-hpux*)
        # make 'foo == bar;' error out
        CFLAGS="$CFLAGS -we4553"
        CXXFLAGS="$CXXFLAGS -we4553"
        LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib"
        LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib psapi.lib"
        MOZ_DEBUG_FLAGS='-Zi'
        MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
        WARNINGS_AS_ERRORS='-WX'
+34 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ namespace gc {

#if defined(XP_WIN)
#include "jswin.h"
#include <psapi.h>

static size_t AllocationGranularity = 0;

@@ -91,6 +92,15 @@ MarkPagesInUse(void *p, size_t size)
    return true;
}

size_t
GetPageFaultCount()
{
    PROCESS_MEMORY_COUNTERS pmc;
    if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
        return 0;
    return pmc.PageFaultCount;
}

#elif defined(XP_OS2)

#define INCL_DOSMEMMGR
@@ -216,6 +226,12 @@ MarkPagesInUse(void *p, size_t size)
    return true;
}

size_t
GetPageFaultCount()
{
    return 0;
}

#elif defined(SOLARIS)

#include <sys/mman.h>
@@ -267,10 +283,18 @@ MarkPagesInUse(void *p, size_t size)
    return true;
}

size_t
GetPageFaultCount()
{
    return 0;
}

#elif defined(XP_UNIX) || defined(XP_MACOSX) || defined(DARWIN)

#include <sys/mman.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>

void
InitMemorySubsystem()
@@ -336,6 +360,16 @@ MarkPagesInUse(void *p, size_t size)
    return true;
}

size_t
GetPageFaultCount()
{
    struct rusage usage;
    int err = getrusage(RUSAGE_SELF, &usage);
    if (err)
        return 0;
    return usage.ru_minflt + usage.ru_majflt;
}

#else
#error "Memory mapping functions are not defined for your OS."
#endif
+3 −0
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ bool MarkPagesUnused(void *p, size_t size);
// platforms.
bool MarkPagesInUse(void *p, size_t size);

// Returns #(hard faults) + #(soft faults)
size_t GetPageFaultCount();

} /* namespace gc */
} /* namespace js */

+66 −34
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include "jsutil.h"
#include "prmjtime.h"

#include "gc/Memory.h"
#include "gc/Statistics.h"

#include "gc/Barrier-inl.h"
@@ -124,7 +125,7 @@ class StatisticsSerializer
        if (needComma_)
            pJSON(", ");
        if (asJSON_ && name) {
            putQuoted(name);
            putKey(name);
            pJSON(": ");
        }
        pJSON("{");
@@ -141,7 +142,7 @@ class StatisticsSerializer
        if (needComma_)
            pJSON(", ");
        if (asJSON_)
            putQuoted(name);
            putKey(name);
        pJSON(": [");
        needComma_ = false;
    }
@@ -289,32 +290,53 @@ t(int64_t t)
    return double(t) / PRMJ_USEC_PER_MSEC;
}

struct PhaseInfo
{
    unsigned index;
    const char *name;
};

static PhaseInfo phases[] = {
    { PHASE_GC_BEGIN, "Begin Callback" },
    { PHASE_WAIT_BACKGROUND_THREAD, "Wait Background Thread" },
    { PHASE_PURGE, "Purge" },
    { PHASE_MARK, "Mark" },
    { PHASE_MARK_ROOTS, "Mark Roots" },
    { PHASE_MARK_DELAYED, "Mark Delayed" },
    { PHASE_MARK_OTHER, "Mark Other" },
    { PHASE_FINALIZE_START, "Finalize Start Callback" },
    { PHASE_SWEEP, "Sweep" },
    { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments" },
    { PHASE_SWEEP_OBJECT, "Sweep Object" },
    { PHASE_SWEEP_STRING, "Sweep String" },
    { PHASE_SWEEP_SCRIPT, "Sweep Script" },
    { PHASE_SWEEP_SHAPE, "Sweep Shape" },
    { PHASE_DISCARD_CODE, "Discard Code" },
    { PHASE_DISCARD_ANALYSIS, "Discard Analysis" },
    { PHASE_DISCARD_TI, "Discard TI" },
    { PHASE_SWEEP_TYPES, "Sweep Types" },
    { PHASE_CLEAR_SCRIPT_ANALYSIS, "Clear Script Analysis" },
    { PHASE_FINALIZE_END, "Finalize End Callback" },
    { PHASE_DESTROY, "Deallocate" },
    { PHASE_GC_END, "End Callback" },
    { 0, NULL }
};

static void
FormatPhaseTimes(StatisticsSerializer &ss, const char *name, int64_t *times)
{
    ss.beginObject(name);
    for (unsigned i = 0; phases[i].name; i++)
        ss.appendIfNonzeroMS(phases[i].name, t(times[phases[i].index]));
    ss.endObject();
}

static void
formatPhases(StatisticsSerializer &ss, const char *name, int64_t *times)
FormatPhaseFaults(StatisticsSerializer &ss, const char *name, size_t *faults)
{
    ss.beginObject(name);
    ss.appendIfNonzeroMS("Begin Callback", t(times[PHASE_GC_BEGIN]));
    ss.appendIfNonzeroMS("Wait Background Thread", t(times[PHASE_WAIT_BACKGROUND_THREAD]));
    ss.appendIfNonzeroMS("Purge", t(times[PHASE_PURGE]));
    ss.appendIfNonzeroMS("Mark", t(times[PHASE_MARK]));
    ss.appendIfNonzeroMS("Mark Roots", t(times[PHASE_MARK_ROOTS]));
    ss.appendIfNonzeroMS("Mark Delayed", t(times[PHASE_MARK_DELAYED]));
    ss.appendIfNonzeroMS("Mark Other", t(times[PHASE_MARK_OTHER]));
    ss.appendIfNonzeroMS("Finalize Start Callback", t(times[PHASE_FINALIZE_START]));
    ss.appendIfNonzeroMS("Sweep", t(times[PHASE_SWEEP]));
    ss.appendIfNonzeroMS("Sweep Compartments", t(times[PHASE_SWEEP_COMPARTMENTS]));
    ss.appendIfNonzeroMS("Sweep Object", t(times[PHASE_SWEEP_OBJECT]));
    ss.appendIfNonzeroMS("Sweep String", t(times[PHASE_SWEEP_STRING]));
    ss.appendIfNonzeroMS("Sweep Script", t(times[PHASE_SWEEP_SCRIPT]));
    ss.appendIfNonzeroMS("Sweep Shape", t(times[PHASE_SWEEP_SHAPE]));
    ss.appendIfNonzeroMS("Discard Code", t(times[PHASE_DISCARD_CODE]));
    ss.appendIfNonzeroMS("Discard Analysis", t(times[PHASE_DISCARD_ANALYSIS]));
    ss.appendIfNonzeroMS("Discard TI", t(times[PHASE_DISCARD_TI]));
    ss.appendIfNonzeroMS("Sweep Types", t(times[PHASE_SWEEP_TYPES]));
    ss.appendIfNonzeroMS("Clear Script Analysis", t(times[PHASE_CLEAR_SCRIPT_ANALYSIS]));
    ss.appendIfNonzeroMS("Finalize End Callback", t(times[PHASE_FINALIZE_END]));
    ss.appendIfNonzeroMS("Deallocate", t(times[PHASE_DESTROY]));
    ss.appendIfNonzeroMS("End Callback", t(times[PHASE_GC_END]));
    for (unsigned i = 0; phases[i].name; i++)
        ss.appendNumber(phases[i].name, "%u", "", unsigned(faults[phases[i].index]));
    ss.endObject();
}

@@ -365,21 +387,25 @@ Statistics::formatData(StatisticsSerializer &ss, uint64_t timestamp)
            ss.beginObject(NULL);
            ss.extra("    ");
            ss.appendNumber("Slice", "%d", "", i);
            ss.appendDecimal("Time", "ms", t(slices[i].end - slices[0].start));
            ss.extra(" (");
            ss.appendDecimal("Pause", "", t(width));
            ss.extra(" (");
            ss.appendDecimal("When", "ms", t(slices[i].end - slices[0].start));
            ss.appendString("Reason", ExplainReason(slices[i].reason));
            if (slices[i].resetReason)
                ss.appendString("Reset", slices[i].resetReason);
            ss.extra("): ");
            formatPhases(ss, "times", slices[i].phaseTimes);
            FormatPhaseTimes(ss, "Times", slices[i].phaseTimes);
            if (ss.isJSON())
                FormatPhaseFaults(ss, "Page Faults", slices[i].phaseFaults);
            ss.endLine();
            ss.endObject();
        }
        ss.endArray();
    }
    ss.extra("    Totals: ");
    formatPhases(ss, "totals", phaseTimes);
    FormatPhaseTimes(ss, "Totals", phaseTimes);
    if (ss.isJSON())
        FormatPhaseFaults(ss, "Total Page Faults", phaseFaults);
    ss.endObject();

    return !ss.isOOM();
@@ -439,7 +465,7 @@ Statistics::~Statistics()
    if (fp) {
        if (fullFormat) {
            StatisticsSerializer ss(StatisticsSerializer::AsText);
            formatPhases(ss, "", phaseTotals);
            FormatPhaseTimes(ss, "", phaseTotals);
            char *msg = ss.finishCString();
            if (msg) {
                fprintf(fp, "TOTALS\n%s\n\n-------\n", msg);
@@ -481,8 +507,10 @@ Statistics::printStats()
void
Statistics::beginGC()
{
    PodArrayZero(phaseStarts);
    PodArrayZero(phaseStartTimes);
    PodArrayZero(phaseStartFaults);
    PodArrayZero(phaseTimes);
    PodArrayZero(phaseFaults);

    slices.clearAndFree();
    nonincrementalReason = NULL;
@@ -570,7 +598,8 @@ Statistics::endSlice()
void
Statistics::beginPhase(Phase phase)
{
    phaseStarts[phase] = PRMJ_Now();
    phaseStartTimes[phase] = PRMJ_Now();
    phaseStartFaults[phase] = gc::GetPageFaultCount();

    if (phase == gcstats::PHASE_MARK)
        Probes::GCStartMarkPhase();
@@ -581,11 +610,14 @@ Statistics::beginPhase(Phase phase)
void
Statistics::endPhase(Phase phase)
{
    int64_t now = PRMJ_Now();
    int64_t t = now - phaseStarts[phase];
    int64_t t = PRMJ_Now() - phaseStartTimes[phase];
    slices.back().phaseTimes[phase] += t;
    phaseTimes[phase] += t;

    size_t faults = gc::GetPageFaultCount() - phaseStartFaults[phase];
    slices.back().phaseFaults[phase] += faults;
    phaseFaults[phase] += faults;

    if (phase == gcstats::PHASE_MARK)
        Probes::GCEndMarkPhase();
    else if (phase == gcstats::PHASE_SWEEP)
+5 −1
Original line number Diff line number Diff line
@@ -131,12 +131,14 @@ struct Statistics {
          : reason(reason), resetReason(NULL), start(start)
        {
            PodArrayZero(phaseTimes);
            PodArrayZero(phaseFaults);
        }

        gcreason::Reason reason;
        const char *resetReason;
        int64_t start, end;
        int64_t phaseTimes[PHASE_LIMIT];
        size_t phaseFaults[PHASE_LIMIT];

        int64_t duration() const { return end - start; }
    };
@@ -144,10 +146,12 @@ struct Statistics {
    Vector<SliceData, 8, SystemAllocPolicy> slices;

    /* Most recent time when the given phase started. */
    int64_t phaseStarts[PHASE_LIMIT];
    int64_t phaseStartTimes[PHASE_LIMIT];
    size_t phaseStartFaults[PHASE_LIMIT];

    /* Total time in a given phase for this GC. */
    int64_t phaseTimes[PHASE_LIMIT];
    size_t phaseFaults[PHASE_LIMIT];

    /* Total time in a given phase over all GCs. */
    int64_t phaseTotals[PHASE_LIMIT];