зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1204554 part 3.0 - Collect lcov output on the JSCompartment, and on the JSRuntime. r=terrence,bhackett
This commit is contained in:
Родитель
848c5c4b1c
Коммит
b85acbc481
|
@ -80,7 +80,8 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
|
|||
maybeAlive(true),
|
||||
jitCompartment_(nullptr),
|
||||
mappedArgumentsTemplate_(nullptr),
|
||||
unmappedArgumentsTemplate_(nullptr)
|
||||
unmappedArgumentsTemplate_(nullptr),
|
||||
lcovOutput()
|
||||
{
|
||||
PodArrayZero(sawDeprecatedLanguageExtension);
|
||||
runtime_->numCompartments++;
|
||||
|
@ -91,6 +92,11 @@ JSCompartment::~JSCompartment()
|
|||
{
|
||||
reportTelemetry();
|
||||
|
||||
// Write the code coverage information in a file.
|
||||
JSRuntime* rt = runtimeFromMainThread();
|
||||
if (rt->lcovOutput.isEnabled())
|
||||
rt->lcovOutput.writeLCovResult(lcovOutput);
|
||||
|
||||
js_delete(jitCompartment_);
|
||||
js_delete(watchpointMap);
|
||||
js_delete(scriptCountsMap);
|
||||
|
|
|
@ -662,7 +662,8 @@ struct JSCompartment
|
|||
// Debugger API, or for the entire runtime.
|
||||
bool collectCoverage() const {
|
||||
return debuggerObservesCoverage() ||
|
||||
runtimeFromAnyThread()->profilingScripts;
|
||||
runtimeFromAnyThread()->profilingScripts ||
|
||||
runtimeFromAnyThread()->lcovOutput.isEnabled();
|
||||
}
|
||||
void clearScriptCounts();
|
||||
|
||||
|
@ -746,6 +747,11 @@ struct JSCompartment
|
|||
|
||||
public:
|
||||
void addTelemetry(const char* filename, DeprecatedLanguageExtension e);
|
||||
|
||||
public:
|
||||
// Aggregated output used to collect JSScript hit counts when code coverage
|
||||
// is enabled.
|
||||
js::coverage::LCovCompartment lcovOutput;
|
||||
};
|
||||
|
||||
inline bool
|
||||
|
|
|
@ -2936,6 +2936,11 @@ JSScript::finalize(FreeOp* fop)
|
|||
// JSScript::Create(), but not yet finished initializing it with
|
||||
// fullyInitFromEmitter() or fullyInitTrivial().
|
||||
|
||||
// Collect code coverage information for this script and all its inner
|
||||
// scripts, and store the aggregated information on the compartment.
|
||||
if (isTopLevel() && fop->runtime()->lcovOutput.isEnabled())
|
||||
compartment()->lcovOutput.collectCodeCoverageInfo(compartment(), this);
|
||||
|
||||
fop->runtime()->spsProfiler.onScriptFinalized(this);
|
||||
|
||||
if (types_)
|
||||
|
|
|
@ -6,13 +6,23 @@
|
|||
|
||||
#include "vm/CodeCoverage.h"
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#if defined(XP_WIN)
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "jscompartment.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsprf.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/Time.h"
|
||||
|
||||
// This file contains a few functions which are used to produce files understood
|
||||
// by lcov tools. A detailed description of the format is available in the man
|
||||
|
@ -360,6 +370,68 @@ LCovCompartment::writeCompartmentName(JSCompartment* comp)
|
|||
return !outTN_.hadOutOfMemory();
|
||||
}
|
||||
|
||||
LCovRuntime::LCovRuntime()
|
||||
: out_(),
|
||||
#if defined(XP_WIN)
|
||||
pid_(GetCurrentProcessId())
|
||||
#else
|
||||
pid_(getpid())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
LCovRuntime::~LCovRuntime()
|
||||
{
|
||||
if (out_.isInitialized())
|
||||
out_.finish();
|
||||
}
|
||||
|
||||
void
|
||||
LCovRuntime::init()
|
||||
{
|
||||
const char* outDir = getenv("JS_CODE_COVERAGE_OUTPUT_DIR");
|
||||
if (!outDir || *outDir == 0)
|
||||
return;
|
||||
|
||||
int64_t timestamp = static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_SEC;
|
||||
static mozilla::Atomic<size_t> globalRuntimeId(0);
|
||||
size_t rid = globalRuntimeId++;
|
||||
|
||||
char name[1024];
|
||||
size_t len = JS_snprintf(name, sizeof(name), "%s/%" PRId64 "-%d-%d.info",
|
||||
outDir, timestamp, size_t(pid_), rid);
|
||||
if (sizeof(name) < len) {
|
||||
fprintf(stderr, "Warning: LCovRuntime::init: Cannot serialize file name.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we cannot open the file, report a warning.
|
||||
if (!out_.init(name))
|
||||
fprintf(stderr, "Warning: LCovRuntime::init: Cannot open file named '%s'.", name);
|
||||
}
|
||||
|
||||
void
|
||||
LCovRuntime::writeLCovResult(LCovCompartment& comp)
|
||||
{
|
||||
if (!out_.isInitialized())
|
||||
return;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
size_t p = GetCurrentProcessId();
|
||||
#else
|
||||
size_t p = getpid();
|
||||
#endif
|
||||
if (pid_ != p) {
|
||||
pid_ = p;
|
||||
out_.finish();
|
||||
init();
|
||||
if (!out_.isInitialized())
|
||||
return;
|
||||
}
|
||||
|
||||
comp.exportInto(out_);
|
||||
out_.flush();
|
||||
}
|
||||
|
||||
} // namespace coverage
|
||||
} // namespace js
|
||||
|
|
|
@ -101,6 +101,43 @@ class LCovCompartment
|
|||
LCovSourceVector* sources_;
|
||||
};
|
||||
|
||||
class LCovRuntime
|
||||
{
|
||||
public:
|
||||
LCovRuntime();
|
||||
~LCovRuntime();
|
||||
|
||||
// If the environment variable JS_CODE_COVERAGE_OUTPUT_DIR is set to a
|
||||
// directory, create a file inside this directory which uses the process
|
||||
// ID, the thread ID and a timestamp to ensure the uniqueness of the
|
||||
// file.
|
||||
//
|
||||
// At the end of the execution, this file should contains the LCOV output of
|
||||
// all the scripts executed in the current JSRuntime.
|
||||
void init();
|
||||
|
||||
// Check if we should collect code coverage information.
|
||||
bool isEnabled() const { return out_.isInitialized(); }
|
||||
|
||||
// Write the aggregated result of the code coverage of a compartment
|
||||
// into a file.
|
||||
void writeLCovResult(LCovCompartment& comp);
|
||||
|
||||
private:
|
||||
// When a process forks, the file will remain open, but 2 processes will
|
||||
// have the same file. To avoid conflicting writes, we open a new file for
|
||||
// the child process.
|
||||
void maybeReopenAfterFork();
|
||||
|
||||
private:
|
||||
// Output file which is created if code coverage is enabled.
|
||||
Fprinter out_;
|
||||
|
||||
// The process' PID is used to watch for fork. When the process fork,
|
||||
// we want to close the current file and open a new one.
|
||||
size_t pid_;
|
||||
};
|
||||
|
||||
} // namespace coverage
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ class Fprinter final : public GenericPrinter
|
|||
// Initialize this printer, returns false on error.
|
||||
bool init(const char* path);
|
||||
void init(FILE* fp);
|
||||
bool isInitialized() {
|
||||
bool isInitialized() const {
|
||||
return file_ != nullptr;
|
||||
}
|
||||
void flush();
|
||||
|
|
|
@ -176,6 +176,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
simulator_(nullptr),
|
||||
#endif
|
||||
scriptAndCountsVector(nullptr),
|
||||
lcovOutput(),
|
||||
NaNValue(DoubleNaNValue()),
|
||||
negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
|
||||
positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
|
||||
|
@ -242,6 +243,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
|
||||
PodArrayZero(nativeStackQuota);
|
||||
PodZero(&asmJSCacheOps);
|
||||
lcovOutput.init();
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#endif
|
||||
#include "js/TraceableVector.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/CodeCoverage.h"
|
||||
#include "vm/CommonPropertyNames.h"
|
||||
#include "vm/DateTime.h"
|
||||
#include "vm/MallocProvider.h"
|
||||
|
@ -1056,6 +1057,9 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
/* Strong references on scripts held for PCCount profiling API. */
|
||||
JS::PersistentRooted<js::ScriptAndCountsVector>* scriptAndCountsVector;
|
||||
|
||||
/* Code coverage output. */
|
||||
js::coverage::LCovRuntime lcovOutput;
|
||||
|
||||
/* Well-known numbers held for use by this runtime's contexts. */
|
||||
const js::Value NaNValue;
|
||||
const js::Value negativeInfinityValue;
|
||||
|
|
Загрузка…
Ссылка в новой задаче