mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 741652 - On Linux, make JS_StartProfiling start the |perf| profiler. r=sfink
This commit is contained in:
parent
2219301d4a
commit
4534006f67
@ -79,6 +79,7 @@
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
#include "jsautooplen.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "sharkctl.h"
|
||||
@ -86,6 +87,7 @@
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
using namespace mozilla;
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_GetDebugMode(JSContext *cx)
|
||||
@ -1114,6 +1116,10 @@ JS_StartProfiling(const char *profileName)
|
||||
#ifdef MOZ_VTUNE
|
||||
if (!js_StartVtune(profileName))
|
||||
ok = JS_FALSE;
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
if (!js_StartPerf())
|
||||
ok = JS_FALSE;
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
@ -1128,6 +1134,10 @@ JS_StopProfiling(const char *profileName)
|
||||
#ifdef MOZ_VTUNE
|
||||
if (!js_StopVtune())
|
||||
ok = JS_FALSE;
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
if (!js_StopPerf())
|
||||
ok = JS_FALSE;
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
@ -1581,6 +1591,140 @@ js_ResumeVtune()
|
||||
|
||||
#endif /* MOZ_VTUNE */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
/*
|
||||
* Code for starting and stopping |perf|, the Linux profiler.
|
||||
*
|
||||
* Output from profiling is written to mozperf.data in your cwd.
|
||||
*
|
||||
* To enable, set MOZ_PROFILE_WITH_PERF=1 in your environment.
|
||||
*
|
||||
* To pass additional parameters to |perf record|, provide them in the
|
||||
* MOZ_PROFILE_PERF_FLAGS environment variable. If this variable does not
|
||||
* exist, we default it to "--call-graph". (If you don't want --call-graph but
|
||||
* don't want to pass any other args, define MOZ_PROFILE_PERF_FLAGS to the empty
|
||||
* string.)
|
||||
*
|
||||
* If you include --pid or --output in MOZ_PROFILE_PERF_FLAGS, you're just
|
||||
* asking for trouble.
|
||||
*
|
||||
* Our split-on-spaces logic is lame, so don't expect MOZ_PROFILE_PERF_FLAGS to
|
||||
* work if you pass an argument which includes a space (e.g.
|
||||
* MOZ_PROFILE_PERF_FLAGS="-e 'foo bar'").
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
static bool perfInitialized = false;
|
||||
static pid_t perfPid = 0;
|
||||
|
||||
JSBool js_StartPerf()
|
||||
{
|
||||
const char *outfile = "mozperf.data";
|
||||
|
||||
if (perfPid != 0) {
|
||||
UnsafeError("js_StartPerf: called while perf was already running!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bail if MOZ_PROFILE_WITH_PERF is empty or undefined.
|
||||
if (!getenv("MOZ_PROFILE_WITH_PERF") ||
|
||||
!strlen(getenv("MOZ_PROFILE_WITH_PERF"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete mozperf.data the first time through -- we're going to append to it
|
||||
* later on, so we want it to be clean when we start out.
|
||||
*/
|
||||
if (!perfInitialized) {
|
||||
perfInitialized = true;
|
||||
unlink(outfile);
|
||||
char cwd[4096];
|
||||
printf("Writing perf profiling data to %s/%s\n",
|
||||
getcwd(cwd, sizeof(cwd)), outfile);
|
||||
}
|
||||
|
||||
pid_t mainPid = getpid();
|
||||
|
||||
pid_t childPid = fork();
|
||||
if (childPid == 0) {
|
||||
/* perf record --append --pid $mainPID --output=$outfile $MOZ_PROFILE_PERF_FLAGS */
|
||||
|
||||
char mainPidStr[16];
|
||||
snprintf(mainPidStr, sizeof(mainPidStr), "%d", mainPid);
|
||||
const char *defaultArgs[] = {"perf", "record", "--append",
|
||||
"--pid", mainPidStr, "--output", outfile};
|
||||
|
||||
Vector<const char*, 0, SystemAllocPolicy> args;
|
||||
args.append(defaultArgs, ArrayLength(defaultArgs));
|
||||
|
||||
const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
|
||||
if (!flags) {
|
||||
flags = "--call-graph";
|
||||
}
|
||||
|
||||
// Split |flags| on spaces. (Don't bother to free it -- we're going to
|
||||
// exec anyway.)
|
||||
char *toksave;
|
||||
char *tok = strtok_r(strdup(flags), " ", &toksave);
|
||||
while (tok) {
|
||||
args.append(tok);
|
||||
tok = strtok_r(NULL, " ", &toksave);
|
||||
}
|
||||
|
||||
args.append((char*) NULL);
|
||||
|
||||
execvp("perf", const_cast<char**>(args.begin()));
|
||||
|
||||
/* Reached only if execlp fails. */
|
||||
fprintf(stderr, "Unable to start perf.\n");
|
||||
exit(1);
|
||||
}
|
||||
else if (childPid > 0) {
|
||||
perfPid = childPid;
|
||||
|
||||
/* Give perf a chance to warm up. */
|
||||
usleep(500 * 1000);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
UnsafeError("js_StartPerf: fork() failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JSBool js_StopPerf()
|
||||
{
|
||||
if (perfPid == 0) {
|
||||
UnsafeError("js_StopPerf: perf is not running.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (kill(perfPid, SIGINT)) {
|
||||
UnsafeError("js_StopPerf: kill failed\n");
|
||||
|
||||
// Try to reap the process anyway.
|
||||
waitpid(perfPid, NULL, WNOHANG);
|
||||
}
|
||||
else {
|
||||
waitpid(perfPid, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If kill() failed, assume it failed because perf died early and continue
|
||||
* on as though perf had been successfully killed.
|
||||
*/
|
||||
perfPid = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DumpBytecode(JSContext *cx, JSScript *script)
|
||||
{
|
||||
|
@ -532,6 +532,16 @@ js_ResumeVtune();
|
||||
|
||||
#endif /* MOZ_VTUNE */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_StartPerf();
|
||||
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_StopPerf();
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_DumpBytecode(JSContext *cx, JSScript *script);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user