mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 881882 - OdinMonkey: report compile time and slow functions in asm.js success message (r=sstangl)
--HG-- extra : rebase_source : b72090feaf9e250e5085dcb8731edf4a1ff0daec
This commit is contained in:
parent
31025066ec
commit
4b8935fe96
@ -932,6 +932,7 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
MIRTypeVector argTypes_;
|
||||
RetType returnType_;
|
||||
mutable Label code_;
|
||||
unsigned compileTime_;
|
||||
|
||||
public:
|
||||
Func(ParseNode *fn, ParseNode *body, MoveRef<MIRTypeVector> types, RetType returnType)
|
||||
@ -939,7 +940,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
body_(body),
|
||||
argTypes_(types),
|
||||
returnType_(returnType),
|
||||
code_()
|
||||
code_(),
|
||||
compileTime_(0)
|
||||
{}
|
||||
|
||||
Func(MoveRef<Func> rhs)
|
||||
@ -947,7 +949,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
body_(rhs->body_),
|
||||
argTypes_(Move(rhs->argTypes_)),
|
||||
returnType_(rhs->returnType_),
|
||||
code_(rhs->code_)
|
||||
code_(rhs->code_),
|
||||
compileTime_(rhs->compileTime_)
|
||||
{}
|
||||
|
||||
~Func()
|
||||
@ -964,6 +967,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
const MIRTypeVector &argMIRTypes() const { return argTypes_; }
|
||||
RetType returnType() const { return returnType_; }
|
||||
Label *codeLabel() const { return &code_; }
|
||||
unsigned compileTime() const { return compileTime_; }
|
||||
void accumulateCompileTime(unsigned ms) { compileTime_ += ms; }
|
||||
};
|
||||
|
||||
class Global
|
||||
@ -1100,10 +1105,19 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
typedef HashMap<ExitDescriptor, unsigned, ExitDescriptor, ContextAllocPolicy> ExitMap;
|
||||
|
||||
private:
|
||||
struct SlowFunction
|
||||
{
|
||||
PropertyName *name;
|
||||
unsigned ms;
|
||||
unsigned line;
|
||||
unsigned column;
|
||||
};
|
||||
|
||||
typedef HashMap<PropertyName*, AsmJSMathBuiltin> MathNameMap;
|
||||
typedef HashMap<PropertyName*, Global> GlobalMap;
|
||||
typedef Vector<Func> FuncVector;
|
||||
typedef Vector<AsmJSGlobalAccess> GlobalAccessVector;
|
||||
typedef Vector<SlowFunction> SlowFunctionVector;
|
||||
|
||||
JSContext * cx_;
|
||||
MacroAssembler masm_;
|
||||
@ -1123,6 +1137,10 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
|
||||
char * errorString_;
|
||||
ParseNode * errorNode_;
|
||||
|
||||
int64_t usecBefore_;
|
||||
SlowFunctionVector slowFunctions_;
|
||||
|
||||
TokenStream & tokenStream_;
|
||||
|
||||
DebugOnly<int> currentPass_;
|
||||
@ -1147,6 +1165,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
globalAccesses_(cx),
|
||||
errorString_(NULL),
|
||||
errorNode_(NULL),
|
||||
usecBefore_(PRMJ_Now()),
|
||||
slowFunctions_(cx),
|
||||
tokenStream_(ts),
|
||||
currentPass_(1)
|
||||
{}
|
||||
@ -1156,7 +1176,7 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
tokenStream_.reportAsmJSError(errorNode_->pn_pos.begin,
|
||||
JSMSG_USE_ASM_TYPE_FAIL,
|
||||
errorString_);
|
||||
JS_smprintf_free(errorString_);
|
||||
js_free(errorString_);
|
||||
}
|
||||
|
||||
// Avoid spurious Label assertions on compilation failure.
|
||||
@ -1235,6 +1255,18 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
return false;
|
||||
}
|
||||
|
||||
static const unsigned SLOW_FUNCTION_THRESHOLD_MS = 250;
|
||||
|
||||
bool maybeReportCompileTime(ParseNode *fn, unsigned ms) {
|
||||
if (ms < SLOW_FUNCTION_THRESHOLD_MS)
|
||||
return true;
|
||||
SlowFunction sf;
|
||||
sf.name = FunctionName(fn);
|
||||
sf.ms = ms;
|
||||
tokenStream_.srcCoords.lineNumAndColumnIndex(fn->pn_pos.begin, &sf.line, &sf.column);
|
||||
return slowFunctions_.append(sf);
|
||||
}
|
||||
|
||||
/*************************************************** Read-only interface */
|
||||
|
||||
JSContext *cx() const { return cx_; }
|
||||
@ -1456,6 +1488,31 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
module_->exportedFunction(exportIndex).initCodeOffset(masm_.size());
|
||||
}
|
||||
|
||||
void buildCompilationTimeReport(ScopedJSFreePtr<char> *out) {
|
||||
int64_t usecAfter = PRMJ_Now();
|
||||
int msTotal = (usecAfter - usecBefore_) / PRMJ_USEC_PER_MSEC;
|
||||
ScopedJSFreePtr<char> slowFuns;
|
||||
if (!slowFunctions_.empty()) {
|
||||
slowFuns.reset(JS_smprintf("; %d functions compiled slowly: ", slowFunctions_.length()));
|
||||
if (!slowFuns)
|
||||
return;
|
||||
for (unsigned i = 0; i < slowFunctions_.length(); i++) {
|
||||
SlowFunction &func = slowFunctions_[i];
|
||||
JSAutoByteString name;
|
||||
if (!js_AtomToPrintableString(cx_, func.name, &name))
|
||||
return;
|
||||
slowFuns.reset(JS_smprintf("%s%s:%u:%u (%ums, %g%%)%s", slowFuns.get(),
|
||||
name.ptr(), func.line, func.column, func.ms,
|
||||
double(func.ms)/double(msTotal),
|
||||
i+1 < slowFunctions_.length() ? ", " : ""));
|
||||
if (!slowFuns)
|
||||
return;
|
||||
}
|
||||
}
|
||||
out->reset(JS_smprintf("total compilation time %dms%s",
|
||||
msTotal, slowFuns ? slowFuns.get() : ""));
|
||||
}
|
||||
|
||||
bool finish(ScopedJSDeletePtr<AsmJSModule> *module) {
|
||||
// After finishing, the only valid operation on an ModuleCompiler is
|
||||
// destruction.
|
||||
@ -4633,6 +4690,8 @@ CheckVariableDecls(ModuleCompiler &m, FunctionCompiler::LocalMap *locals, ParseN
|
||||
static MIRGenerator *
|
||||
CheckFunctionBody(ModuleCompiler &m, ModuleCompiler::Func &func, LifoAlloc &lifo)
|
||||
{
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
// CheckFunctionSignature already has already checked the
|
||||
// function head as well as argument type declarations. The ParseNode*
|
||||
// stored in f.body points to the first non-argument statement.
|
||||
@ -4675,6 +4734,8 @@ CheckFunctionBody(ModuleCompiler &m, ModuleCompiler::Func &func, LifoAlloc &lifo
|
||||
f.returnVoid();
|
||||
JS_ASSERT(!tempAlloc->rootList());
|
||||
|
||||
func.accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC);
|
||||
|
||||
return mirGen;
|
||||
}
|
||||
|
||||
@ -4682,6 +4743,8 @@ static bool
|
||||
GenerateAsmJSCode(ModuleCompiler &m, ModuleCompiler::Func &func,
|
||||
MIRGenerator &mirGen, LIRGraph &lir)
|
||||
{
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
m.masm().bind(func.codeLabel());
|
||||
|
||||
ScopedJSDeletePtr<CodeGenerator> codegen(GenerateCode(&mirGen, &lir, &m.masm()));
|
||||
@ -4714,6 +4777,10 @@ GenerateAsmJSCode(ModuleCompiler &m, ModuleCompiler::Func &func,
|
||||
// Align internal function headers.
|
||||
m.masm().align(CodeAlignment);
|
||||
|
||||
func.accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC);
|
||||
if (!m.maybeReportCompileTime(func.fn(), func.compileTime()))
|
||||
return false;
|
||||
|
||||
// Unlike regular IonMonkey which links and generates a new IonCode for
|
||||
// every function, we accumulate all the functions in the module in a
|
||||
// single MacroAssembler and link at end. Linking asm.js doesn't require a
|
||||
@ -4743,6 +4810,8 @@ CheckFunctionBodiesSequential(ModuleCompiler &m)
|
||||
|
||||
IonContext icx(m.cx()->compartment(), &mirGen->temp());
|
||||
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
if (!OptimizeMIR(mirGen))
|
||||
return m.fail(func.fn(), "internal compiler failure (probably out of memory)");
|
||||
|
||||
@ -4750,6 +4819,8 @@ CheckFunctionBodiesSequential(ModuleCompiler &m)
|
||||
if (!lir)
|
||||
return m.fail(func.fn(), "internal compiler failure (probably out of memory)");
|
||||
|
||||
func.accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC);
|
||||
|
||||
if (!GenerateAsmJSCode(m, func, *mirGen, *lir))
|
||||
return false;
|
||||
|
||||
@ -4798,8 +4869,12 @@ GenerateCodeForFinishedJob(ModuleCompiler &m, ParallelGroupState &group, AsmJSPa
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
ModuleCompiler::Func &func = m.function(task->funcNum);
|
||||
|
||||
func.accumulateCompileTime(task->compileTime);
|
||||
|
||||
// Perform code generation on the main thread.
|
||||
if (!GenerateAsmJSCode(m, m.function(task->funcNum), *task->mir, *task->lir))
|
||||
if (!GenerateAsmJSCode(m, func, *task->mir, *task->lir))
|
||||
return false;
|
||||
group.compiledJobs++;
|
||||
|
||||
@ -5996,7 +6071,8 @@ GenerateExits(ModuleCompiler &m)
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckModule(JSContext *cx, TokenStream &ts, ParseNode *fn, ScopedJSDeletePtr<AsmJSModule> *module)
|
||||
CheckModule(JSContext *cx, TokenStream &ts, ParseNode *fn, ScopedJSDeletePtr<AsmJSModule> *module,
|
||||
ScopedJSFreePtr<char> *compilationTimeReport)
|
||||
{
|
||||
ModuleCompiler m(cx, ts);
|
||||
if (!m.init())
|
||||
@ -6057,11 +6133,15 @@ CheckModule(JSContext *cx, TokenStream &ts, ParseNode *fn, ScopedJSDeletePtr<Asm
|
||||
if (!GenerateExits(m))
|
||||
return false;
|
||||
|
||||
return m.finish(module);
|
||||
if (!m.finish(module))
|
||||
return false;
|
||||
|
||||
m.buildCompilationTimeReport(compilationTimeReport);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
Warn(JSContext *cx, int code, const char *str = NULL)
|
||||
Warn(JSContext *cx, int code, const char *str)
|
||||
{
|
||||
return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage,
|
||||
NULL, code, str);
|
||||
@ -6094,8 +6174,9 @@ js::CompileAsmJS(JSContext *cx, TokenStream &ts, ParseNode *fn, const CompileOpt
|
||||
}
|
||||
# endif
|
||||
|
||||
ScopedJSFreePtr<char> compilationTimeReport;
|
||||
ScopedJSDeletePtr<AsmJSModule> module;
|
||||
if (!CheckModule(cx, ts, fn, &module))
|
||||
if (!CheckModule(cx, ts, fn, &module, &compilationTimeReport))
|
||||
return !cx->isExceptionPending();
|
||||
|
||||
module->initPostLinkFailureInfo(options, scriptSource, bufStart, bufEnd);
|
||||
@ -6118,7 +6199,7 @@ js::CompileAsmJS(JSContext *cx, TokenStream &ts, ParseNode *fn, const CompileOpt
|
||||
|
||||
SetAsmJSModuleObject(moduleFun, moduleObj);
|
||||
|
||||
return Warn(cx, JSMSG_USE_ASM_TYPE_OK);
|
||||
return Warn(cx, JSMSG_USE_ASM_TYPE_OK, compilationTimeReport);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -139,10 +139,11 @@ struct AsmJSParallelTask
|
||||
uint32_t funcNum; // Index |i| of function in |Module.function(i)|.
|
||||
ion::MIRGenerator *mir; // Passed from main thread to worker.
|
||||
ion::LIRGraph *lir; // Passed from worker to main thread.
|
||||
unsigned compileTime;
|
||||
|
||||
AsmJSParallelTask(size_t defaultChunkSize)
|
||||
: lifo(defaultChunkSize),
|
||||
funcNum(0), mir(NULL), lir(NULL)
|
||||
funcNum(0), mir(NULL), lir(NULL), compileTime(0)
|
||||
{ }
|
||||
|
||||
void init(uint32_t newFuncNum, ion::MIRGenerator *newMir) {
|
||||
|
@ -394,7 +394,7 @@ MSG_DEF(JSMSG_CURLY_AFTER_MODULE, 340, 0, JSEXN_SYNTAXERR, "missing } after
|
||||
MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 341, 0, JSEXN_SYNTAXERR, "'use asm' directive only works on function code")
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_FAIL, 342, 1, JSEXN_TYPEERR, "asm.js type error: {0}")
|
||||
MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 343, 1, JSEXN_TYPEERR, "asm.js link error: {0}")
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 344, 0, JSEXN_ERR, "successfully compiled asm.js code")
|
||||
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 344, 1, JSEXN_ERR, "successfully compiled asm.js code ({0})")
|
||||
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 345, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
|
||||
MSG_DEF(JSMSG_YIELD_IN_ARROW, 346, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
|
||||
MSG_DEF(JSMSG_WRONG_VALUE, 347, 2, JSEXN_ERR, "expected {0} but found {1}")
|
||||
|
@ -346,6 +346,8 @@ WorkerThread::handleAsmJSWorkload(WorkerThreadState &state)
|
||||
do {
|
||||
ion::IonContext icx(asmData->mir->compartment, &asmData->mir->temp());
|
||||
|
||||
int64_t before = PRMJ_Now();
|
||||
|
||||
if (!OptimizeMIR(asmData->mir))
|
||||
break;
|
||||
|
||||
@ -353,6 +355,9 @@ WorkerThread::handleAsmJSWorkload(WorkerThreadState &state)
|
||||
if (!asmData->lir)
|
||||
break;
|
||||
|
||||
int64_t after = PRMJ_Now();
|
||||
asmData->compileTime = (after - before) / PRMJ_USEC_PER_MSEC;
|
||||
|
||||
success = true;
|
||||
} while(0);
|
||||
state.lock();
|
||||
|
Loading…
Reference in New Issue
Block a user