Changeset 253613 in webkit
- Timestamp:
- Dec 17, 2019, 12:50:20 AM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r253609 r253613 1 2019-12-16 Mark Lam <mark.lam@apple.com> 2 3 Relanding r253581: Changed jsc shell timeout mechanism to leverage the VMTraps and use CPUTime. 4 https://bugs.webkit.org/show_bug.cgi?id=205279 5 <rdar://problem/57971874> 6 7 Reviewed by Saam Barati. 8 9 This fixes all the timeouts that occur due to CPU time starvation when 10 running JSC tests on a debug build. 11 12 What this means is that the timeout mechanism may trigger asynchronous 13 OSR exits. If a test requires no OSR exits, that test should 14 requireOption("--usePollingTraps=true") so that the VMTraps will use its 15 polling implementation instead. 16 17 I've tested this with a full run of the JSC stress tests with a debug 18 build and saw 0 timeouts. I've also tested it with a contrived tests that 19 loops forever, and saw the expected timeout crash. 20 21 Will look into re-tuning needed timeout value (and other JSC tests timeout 22 cleanup) in https://bugs.webkit.org/show_bug.cgi?id=205298. 23 24 Update: in the previously landed patch, I did a last minute sort of the cases 25 Int the switch statement in VMTraps::handleTraps() before posting my patch. 26 This is incorrect to do since one of the cases need to fall through to another 27 case. This patch undoes the sorting to the order I originally had the cases 28 in during development and testing. 29 30 * interpreter/Interpreter.cpp: 31 (JSC::Interpreter::executeProgram): 32 (JSC::Interpreter::executeCall): 33 (JSC::Interpreter::executeConstruct): 34 (JSC::Interpreter::execute): 35 (JSC::Interpreter::executeModuleProgram): 36 * interpreter/InterpreterInlines.h: 37 (JSC::Interpreter::execute): 38 * jsc.cpp: 39 (startTimeoutTimer): 40 (timeoutCheckCallback): 41 (initializeTimeoutIfNeeded): 42 (startTimeoutThreadIfNeeded): 43 (runJSC): 44 (jscmain): 45 * runtime/JSCConfig.h: 46 * runtime/VM.h: 47 (JSC::VM::notifyNeedShellTimeoutCheck): 48 * runtime/VMTraps.cpp: 49 (JSC::VMTraps::handleTraps): 50 * runtime/VMTraps.h: 51 (JSC::VMTraps::Mask::Mask): 52 (JSC::VMTraps::Mask::allEventTypes): 53 (JSC::VMTraps::Mask::init): 54 (JSC::VMTraps::interruptingTraps): 55 * tools/VMInspector.cpp: 56 (JSC::VMInspector::forEachVM): 57 * tools/VMInspector.h: 58 1 59 2019-12-16 Mark Lam <mark.lam@apple.com> 2 60 -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r253609 r253613 821 821 } 822 822 823 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);824 if (UNLIKELY(vm.needTrapHandling( mask))) {825 vm.handleTraps(globalObject, vm.topCallFrame, mask);823 constexpr auto trapsMask = VMTraps::interruptingTraps(); 824 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 825 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 826 826 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 827 827 } … … 882 882 newCodeBlock = 0; 883 883 884 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);885 if (UNLIKELY(vm.needTrapHandling( mask))) {886 vm.handleTraps(globalObject, vm.topCallFrame, mask);884 constexpr auto trapsMask = VMTraps::interruptingTraps(); 885 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 886 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 887 887 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 888 888 } … … 953 953 newCodeBlock = 0; 954 954 955 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);956 if (UNLIKELY(vm.needTrapHandling( mask))) {957 vm.handleTraps(globalObject, vm.topCallFrame, mask);955 constexpr auto trapsMask = VMTraps::interruptingTraps(); 956 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 957 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 958 958 RETURN_IF_EXCEPTION(throwScope, nullptr); 959 959 } … … 1137 1137 } 1138 1138 1139 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);1140 if (UNLIKELY(vm.needTrapHandling( mask))) {1141 vm.handleTraps(globalObject, vm.topCallFrame, mask);1139 constexpr auto trapsMask = VMTraps::interruptingTraps(); 1140 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 1141 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 1142 1142 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 1143 1143 } … … 1187 1187 } 1188 1188 1189 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);1190 if (UNLIKELY(vm.needTrapHandling( mask))) {1191 vm.handleTraps(globalObject, vm.topCallFrame, mask);1189 constexpr auto trapsMask = VMTraps::interruptingTraps(); 1190 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 1191 vm.handleTraps(globalObject, vm.topCallFrame, trapsMask); 1192 1192 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 1193 1193 } -
trunk/Source/JavaScriptCore/interpreter/InterpreterInlines.h
r253609 r253613 1 1 /* 2 2 * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com> 3 * Copyright (C) 2016-201 8Apple Inc. All rights reserved.3 * Copyright (C) 2016-2019 Apple Inc. All rights reserved. 4 4 * 5 5 * Redistribution and use in source and binary forms, with or without … … 75 75 StackStats::CheckPoint stackCheckPoint; 76 76 77 VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);78 if (UNLIKELY(vm.needTrapHandling( mask))) {79 vm.handleTraps(closure.protoCallFrame->globalObject, closure.oldCallFrame, mask);77 constexpr auto trapsMask = VMTraps::interruptingTraps(); 78 if (UNLIKELY(vm.needTrapHandling(trapsMask))) { 79 vm.handleTraps(closure.protoCallFrame->globalObject, closure.oldCallFrame, trapsMask); 80 80 RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); 81 81 } -
trunk/Source/JavaScriptCore/jsc.cpp
r253609 r253613 71 71 #include "TestRunnerUtils.h" 72 72 #include "TypedArrayInlines.h" 73 #include "VMInspector.h" 73 74 #include "WasmCapabilities.h" 74 75 #include "WasmContext.h" … … 85 86 #include <type_traits> 86 87 #include <wtf/Box.h> 88 #include <wtf/CPUTime.h> 87 89 #include <wtf/CommaPrinter.h> 88 90 #include <wtf/FileSystem.h> … … 2428 2430 static double s_desiredTimeout; 2429 2431 static double s_timeoutMultiplier = 1.0; 2430 2431 static void startTimeoutThreadIfNeeded() 2432 static Seconds s_timeoutDuration; 2433 static Seconds s_maxAllowedCPUTime; 2434 static VM* s_vm; 2435 2436 static void startTimeoutTimer(Seconds duration) 2437 { 2438 Thread::create("jsc Timeout Thread", [=] () { 2439 sleep(duration); 2440 VMInspector::forEachVM([&] (VM& vm) -> VMInspector::FunctorStatus { 2441 if (&vm != s_vm) 2442 return VMInspector::FunctorStatus::Continue; 2443 vm.notifyNeedShellTimeoutCheck(); 2444 return VMInspector::FunctorStatus::Done; 2445 }); 2446 }); 2447 } 2448 2449 static void timeoutCheckCallback(VM& vm) 2450 { 2451 RELEASE_ASSERT(&vm == s_vm); 2452 auto cpuTime = CPUTime::forCurrentThread(); 2453 if (cpuTime >= s_maxAllowedCPUTime) { 2454 dataLog("Timed out after ", s_timeoutDuration, " seconds!\n"); 2455 CRASH(); 2456 } 2457 auto remainingTime = s_maxAllowedCPUTime - cpuTime; 2458 startTimeoutTimer(remainingTime); 2459 } 2460 2461 static void initializeTimeoutIfNeeded() 2432 2462 { 2433 2463 if (char* timeoutString = getenv("JSCTEST_timeout")) { … … 2435 2465 dataLog("WARNING: timeout string is malformed, got ", timeoutString, 2436 2466 " but expected a number. Not using a timeout.\n"); 2437 } else { 2438 Thread::create("jsc Timeout Thread", [] () { 2439 Seconds timeoutDuration(s_desiredTimeout * s_timeoutMultiplier); 2440 sleep(timeoutDuration); 2441 dataLog("Timed out after ", timeoutDuration, " seconds!\n"); 2442 CRASH(); 2443 }); 2444 } 2445 } 2467 } else 2468 g_jscConfig.shellTimeoutCheckCallback = timeoutCheckCallback; 2469 } 2470 } 2471 2472 static void startTimeoutThreadIfNeeded(VM& vm) 2473 { 2474 if (!g_jscConfig.shellTimeoutCheckCallback) 2475 return; 2476 2477 s_vm = &vm; 2478 s_timeoutDuration = Seconds(s_desiredTimeout * s_timeoutMultiplier); 2479 s_maxAllowedCPUTime = CPUTime::forCurrentThread() + s_timeoutDuration; 2480 Seconds timeoutDuration(s_desiredTimeout * s_timeoutMultiplier); 2481 startTimeoutTimer(timeoutDuration); 2446 2482 } 2447 2483 … … 3000 3036 JSLockHolder locker(vm); 3001 3037 3038 startTimeoutThreadIfNeeded(vm); 3002 3039 if (options.m_profile && !vm.m_perBytecodeProfiler) 3003 3040 vm.m_perBytecodeProfiler = makeUnique<Profiler::Database>(vm); … … 3100 3137 // Initialize JSC before getting VM. 3101 3138 JSC::initializeThreading(); 3102 startTimeoutThreadIfNeeded();3139 initializeTimeoutIfNeeded(); 3103 3140 #if ENABLE(WEBASSEMBLY) 3104 3141 JSC::Wasm::enableFastMemory(); -
trunk/Source/JavaScriptCore/runtime/JSCConfig.h
r253609 r253613 33 33 class ExecutableAllocator; 34 34 class FixedVMPoolExecutableAllocator; 35 class VM; 35 36 36 37 #if CPU(ARM64) || PLATFORM(WATCHOS) … … 83 84 84 85 OptionsStorage options; 86 87 void (*shellTimeoutCheckCallback)(VM&); 85 88 }; 86 89 char ensureSize[ConfigSizeToProtect]; -
trunk/Source/JavaScriptCore/runtime/VM.h
r253609 r253613 1068 1068 1069 1069 void notifyNeedDebuggerBreak() { m_traps.fireTrap(VMTraps::NeedDebuggerBreak); } 1070 void notifyNeedShellTimeoutCheck() { m_traps.fireTrap(VMTraps::NeedShellTimeoutCheck); } 1070 1071 void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); } 1071 1072 void notifyNeedWatchdogCheck() { m_traps.fireTrap(VMTraps::NeedWatchdogCheck); } -
trunk/Source/JavaScriptCore/runtime/VMTraps.cpp
r253609 r253613 358 358 invalidateCodeBlocksOnStack(callFrame); 359 359 break; 360 360 361 case NeedShellTimeoutCheck: 362 RELEASE_ASSERT(g_jscConfig.shellTimeoutCheckCallback); 363 g_jscConfig.shellTimeoutCheckCallback(vm); 364 break; 365 361 366 case NeedWatchdogCheck: 362 367 ASSERT(vm.watchdog()); -
trunk/Source/JavaScriptCore/runtime/VMTraps.h
r253609 r253613 1 1 /* 2 * Copyright (C) 2017 Apple Inc. All rights reserved.2 * Copyright (C) 2017-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 53 53 // Sorted in servicing priority order from highest to lowest. 54 54 NeedDebuggerBreak, 55 NeedShellTimeoutCheck, 55 56 NeedTermination, 56 57 NeedWatchdogCheck, … … 62 63 public: 63 64 enum AllEventTypes { AllEventTypesTag }; 64 Mask(AllEventTypes)65 constexpr Mask(AllEventTypes) 65 66 : m_mask(std::numeric_limits<BitField>::max()) 66 67 { } 67 static Mask allEventTypes() { return Mask(AllEventTypesTag); } 68 static constexpr Mask allEventTypes() { return Mask(AllEventTypesTag); } 69 70 constexpr Mask(const Mask&) = default; 71 constexpr Mask(Mask&&) = default; 68 72 69 73 template<typename... Arguments> 70 Mask(Arguments... args)74 constexpr Mask(Arguments... args) 71 75 : m_mask(0) 72 76 { … … 78 82 private: 79 83 template<typename... Arguments> 80 void init(EventType eventType, Arguments... args)84 constexpr void init(EventType eventType, Arguments... args) 81 85 { 82 86 ASSERT(eventType < NumberOfEventTypes); … … 85 89 } 86 90 87 void init() { }91 constexpr void init() { } 88 92 89 93 BitField m_mask; 90 94 }; 95 96 static constexpr Mask interruptingTraps() { return Mask(NeedShellTimeoutCheck, NeedTermination, NeedWatchdogCheck); } 91 97 92 98 ~VMTraps(); -
trunk/Source/JavaScriptCore/tools/VMInspector.cpp
r253609 r253613 107 107 #endif // ENABLE(JIT) 108 108 109 void VMInspector::forEachVM(Function<FunctorStatus(VM&)>&& func) 110 { 111 VMInspector& inspector = instance(); 112 Locker lock(inspector.getLock()); 113 inspector.iterate(func); 114 } 115 109 116 auto VMInspector::isValidExecutableMemory(const VMInspector::Locker&, void* machinePC) -> Expected<bool, Error> 110 117 { -
trunk/Source/JavaScriptCore/tools/VMInspector.h
r253609 r253613 61 61 void iterate(const Locker&, const Functor& functor) { iterate(functor); } 62 62 63 JS_EXPORT_PRIVATE static void forEachVM(Function<FunctorStatus(VM&)>&&); 64 63 65 Expected<Locker, Error> lock(Seconds timeout = Seconds::infinity()); 64 66
Note:
See TracChangeset
for help on using the changeset viewer.