js/src/builtin/Profilers.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* Profiling-related API */
michael@0 8
michael@0 9 #include "builtin/Profilers.h"
michael@0 10
michael@0 11 #include <stdarg.h>
michael@0 12
michael@0 13 #ifdef MOZ_CALLGRIND
michael@0 14 # include <valgrind/callgrind.h>
michael@0 15 #endif
michael@0 16
michael@0 17 #ifdef __APPLE__
michael@0 18 #ifdef MOZ_INSTRUMENTS
michael@0 19 # include "devtools/Instruments.h"
michael@0 20 #endif
michael@0 21 #ifdef MOZ_SHARK
michael@0 22 # include "devtools/sharkctl.h"
michael@0 23 #endif
michael@0 24 #endif
michael@0 25
michael@0 26 #ifdef XP_WIN
michael@0 27 # include <process.h>
michael@0 28 # define getpid _getpid
michael@0 29 #endif
michael@0 30
michael@0 31 #include "vm/Probes.h"
michael@0 32
michael@0 33 #include "jscntxtinlines.h"
michael@0 34
michael@0 35 using namespace js;
michael@0 36
michael@0 37 using mozilla::ArrayLength;
michael@0 38
michael@0 39 /* Thread-unsafe error management */
michael@0 40
michael@0 41 static char gLastError[2000];
michael@0 42
michael@0 43 static void
michael@0 44 #ifdef __GNUC__
michael@0 45 __attribute__((unused,format(printf,1,2)))
michael@0 46 #endif
michael@0 47 UnsafeError(const char *format, ...)
michael@0 48 {
michael@0 49 va_list args;
michael@0 50 va_start(args, format);
michael@0 51 (void) vsnprintf(gLastError, sizeof(gLastError), format, args);
michael@0 52 va_end(args);
michael@0 53
michael@0 54 gLastError[sizeof(gLastError) - 1] = '\0';
michael@0 55 }
michael@0 56
michael@0 57 JS_PUBLIC_API(const char *)
michael@0 58 JS_UnsafeGetLastProfilingError()
michael@0 59 {
michael@0 60 return gLastError;
michael@0 61 }
michael@0 62
michael@0 63 #ifdef __APPLE__
michael@0 64 static bool
michael@0 65 StartOSXProfiling(const char *profileName, pid_t pid)
michael@0 66 {
michael@0 67 bool ok = true;
michael@0 68 const char* profiler = nullptr;
michael@0 69 #ifdef MOZ_SHARK
michael@0 70 ok = Shark::Start();
michael@0 71 profiler = "Shark";
michael@0 72 #endif
michael@0 73 #ifdef MOZ_INSTRUMENTS
michael@0 74 ok = Instruments::Start(pid);
michael@0 75 profiler = "Instruments";
michael@0 76 #endif
michael@0 77 if (!ok) {
michael@0 78 if (profileName)
michael@0 79 UnsafeError("Failed to start %s for %s", profiler, profileName);
michael@0 80 else
michael@0 81 UnsafeError("Failed to start %s", profiler);
michael@0 82 return false;
michael@0 83 }
michael@0 84 return true;
michael@0 85 }
michael@0 86 #endif
michael@0 87
michael@0 88 JS_PUBLIC_API(bool)
michael@0 89 JS_StartProfiling(const char *profileName, pid_t pid)
michael@0 90 {
michael@0 91 bool ok = true;
michael@0 92 #ifdef __APPLE__
michael@0 93 ok = StartOSXProfiling(profileName, pid);
michael@0 94 #endif
michael@0 95 #ifdef __linux__
michael@0 96 if (!js_StartPerf())
michael@0 97 ok = false;
michael@0 98 #endif
michael@0 99 return ok;
michael@0 100 }
michael@0 101
michael@0 102 JS_PUBLIC_API(bool)
michael@0 103 JS_StopProfiling(const char *profileName)
michael@0 104 {
michael@0 105 bool ok = true;
michael@0 106 #ifdef __APPLE__
michael@0 107 #ifdef MOZ_SHARK
michael@0 108 Shark::Stop();
michael@0 109 #endif
michael@0 110 #ifdef MOZ_INSTRUMENTS
michael@0 111 Instruments::Stop(profileName);
michael@0 112 #endif
michael@0 113 #endif
michael@0 114 #ifdef __linux__
michael@0 115 if (!js_StopPerf())
michael@0 116 ok = false;
michael@0 117 #endif
michael@0 118 return ok;
michael@0 119 }
michael@0 120
michael@0 121 /*
michael@0 122 * Start or stop whatever platform- and configuration-specific profiling
michael@0 123 * backends are available.
michael@0 124 */
michael@0 125 static bool
michael@0 126 ControlProfilers(bool toState)
michael@0 127 {
michael@0 128 bool ok = true;
michael@0 129
michael@0 130 if (! probes::ProfilingActive && toState) {
michael@0 131 #ifdef __APPLE__
michael@0 132 #if defined(MOZ_SHARK) || defined(MOZ_INSTRUMENTS)
michael@0 133 const char* profiler;
michael@0 134 #ifdef MOZ_SHARK
michael@0 135 ok = Shark::Start();
michael@0 136 profiler = "Shark";
michael@0 137 #endif
michael@0 138 #ifdef MOZ_INSTRUMENTS
michael@0 139 ok = Instruments::Resume();
michael@0 140 profiler = "Instruments";
michael@0 141 #endif
michael@0 142 if (!ok) {
michael@0 143 UnsafeError("Failed to start %s", profiler);
michael@0 144 }
michael@0 145 #endif
michael@0 146 #endif
michael@0 147 #ifdef MOZ_CALLGRIND
michael@0 148 if (! js_StartCallgrind()) {
michael@0 149 UnsafeError("Failed to start Callgrind");
michael@0 150 ok = false;
michael@0 151 }
michael@0 152 #endif
michael@0 153 } else if (probes::ProfilingActive && ! toState) {
michael@0 154 #ifdef __APPLE__
michael@0 155 #ifdef MOZ_SHARK
michael@0 156 Shark::Stop();
michael@0 157 #endif
michael@0 158 #ifdef MOZ_INSTRUMENTS
michael@0 159 Instruments::Pause();
michael@0 160 #endif
michael@0 161 #endif
michael@0 162 #ifdef MOZ_CALLGRIND
michael@0 163 if (! js_StopCallgrind()) {
michael@0 164 UnsafeError("failed to stop Callgrind");
michael@0 165 ok = false;
michael@0 166 }
michael@0 167 #endif
michael@0 168 }
michael@0 169
michael@0 170 probes::ProfilingActive = toState;
michael@0 171
michael@0 172 return ok;
michael@0 173 }
michael@0 174
michael@0 175 /*
michael@0 176 * Pause/resume whatever profiling mechanism is currently compiled
michael@0 177 * in, if applicable. This will not affect things like dtrace.
michael@0 178 *
michael@0 179 * Do not mix calls to these APIs with calls to the individual
michael@0 180 * profilers' pause/resume functions, because only overall state is
michael@0 181 * tracked, not the state of each profiler.
michael@0 182 */
michael@0 183 JS_PUBLIC_API(bool)
michael@0 184 JS_PauseProfilers(const char *profileName)
michael@0 185 {
michael@0 186 return ControlProfilers(false);
michael@0 187 }
michael@0 188
michael@0 189 JS_PUBLIC_API(bool)
michael@0 190 JS_ResumeProfilers(const char *profileName)
michael@0 191 {
michael@0 192 return ControlProfilers(true);
michael@0 193 }
michael@0 194
michael@0 195 JS_PUBLIC_API(bool)
michael@0 196 JS_DumpProfile(const char *outfile, const char *profileName)
michael@0 197 {
michael@0 198 bool ok = true;
michael@0 199 #ifdef MOZ_CALLGRIND
michael@0 200 js_DumpCallgrind(outfile);
michael@0 201 #endif
michael@0 202 return ok;
michael@0 203 }
michael@0 204
michael@0 205 #ifdef MOZ_PROFILING
michael@0 206
michael@0 207 struct RequiredStringArg {
michael@0 208 JSContext *mCx;
michael@0 209 char *mBytes;
michael@0 210 RequiredStringArg(JSContext *cx, const CallArgs &args, size_t argi, const char *caller)
michael@0 211 : mCx(cx), mBytes(nullptr)
michael@0 212 {
michael@0 213 if (args.length() <= argi) {
michael@0 214 JS_ReportError(cx, "%s: not enough arguments", caller);
michael@0 215 } else if (!args[argi].isString()) {
michael@0 216 JS_ReportError(cx, "%s: invalid arguments (string expected)", caller);
michael@0 217 } else {
michael@0 218 mBytes = JS_EncodeString(cx, args[argi].toString());
michael@0 219 }
michael@0 220 }
michael@0 221 operator void*() {
michael@0 222 return (void*) mBytes;
michael@0 223 }
michael@0 224 ~RequiredStringArg() {
michael@0 225 js_free(mBytes);
michael@0 226 }
michael@0 227 };
michael@0 228
michael@0 229 static bool
michael@0 230 StartProfiling(JSContext *cx, unsigned argc, jsval *vp)
michael@0 231 {
michael@0 232 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 233 if (args.length() == 0) {
michael@0 234 args.rval().setBoolean(JS_StartProfiling(nullptr, getpid()));
michael@0 235 return true;
michael@0 236 }
michael@0 237
michael@0 238 RequiredStringArg profileName(cx, args, 0, "startProfiling");
michael@0 239 if (!profileName)
michael@0 240 return false;
michael@0 241
michael@0 242 if (args.length() == 1) {
michael@0 243 args.rval().setBoolean(JS_StartProfiling(profileName.mBytes, getpid()));
michael@0 244 return true;
michael@0 245 }
michael@0 246
michael@0 247 if (!args[1].isInt32()) {
michael@0 248 JS_ReportError(cx, "startProfiling: invalid arguments (int expected)");
michael@0 249 return false;
michael@0 250 }
michael@0 251 pid_t pid = static_cast<pid_t>(args[1].toInt32());
michael@0 252 args.rval().setBoolean(JS_StartProfiling(profileName.mBytes, pid));
michael@0 253 return true;
michael@0 254 }
michael@0 255
michael@0 256 static bool
michael@0 257 StopProfiling(JSContext *cx, unsigned argc, jsval *vp)
michael@0 258 {
michael@0 259 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 260 if (args.length() == 0) {
michael@0 261 args.rval().setBoolean(JS_StopProfiling(nullptr));
michael@0 262 return true;
michael@0 263 }
michael@0 264
michael@0 265 RequiredStringArg profileName(cx, args, 0, "stopProfiling");
michael@0 266 if (!profileName)
michael@0 267 return false;
michael@0 268 args.rval().setBoolean(JS_StopProfiling(profileName.mBytes));
michael@0 269 return true;
michael@0 270 }
michael@0 271
michael@0 272 static bool
michael@0 273 PauseProfilers(JSContext *cx, unsigned argc, jsval *vp)
michael@0 274 {
michael@0 275 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 276 if (args.length() == 0) {
michael@0 277 args.rval().setBoolean(JS_PauseProfilers(nullptr));
michael@0 278 return true;
michael@0 279 }
michael@0 280
michael@0 281 RequiredStringArg profileName(cx, args, 0, "pauseProfiling");
michael@0 282 if (!profileName)
michael@0 283 return false;
michael@0 284 args.rval().setBoolean(JS_PauseProfilers(profileName.mBytes));
michael@0 285 return true;
michael@0 286 }
michael@0 287
michael@0 288 static bool
michael@0 289 ResumeProfilers(JSContext *cx, unsigned argc, jsval *vp)
michael@0 290 {
michael@0 291 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 292 if (args.length() == 0) {
michael@0 293 args.rval().setBoolean(JS_ResumeProfilers(nullptr));
michael@0 294 return true;
michael@0 295 }
michael@0 296
michael@0 297 RequiredStringArg profileName(cx, args, 0, "resumeProfiling");
michael@0 298 if (!profileName)
michael@0 299 return false;
michael@0 300 args.rval().setBoolean(JS_ResumeProfilers(profileName.mBytes));
michael@0 301 return true;
michael@0 302 }
michael@0 303
michael@0 304 /* Usage: DumpProfile([filename[, profileName]]) */
michael@0 305 static bool
michael@0 306 DumpProfile(JSContext *cx, unsigned argc, jsval *vp)
michael@0 307 {
michael@0 308 bool ret;
michael@0 309 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 310 if (args.length() == 0) {
michael@0 311 ret = JS_DumpProfile(nullptr, nullptr);
michael@0 312 } else {
michael@0 313 RequiredStringArg filename(cx, args, 0, "dumpProfile");
michael@0 314 if (!filename)
michael@0 315 return false;
michael@0 316
michael@0 317 if (args.length() == 1) {
michael@0 318 ret = JS_DumpProfile(filename.mBytes, nullptr);
michael@0 319 } else {
michael@0 320 RequiredStringArg profileName(cx, args, 1, "dumpProfile");
michael@0 321 if (!profileName)
michael@0 322 return false;
michael@0 323
michael@0 324 ret = JS_DumpProfile(filename.mBytes, profileName.mBytes);
michael@0 325 }
michael@0 326 }
michael@0 327
michael@0 328 args.rval().setBoolean(ret);
michael@0 329 return true;
michael@0 330 }
michael@0 331
michael@0 332 #if defined(MOZ_SHARK) || defined(MOZ_INSTRUMENTS)
michael@0 333
michael@0 334 static bool
michael@0 335 IgnoreAndReturnTrue(JSContext *cx, unsigned argc, jsval *vp)
michael@0 336 {
michael@0 337 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 338 args.rval().setBoolean(true);
michael@0 339 return true;
michael@0 340 }
michael@0 341
michael@0 342 #endif
michael@0 343
michael@0 344 #ifdef MOZ_CALLGRIND
michael@0 345 static bool
michael@0 346 StartCallgrind(JSContext *cx, unsigned argc, jsval *vp)
michael@0 347 {
michael@0 348 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 349 args.rval().setBoolean(js_StartCallgrind());
michael@0 350 return true;
michael@0 351 }
michael@0 352
michael@0 353 static bool
michael@0 354 StopCallgrind(JSContext *cx, unsigned argc, jsval *vp)
michael@0 355 {
michael@0 356 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 357 args.rval().setBoolean(js_StopCallgrind());
michael@0 358 return true;
michael@0 359 }
michael@0 360
michael@0 361 static bool
michael@0 362 DumpCallgrind(JSContext *cx, unsigned argc, jsval *vp)
michael@0 363 {
michael@0 364 CallArgs args = CallArgsFromVp(argc, vp);
michael@0 365 if (args.length() == 0) {
michael@0 366 args.rval().setBoolean(js_DumpCallgrind(nullptr));
michael@0 367 return true;
michael@0 368 }
michael@0 369
michael@0 370 RequiredStringArg outFile(cx, args, 0, "dumpCallgrind");
michael@0 371 if (!outFile)
michael@0 372 return false;
michael@0 373
michael@0 374 args.rval().setBoolean(js_DumpCallgrind(outFile.mBytes));
michael@0 375 return true;
michael@0 376 }
michael@0 377 #endif
michael@0 378
michael@0 379 static const JSFunctionSpec profiling_functions[] = {
michael@0 380 JS_FN("startProfiling", StartProfiling, 1,0),
michael@0 381 JS_FN("stopProfiling", StopProfiling, 1,0),
michael@0 382 JS_FN("pauseProfilers", PauseProfilers, 1,0),
michael@0 383 JS_FN("resumeProfilers", ResumeProfilers, 1,0),
michael@0 384 JS_FN("dumpProfile", DumpProfile, 2,0),
michael@0 385 #if defined(MOZ_SHARK) || defined(MOZ_INSTRUMENTS)
michael@0 386 /* Keep users of the old shark API happy. */
michael@0 387 JS_FN("connectShark", IgnoreAndReturnTrue, 0,0),
michael@0 388 JS_FN("disconnectShark", IgnoreAndReturnTrue, 0,0),
michael@0 389 JS_FN("startShark", StartProfiling, 0,0),
michael@0 390 JS_FN("stopShark", StopProfiling, 0,0),
michael@0 391 #endif
michael@0 392 #ifdef MOZ_CALLGRIND
michael@0 393 JS_FN("startCallgrind", StartCallgrind, 0,0),
michael@0 394 JS_FN("stopCallgrind", StopCallgrind, 0,0),
michael@0 395 JS_FN("dumpCallgrind", DumpCallgrind, 1,0),
michael@0 396 #endif
michael@0 397 JS_FS_END
michael@0 398 };
michael@0 399
michael@0 400 #endif
michael@0 401
michael@0 402 JS_PUBLIC_API(bool)
michael@0 403 JS_DefineProfilingFunctions(JSContext *cx, JSObject *objArg)
michael@0 404 {
michael@0 405 RootedObject obj(cx, objArg);
michael@0 406
michael@0 407 assertSameCompartment(cx, obj);
michael@0 408 #ifdef MOZ_PROFILING
michael@0 409 return JS_DefineFunctions(cx, obj, profiling_functions);
michael@0 410 #else
michael@0 411 return true;
michael@0 412 #endif
michael@0 413 }
michael@0 414
michael@0 415 #ifdef MOZ_CALLGRIND
michael@0 416
michael@0 417 JS_FRIEND_API(bool)
michael@0 418 js_StartCallgrind()
michael@0 419 {
michael@0 420 JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_START_INSTRUMENTATION);
michael@0 421 JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_ZERO_STATS);
michael@0 422 return true;
michael@0 423 }
michael@0 424
michael@0 425 JS_FRIEND_API(bool)
michael@0 426 js_StopCallgrind()
michael@0 427 {
michael@0 428 JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_STOP_INSTRUMENTATION);
michael@0 429 return true;
michael@0 430 }
michael@0 431
michael@0 432 JS_FRIEND_API(bool)
michael@0 433 js_DumpCallgrind(const char *outfile)
michael@0 434 {
michael@0 435 if (outfile) {
michael@0 436 JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS_AT(outfile));
michael@0 437 } else {
michael@0 438 JS_SILENCE_UNUSED_VALUE_IN_EXPR(CALLGRIND_DUMP_STATS);
michael@0 439 }
michael@0 440
michael@0 441 return true;
michael@0 442 }
michael@0 443
michael@0 444 #endif /* MOZ_CALLGRIND */
michael@0 445
michael@0 446 #ifdef __linux__
michael@0 447
michael@0 448 /*
michael@0 449 * Code for starting and stopping |perf|, the Linux profiler.
michael@0 450 *
michael@0 451 * Output from profiling is written to mozperf.data in your cwd.
michael@0 452 *
michael@0 453 * To enable, set MOZ_PROFILE_WITH_PERF=1 in your environment.
michael@0 454 *
michael@0 455 * To pass additional parameters to |perf record|, provide them in the
michael@0 456 * MOZ_PROFILE_PERF_FLAGS environment variable. If this variable does not
michael@0 457 * exist, we default it to "--call-graph". (If you don't want --call-graph but
michael@0 458 * don't want to pass any other args, define MOZ_PROFILE_PERF_FLAGS to the empty
michael@0 459 * string.)
michael@0 460 *
michael@0 461 * If you include --pid or --output in MOZ_PROFILE_PERF_FLAGS, you're just
michael@0 462 * asking for trouble.
michael@0 463 *
michael@0 464 * Our split-on-spaces logic is lame, so don't expect MOZ_PROFILE_PERF_FLAGS to
michael@0 465 * work if you pass an argument which includes a space (e.g.
michael@0 466 * MOZ_PROFILE_PERF_FLAGS="-e 'foo bar'").
michael@0 467 */
michael@0 468
michael@0 469 #include <signal.h>
michael@0 470 #include <sys/wait.h>
michael@0 471 #include <unistd.h>
michael@0 472
michael@0 473 static bool perfInitialized = false;
michael@0 474 static pid_t perfPid = 0;
michael@0 475
michael@0 476 bool js_StartPerf()
michael@0 477 {
michael@0 478 const char *outfile = "mozperf.data";
michael@0 479
michael@0 480 if (perfPid != 0) {
michael@0 481 UnsafeError("js_StartPerf: called while perf was already running!\n");
michael@0 482 return false;
michael@0 483 }
michael@0 484
michael@0 485 // Bail if MOZ_PROFILE_WITH_PERF is empty or undefined.
michael@0 486 if (!getenv("MOZ_PROFILE_WITH_PERF") ||
michael@0 487 !strlen(getenv("MOZ_PROFILE_WITH_PERF"))) {
michael@0 488 return true;
michael@0 489 }
michael@0 490
michael@0 491 /*
michael@0 492 * Delete mozperf.data the first time through -- we're going to append to it
michael@0 493 * later on, so we want it to be clean when we start out.
michael@0 494 */
michael@0 495 if (!perfInitialized) {
michael@0 496 perfInitialized = true;
michael@0 497 unlink(outfile);
michael@0 498 char cwd[4096];
michael@0 499 printf("Writing perf profiling data to %s/%s\n",
michael@0 500 getcwd(cwd, sizeof(cwd)), outfile);
michael@0 501 }
michael@0 502
michael@0 503 pid_t mainPid = getpid();
michael@0 504
michael@0 505 pid_t childPid = fork();
michael@0 506 if (childPid == 0) {
michael@0 507 /* perf record --append --pid $mainPID --output=$outfile $MOZ_PROFILE_PERF_FLAGS */
michael@0 508
michael@0 509 char mainPidStr[16];
michael@0 510 snprintf(mainPidStr, sizeof(mainPidStr), "%d", mainPid);
michael@0 511 const char *defaultArgs[] = {"perf", "record", "--append",
michael@0 512 "--pid", mainPidStr, "--output", outfile};
michael@0 513
michael@0 514 Vector<const char*, 0, SystemAllocPolicy> args;
michael@0 515 args.append(defaultArgs, ArrayLength(defaultArgs));
michael@0 516
michael@0 517 const char *flags = getenv("MOZ_PROFILE_PERF_FLAGS");
michael@0 518 if (!flags) {
michael@0 519 flags = "--call-graph";
michael@0 520 }
michael@0 521
michael@0 522 char *flags2 = (char *)js_malloc(strlen(flags) + 1);
michael@0 523 if (!flags2)
michael@0 524 return false;
michael@0 525 strcpy(flags2, flags);
michael@0 526
michael@0 527 // Split |flags2| on spaces. (Don't bother to free it -- we're going to
michael@0 528 // exec anyway.)
michael@0 529 char *toksave;
michael@0 530 char *tok = strtok_r(flags2, " ", &toksave);
michael@0 531 while (tok) {
michael@0 532 args.append(tok);
michael@0 533 tok = strtok_r(nullptr, " ", &toksave);
michael@0 534 }
michael@0 535
michael@0 536 args.append((char*) nullptr);
michael@0 537
michael@0 538 execvp("perf", const_cast<char**>(args.begin()));
michael@0 539
michael@0 540 /* Reached only if execlp fails. */
michael@0 541 fprintf(stderr, "Unable to start perf.\n");
michael@0 542 exit(1);
michael@0 543 }
michael@0 544 else if (childPid > 0) {
michael@0 545 perfPid = childPid;
michael@0 546
michael@0 547 /* Give perf a chance to warm up. */
michael@0 548 usleep(500 * 1000);
michael@0 549 return true;
michael@0 550 }
michael@0 551 else {
michael@0 552 UnsafeError("js_StartPerf: fork() failed\n");
michael@0 553 return false;
michael@0 554 }
michael@0 555 }
michael@0 556
michael@0 557 bool js_StopPerf()
michael@0 558 {
michael@0 559 if (perfPid == 0) {
michael@0 560 UnsafeError("js_StopPerf: perf is not running.\n");
michael@0 561 return true;
michael@0 562 }
michael@0 563
michael@0 564 if (kill(perfPid, SIGINT)) {
michael@0 565 UnsafeError("js_StopPerf: kill failed\n");
michael@0 566
michael@0 567 // Try to reap the process anyway.
michael@0 568 waitpid(perfPid, nullptr, WNOHANG);
michael@0 569 }
michael@0 570 else {
michael@0 571 waitpid(perfPid, nullptr, 0);
michael@0 572 }
michael@0 573
michael@0 574 perfPid = 0;
michael@0 575 return true;
michael@0 576 }
michael@0 577
michael@0 578 #endif /* __linux__ */

mercurial