ExecutionCounter.h
1 /* 2 * Copyright (C) 2012-2017 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #pragma once 27 28 #include "JSGlobalObject.h" 29 #include "Options.h" 30 #include <wtf/PrintStream.h> 31 32 namespace JSC { 33 34 class CodeBlock; 35 36 enum CountingVariant { 37 CountingForBaseline, 38 CountingForUpperTiers 39 }; 40 41 double applyMemoryUsageHeuristics(int32_t value, CodeBlock*); 42 int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*); 43 44 inline int32_t formattedTotalExecutionCount(float value) 45 { 46 union { 47 int32_t i; 48 float f; 49 } u; 50 u.f = value; 51 return u.i; 52 } 53 54 template<CountingVariant countingVariant> 55 class ExecutionCounter { 56 WTF_MAKE_FAST_ALLOCATED; 57 WTF_MAKE_NONMOVABLE(ExecutionCounter); 58 public: 59 ExecutionCounter(); 60 void forceSlowPathConcurrently(); // If you use this, checkIfThresholdCrossedAndSet() may still return false. 61 bool checkIfThresholdCrossedAndSet(CodeBlock*); 62 bool hasCrossedThreshold() const { return m_counter >= 0; } 63 void setNewThreshold(int32_t threshold, CodeBlock*); 64 void deferIndefinitely(); 65 double count() const { return static_cast<double>(m_totalCount) + m_counter; } 66 void dump(PrintStream&) const; 67 68 void setNewThresholdForOSRExit(uint32_t activeThreshold, double memoryUsageAdjustedThreshold) 69 { 70 m_activeThreshold = activeThreshold; 71 m_counter = static_cast<int32_t>(-memoryUsageAdjustedThreshold); 72 m_totalCount = memoryUsageAdjustedThreshold; 73 } 74 75 static int32_t maximumExecutionCountsBetweenCheckpoints() 76 { 77 switch (countingVariant) { 78 case CountingForBaseline: 79 return Options::maximumExecutionCountsBetweenCheckpointsForBaseline(); 80 case CountingForUpperTiers: 81 return Options::maximumExecutionCountsBetweenCheckpointsForUpperTiers(); 82 default: 83 RELEASE_ASSERT_NOT_REACHED(); 84 return 0; 85 } 86 } 87 88 template<typename T> 89 static T clippedThreshold(JSGlobalObject* globalObject, T threshold) 90 { 91 int32_t maxThreshold; 92 if (Options::randomizeExecutionCountsBetweenCheckpoints() && globalObject) 93 maxThreshold = globalObject->weakRandomInteger() % maximumExecutionCountsBetweenCheckpoints(); 94 else 95 maxThreshold = maximumExecutionCountsBetweenCheckpoints(); 96 if (threshold > maxThreshold) 97 threshold = maxThreshold; 98 return threshold; 99 } 100 101 private: 102 bool hasCrossedThreshold(CodeBlock*) const; 103 bool setThreshold(CodeBlock*); 104 void reset(); 105 106 public: 107 // NB. These are intentionally public because it will be modified from machine code. 108 109 // This counter is incremented by the JIT or LLInt. It starts out negative and is 110 // counted up until it becomes non-negative. At the start of a counting period, 111 // the threshold we wish to reach is m_totalCount + m_counter, in the sense that 112 // we will add X to m_totalCount and subtract X from m_counter. 113 int32_t m_counter; 114 115 // Counts the total number of executions we have seen plus the ones we've set a 116 // threshold for in m_counter. Because m_counter's threshold is negative, the 117 // total number of actual executions can always be computed as m_totalCount + 118 // m_counter. 119 float m_totalCount; 120 121 // This is the threshold we were originally targeting, without any correction for 122 // the memory usage heuristics. 123 int32_t m_activeThreshold; 124 }; 125 126 typedef ExecutionCounter<CountingForBaseline> BaselineExecutionCounter; 127 typedef ExecutionCounter<CountingForUpperTiers> UpperTierExecutionCounter; 128 129 } // namespace JSC