]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 | 1 | /* |
81345200 | 2 | * Copyright (C) 2011, 2012, 2014 Apple Inc. All rights reserved. |
6fe7ccc8 A |
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 | #include "config.h" | |
27 | #include "Options.h" | |
28 | ||
93a37866 A |
29 | #include "HeapStatistics.h" |
30 | #include <algorithm> | |
6fe7ccc8 | 31 | #include <limits> |
93a37866 A |
32 | #include <stdlib.h> |
33 | #include <string.h> | |
81345200 | 34 | #include <wtf/DataLog.h> |
6fe7ccc8 A |
35 | #include <wtf/NumberOfCores.h> |
36 | #include <wtf/PageBlock.h> | |
93a37866 A |
37 | #include <wtf/StdLibExtras.h> |
38 | #include <wtf/StringExtras.h> | |
6fe7ccc8 A |
39 | |
40 | #if OS(DARWIN) && ENABLE(PARALLEL_GC) | |
41 | #include <sys/sysctl.h> | |
42 | #endif | |
43 | ||
93a37866 | 44 | namespace JSC { |
6fe7ccc8 | 45 | |
6fe7ccc8 A |
46 | static bool parse(const char* string, bool& value) |
47 | { | |
48 | if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) { | |
49 | value = true; | |
50 | return true; | |
51 | } | |
52 | if (!strcasecmp(string, "false") || !strcasecmp(string, "no") || !strcmp(string, "0")) { | |
53 | value = false; | |
54 | return true; | |
55 | } | |
56 | return false; | |
57 | } | |
58 | ||
59 | static bool parse(const char* string, int32_t& value) | |
60 | { | |
61 | return sscanf(string, "%d", &value) == 1; | |
62 | } | |
63 | ||
64 | static bool parse(const char* string, unsigned& value) | |
65 | { | |
66 | return sscanf(string, "%u", &value) == 1; | |
67 | } | |
68 | ||
69 | static bool parse(const char* string, double& value) | |
70 | { | |
71 | return sscanf(string, "%lf", &value) == 1; | |
72 | } | |
73 | ||
93a37866 A |
74 | static bool parse(const char* string, OptionRange& value) |
75 | { | |
76 | return value.init(string); | |
77 | } | |
78 | ||
81345200 A |
79 | static bool parse(const char* string, const char*& value) |
80 | { | |
81 | value = string; | |
82 | return true; | |
83 | } | |
84 | ||
85 | static bool parse(const char* string, GCLogging::Level& value) | |
86 | { | |
87 | if (!strcasecmp(string, "none") || !strcasecmp(string, "no") || !strcasecmp(string, "false") || !strcmp(string, "0")) { | |
88 | value = GCLogging::None; | |
89 | return true; | |
90 | } | |
91 | ||
92 | if (!strcasecmp(string, "basic") || !strcasecmp(string, "yes") || !strcasecmp(string, "true") || !strcmp(string, "1")) { | |
93 | value = GCLogging::Basic; | |
94 | return true; | |
95 | } | |
96 | ||
97 | if (!strcasecmp(string, "verbose") || !strcmp(string, "2")) { | |
98 | value = GCLogging::Verbose; | |
99 | return true; | |
100 | } | |
101 | ||
102 | return false; | |
103 | } | |
104 | ||
93a37866 | 105 | template<typename T> |
81345200 | 106 | bool overrideOptionWithHeuristic(T& variable, const char* name) |
6fe7ccc8 | 107 | { |
93a37866 | 108 | #if !OS(WINCE) |
6fe7ccc8 | 109 | const char* stringValue = getenv(name); |
93a37866 | 110 | if (!stringValue) |
81345200 | 111 | return false; |
6fe7ccc8 A |
112 | |
113 | if (parse(stringValue, variable)) | |
81345200 | 114 | return true; |
6fe7ccc8 A |
115 | |
116 | fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue); | |
93a37866 | 117 | #endif |
81345200 | 118 | return false; |
6fe7ccc8 A |
119 | } |
120 | ||
81345200 | 121 | static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1) |
93a37866 | 122 | { |
81345200 | 123 | int cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfWorkerThreads); |
93a37866 A |
124 | |
125 | // Be paranoid, it is the OS we're dealing with, after all. | |
126 | ASSERT(cpusToUse >= 1); | |
81345200 A |
127 | return std::max(cpusToUse, minimum); |
128 | } | |
129 | ||
130 | static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta) | |
131 | { | |
132 | if (WTF::numberOfProcessorCores() <= 2) | |
133 | return twoCorePriorityDelta; | |
134 | ||
135 | return multiCorePriorityDelta; | |
136 | } | |
137 | ||
138 | static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers) | |
139 | { | |
140 | #if ENABLE(PARALLEL_GC) | |
141 | return computeNumberOfWorkerThreads(maxNumberOfGCMarkers); | |
6fe7ccc8 | 142 | #else |
93a37866 | 143 | UNUSED_PARAM(maxNumberOfGCMarkers); |
81345200 | 144 | return 1; |
6fe7ccc8 | 145 | #endif |
93a37866 A |
146 | } |
147 | ||
148 | bool OptionRange::init(const char* rangeString) | |
6fe7ccc8 | 149 | { |
93a37866 A |
150 | // rangeString should be in the form of [!]<low>[:<high>] |
151 | // where low and high are unsigned | |
6fe7ccc8 | 152 | |
93a37866 | 153 | bool invert = false; |
6fe7ccc8 | 154 | |
93a37866 A |
155 | if (m_state > Uninitialized) |
156 | return true; | |
6fe7ccc8 | 157 | |
93a37866 A |
158 | if (!rangeString) { |
159 | m_state = InitError; | |
160 | return false; | |
161 | } | |
6fe7ccc8 | 162 | |
93a37866 | 163 | m_rangeString = rangeString; |
6fe7ccc8 | 164 | |
93a37866 A |
165 | if (*rangeString == '!') { |
166 | invert = true; | |
167 | rangeString++; | |
168 | } | |
6fe7ccc8 | 169 | |
93a37866 | 170 | int scanResult = sscanf(rangeString, " %u:%u", &m_lowLimit, &m_highLimit); |
6fe7ccc8 | 171 | |
93a37866 A |
172 | if (!scanResult || scanResult == EOF) { |
173 | m_state = InitError; | |
174 | return false; | |
175 | } | |
6fe7ccc8 | 176 | |
93a37866 A |
177 | if (scanResult == 1) |
178 | m_highLimit = m_lowLimit; | |
179 | ||
180 | if (m_lowLimit > m_highLimit) { | |
181 | m_state = InitError; | |
182 | return false; | |
183 | } | |
184 | ||
185 | m_state = invert ? Inverted : Normal; | |
186 | ||
187 | return true; | |
188 | } | |
189 | ||
190 | bool OptionRange::isInRange(unsigned count) | |
191 | { | |
192 | if (m_state < Normal) | |
193 | return true; | |
194 | ||
195 | if ((m_lowLimit <= count) && (count <= m_highLimit)) | |
196 | return m_state == Normal ? true : false; | |
197 | ||
198 | return m_state == Normal ? false : true; | |
199 | } | |
200 | ||
201 | Options::Entry Options::s_options[Options::numberOfOptions]; | |
202 | ||
203 | // Realize the names for each of the options: | |
204 | const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = { | |
205 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
206 | { #name_, Options::type_##Type }, | |
207 | JSC_OPTIONS(FOR_EACH_OPTION) | |
208 | #undef FOR_EACH_OPTION | |
209 | }; | |
210 | ||
81345200 A |
211 | static void recomputeDependentOptions() |
212 | { | |
213 | #if !ENABLE(JIT) | |
214 | Options::useLLInt() = true; | |
215 | Options::useJIT() = false; | |
216 | Options::useDFGJIT() = false; | |
217 | Options::useFTLJIT() = false; | |
218 | #endif | |
219 | #if !ENABLE(YARR_JIT) | |
220 | Options::useRegExpJIT() = false; | |
221 | #endif | |
222 | #if !ENABLE(CONCURRENT_JIT) | |
223 | Options::enableConcurrentJIT() = false; | |
224 | #endif | |
225 | #if !ENABLE(DFG_JIT) | |
226 | Options::useDFGJIT() = false; | |
227 | Options::useFTLJIT() = false; | |
228 | #endif | |
229 | #if !ENABLE(FTL_JIT) | |
230 | Options::useFTLJIT() = false; | |
231 | #endif | |
232 | ||
233 | if (Options::showDisassembly() | |
234 | || Options::showDFGDisassembly() | |
235 | || Options::showFTLDisassembly() | |
236 | || Options::dumpBytecodeAtDFGTime() | |
237 | || Options::dumpGraphAtEachPhase() | |
238 | || Options::verboseCompilation() | |
239 | || Options::verboseFTLCompilation() | |
240 | || Options::logCompilationChanges() | |
241 | || Options::validateGraph() | |
242 | || Options::validateGraphAtEachPhase() | |
243 | || Options::verboseOSR() | |
244 | || Options::verboseCompilationQueue() | |
245 | || Options::reportCompileTimes() | |
246 | || Options::reportFTLCompileTimes() | |
247 | || Options::verboseCFA() | |
248 | || Options::verboseFTLFailure()) | |
249 | Options::alwaysComputeHash() = true; | |
250 | ||
251 | // Compute the maximum value of the reoptimization retry counter. This is simply | |
252 | // the largest value at which we don't overflow the execute counter, when using it | |
253 | // to left-shift the execution counter by this amount. Currently the value ends | |
254 | // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles | |
255 | // total on a 32-bit processor. | |
256 | Options::reoptimizationRetryCounterMax() = 0; | |
257 | while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())) | |
258 | Options::reoptimizationRetryCounterMax()++; | |
259 | ||
260 | ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0); | |
261 | ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())); | |
262 | } | |
263 | ||
93a37866 A |
264 | void Options::initialize() |
265 | { | |
266 | // Initialize each of the options with their default values: | |
267 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
268 | name_() = defaultValue_; | |
269 | JSC_OPTIONS(FOR_EACH_OPTION) | |
270 | #undef FOR_EACH_OPTION | |
271 | ||
93a37866 A |
272 | // Allow environment vars to override options if applicable. |
273 | // The evn var should be the name of the option prefixed with | |
274 | // "JSC_". | |
275 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
81345200 A |
276 | if (overrideOptionWithHeuristic(name_(), "JSC_" #name_)) \ |
277 | s_options[OPT_##name_].didOverride = true; | |
93a37866 A |
278 | JSC_OPTIONS(FOR_EACH_OPTION) |
279 | #undef FOR_EACH_OPTION | |
280 | ||
281 | #if 0 | |
282 | ; // Deconfuse editors that do auto indentation | |
283 | #endif | |
6fe7ccc8 | 284 | |
81345200 | 285 | recomputeDependentOptions(); |
93a37866 | 286 | |
81345200 A |
287 | // Do range checks where needed and make corrections to the options: |
288 | ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp()); | |
289 | ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon()); | |
290 | ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0); | |
93a37866 A |
291 | } |
292 | ||
293 | // Parses a single command line option in the format "<optionName>=<value>" | |
294 | // (no spaces allowed) and set the specified option if appropriate. | |
295 | bool Options::setOption(const char* arg) | |
296 | { | |
297 | // arg should look like this: | |
298 | // <jscOptionName>=<appropriate value> | |
299 | const char* equalStr = strchr(arg, '='); | |
300 | if (!equalStr) | |
301 | return false; | |
302 | ||
303 | const char* valueStr = equalStr + 1; | |
304 | ||
305 | // For each option, check if the specify arg is a match. If so, set the arg | |
306 | // if the value makes sense. Otherwise, move on to checking the next option. | |
307 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
308 | if (!strncmp(arg, #name_, equalStr - arg)) { \ | |
309 | type_ value; \ | |
81345200 | 310 | value = (defaultValue_); \ |
93a37866 A |
311 | bool success = parse(valueStr, value); \ |
312 | if (success) { \ | |
313 | name_() = value; \ | |
81345200 A |
314 | s_options[OPT_##name_].didOverride = true; \ |
315 | recomputeDependentOptions(); \ | |
93a37866 A |
316 | return true; \ |
317 | } \ | |
318 | return false; \ | |
319 | } | |
320 | ||
321 | JSC_OPTIONS(FOR_EACH_OPTION) | |
322 | #undef FOR_EACH_OPTION | |
323 | ||
81345200 | 324 | return false; // No option matched. |
6fe7ccc8 A |
325 | } |
326 | ||
93a37866 A |
327 | void Options::dumpAllOptions(FILE* stream) |
328 | { | |
329 | fprintf(stream, "JSC runtime options:\n"); | |
330 | for (int id = 0; id < numberOfOptions; id++) | |
331 | dumpOption(static_cast<OptionID>(id), stream, " ", "\n"); | |
332 | } | |
333 | ||
334 | void Options::dumpOption(OptionID id, FILE* stream, const char* header, const char* footer) | |
335 | { | |
336 | if (id >= numberOfOptions) | |
337 | return; // Illegal option. | |
338 | ||
339 | fprintf(stream, "%s%s: ", header, s_optionsInfo[id].name); | |
340 | switch (s_optionsInfo[id].type) { | |
341 | case boolType: | |
342 | fprintf(stream, "%s", s_options[id].u.boolVal?"true":"false"); | |
343 | break; | |
344 | case unsignedType: | |
345 | fprintf(stream, "%u", s_options[id].u.unsignedVal); | |
346 | break; | |
347 | case doubleType: | |
348 | fprintf(stream, "%lf", s_options[id].u.doubleVal); | |
349 | break; | |
350 | case int32Type: | |
351 | fprintf(stream, "%d", s_options[id].u.int32Val); | |
352 | break; | |
353 | case optionRangeType: | |
354 | fprintf(stream, "%s", s_options[id].u.optionRangeVal.rangeString()); | |
355 | break; | |
81345200 A |
356 | case optionStringType: { |
357 | const char* option = s_options[id].u.optionStringVal; | |
358 | if (!option) | |
359 | option = ""; | |
360 | fprintf(stream, "%s", option); | |
361 | break; | |
362 | } | |
363 | case gcLogLevelType: { | |
364 | fprintf(stream, "%s", GCLogging::levelAsString(s_options[id].u.gcLogLevelVal)); | |
365 | break; | |
366 | } | |
93a37866 A |
367 | } |
368 | fprintf(stream, "%s", footer); | |
369 | } | |
6fe7ccc8 | 370 | |
93a37866 | 371 | } // namespace JSC |
6fe7ccc8 | 372 |