1 /*
2  * Knobs.cpp
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #include "flow/Knobs.h"
22 #include "flow/flow.h"
23 #include <cmath>
24 
25 FlowKnobs const* FLOW_KNOBS = new FlowKnobs();
26 
27 #define init( knob, value ) initKnob( knob, value, #knob )
28 
FlowKnobs(bool randomize,bool isSimulated)29 FlowKnobs::FlowKnobs(bool randomize, bool isSimulated) {
30 	init( AUTOMATIC_TRACE_DUMP,                                  1 );
31 	init( PREVENT_FAST_SPIN_DELAY,                             .01 );
32 	init( CACHE_REFRESH_INTERVAL_WHEN_ALL_ALTERNATIVES_FAILED, 1.0 );
33 
34 	init( DELAY_JITTER_OFFSET,                                 0.9 );
35 	init( DELAY_JITTER_RANGE,                                  0.2 );
36 	init( BUSY_WAIT_THRESHOLD,                                   0 ); // 1e100 == never sleep
37 	init( CLIENT_REQUEST_INTERVAL,                             0.1 ); if( randomize && BUGGIFY ) CLIENT_REQUEST_INTERVAL = 1.0;
38 	init( SERVER_REQUEST_INTERVAL,                             0.1 ); if( randomize && BUGGIFY ) SERVER_REQUEST_INTERVAL = 1.0;
39 
40 	init( REACTOR_FLAGS,                                         0 );
41 
42 	init( DISABLE_ASSERTS,                                       0 );
43 	init( QUEUE_MODEL_SMOOTHING_AMOUNT,                        2.0 );
44 
45 	init( SLOWTASK_PROFILING_INTERVAL,                       0.125 ); // A value of 0 disables SlowTask profiling
46 	init( SLOWTASK_PROFILING_MAX_LOG_INTERVAL,                 1.0 );
47 	init( SLOWTASK_PROFILING_LOG_BACKOFF,                      2.0 );
48 
49 	init( RANDOMSEED_RETRY_LIMIT,                                4 );
50 	init( FAST_ALLOC_LOGGING_BYTES,                           10e6 );
51 	init( HUGE_ARENA_LOGGING_BYTES,                          100e6 );
52 	init( HUGE_ARENA_LOGGING_INTERVAL,                         5.0 );
53 
54 	//connectionMonitor
55 	init( CONNECTION_MONITOR_LOOP_TIME,   isSimulated ? 0.75 : 1.0 ); if( randomize && BUGGIFY ) CONNECTION_MONITOR_LOOP_TIME = 6.0;
56 	init( CONNECTION_MONITOR_TIMEOUT,     isSimulated ? 1.50 : 2.0 ); if( randomize && BUGGIFY ) CONNECTION_MONITOR_TIMEOUT = 6.0;
57 
58 	//FlowTransport
59 	init( CONNECTION_REJECTED_MESSAGE_DELAY,                   1.0 );
60 	init( CONNECTION_ID_TIMEOUT,                             600.0 ); if( randomize && BUGGIFY ) CONNECTION_ID_TIMEOUT = 60.0;
61 	init( CONNECTION_CLEANUP_DELAY,                          100.0 );
62 	init( INITIAL_RECONNECTION_TIME,                          0.05 );
63 	init( MAX_RECONNECTION_TIME,                               0.5 );
64 	init( RECONNECTION_TIME_GROWTH_RATE,                       1.2 );
65 	init( RECONNECTION_RESET_TIME,                             5.0 );
66 	init( CONNECTION_ACCEPT_DELAY,                            0.01 );
67 	init( TOO_MANY_CONNECTIONS_CLOSED_RESET_DELAY,             5.0 );
68 	init( TOO_MANY_CONNECTIONS_CLOSED_TIMEOUT,                20.0 );
69 
70 	init( TLS_CERT_REFRESH_DELAY_SECONDS,                 12*60*60 );
71 
72 	//AsyncFileCached
73 	init( PAGE_CACHE_4K,                                2000LL<<20 );
74 	init( PAGE_CACHE_64K,                                200LL<<20 );
75 	init( SIM_PAGE_CACHE_4K,                                   1e8 );
76 	init( SIM_PAGE_CACHE_64K,                                  1e7 );
77 	init( BUGGIFY_SIM_PAGE_CACHE_4K,                           1e6 );
78 	init( BUGGIFY_SIM_PAGE_CACHE_64K,                          1e6 );
79 	init( MAX_EVICT_ATTEMPTS,                                  100 ); if( randomize && BUGGIFY ) MAX_EVICT_ATTEMPTS = 2;
80 	init( PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION,                 0.1 ); if( randomize && BUGGIFY ) PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION = 0.0; else if( randomize && BUGGIFY ) PAGE_CACHE_TRUNCATE_LOOKUP_FRACTION = 1.0;
81 
82 	//AsyncFileKAIO
83 	init( MAX_OUTSTANDING,                                      64 );
84 	init( MIN_SUBMIT,                                           10 );
85 
86 	init( PAGE_WRITE_CHECKSUM_HISTORY,                           0 ); if( randomize && BUGGIFY ) PAGE_WRITE_CHECKSUM_HISTORY = 10000000;
87 	init( DISABLE_POSIX_KERNEL_AIO,                              0 );
88 
89 	//AsyncFileNonDurable
90 	init( MAX_PRIOR_MODIFICATION_DELAY,                        1.0 ); if( randomize && BUGGIFY ) MAX_PRIOR_MODIFICATION_DELAY = 10.0;
91 
92 	//GenericActors
93 	init( MAX_DELIVER_DUPLICATE_DELAY,                         1.0 ); if( randomize && BUGGIFY ) MAX_DELIVER_DUPLICATE_DELAY = 10.0;
94 	init( BUGGIFY_FLOW_LOCK_RELEASE_DELAY,                     1.0 );
95 
96 	//IAsyncFile
97 	init( INCREMENTAL_DELETE_TRUNCATE_AMOUNT,                  5e8 ); //500MB
98 	init( INCREMENTAL_DELETE_INTERVAL,                         1.0 ); //every 1 second
99 
100 	//Net2 and FlowTransport
101 	init( MIN_COALESCE_DELAY,                                10e-6 ); if( randomize && BUGGIFY ) MIN_COALESCE_DELAY = 0;
102 	init( MAX_COALESCE_DELAY,                                20e-6 ); if( randomize && BUGGIFY ) MAX_COALESCE_DELAY = 0;
103 	init( SLOW_LOOP_CUTOFF,                          15.0 / 1000.0 );
104 	init( SLOW_LOOP_SAMPLING_RATE,                             0.1 );
105 	init( TSC_YIELD_TIME,                                  1000000 );
106 
107 	//Network
108 	init( PACKET_LIMIT,                                  100LL<<20 );
109 	init( PACKET_WARNING,                                  2LL<<20 );  // 2MB packet warning quietly allows for 1MB system messages
110 	init( TIME_OFFSET_LOGGING_INTERVAL,                       60.0 );
111 
112 	//Sim2
113 	init( MIN_OPEN_TIME,                                    0.0002 );
114 	init( MAX_OPEN_TIME,                                    0.0012 );
115 	init( SIM_DISK_IOPS,                                      5000 );
116 	init( SIM_DISK_BANDWIDTH,                             50000000 );
117 	init( MIN_NETWORK_LATENCY,                              100e-6 );
118 	init( FAST_NETWORK_LATENCY,                             800e-6 );
119 	init( SLOW_NETWORK_LATENCY,                             100e-3 );
120 	init( MAX_CLOGGING_LATENCY,                                  0 ); if( randomize && BUGGIFY ) MAX_CLOGGING_LATENCY =  0.1 * g_random->random01();
121 	init( MAX_BUGGIFIED_DELAY,                                   0 ); if( randomize && BUGGIFY ) MAX_BUGGIFIED_DELAY =  0.2 * g_random->random01();
122 
123 	//Tracefiles
124 	init( ZERO_LENGTH_FILE_PAD,                                  1 );
125 	init( TRACE_FLUSH_INTERVAL,                               0.25 );
126 	init( TRACE_RETRY_OPEN_INTERVAL,						  1.00 );
127 	init( MIN_TRACE_SEVERITY,                 isSimulated ? 0 : 10 ); // Related to the trace severity in Trace.h
128 	init( MAX_TRACE_SUPPRESSIONS,                              1e4 );
129 	init( TRACE_SYNC_ENABLED,                                    0 );
130 	init( TRACE_EVENT_METRIC_UNITS_PER_SAMPLE,                 500 );
131 	init( TRACE_EVENT_THROTTLER_SAMPLE_EXPIRY,              1800.0 ); // 30 mins
132 	init( TRACE_EVENT_THROTTLER_MSG_LIMIT,                   20000 );
133 
134 	//TDMetrics
135 	init( MAX_METRICS,                                         600 );
136 	init( MAX_METRIC_SIZE,                                    2500 );
137 	init( MAX_METRIC_LEVEL,                                     25 );
138 	init( METRIC_LEVEL_DIVISOR,                             log(4) );
139 	init( METRIC_LIMIT_START_QUEUE_SIZE,                        10 );  // The queue size at which to start restricting logging by disabling levels
140 	init( METRIC_LIMIT_RESPONSE_FACTOR,                         10 );  // The additional queue size at which to disable logging of another level (higher == less restrictive)
141 
142 	//Load Balancing
143 	init( LOAD_BALANCE_MAX_BACKOFF,                            5.0 );
144 	init( LOAD_BALANCE_START_BACKOFF,                         0.01 );
145 	init( LOAD_BALANCE_BACKOFF_RATE,                           2.0 );
146 	init( MAX_LAGGING_REQUESTS_OUTSTANDING,                 100000 );
147 	init( INSTANT_SECOND_REQUEST_MULTIPLIER,                   2.0 );
148 	init( BASE_SECOND_REQUEST_TIME,                         0.0005 );
149 	init( SECOND_REQUEST_MULTIPLIER_GROWTH,                   0.01 );
150 	init( SECOND_REQUEST_MULTIPLIER_DECAY,                 0.00025 );
151 	init( SECOND_REQUEST_BUDGET_GROWTH,                       0.05 );
152 	init( SECOND_REQUEST_MAX_BUDGET,                         100.0 );
153 	init( ALTERNATIVES_FAILURE_RESET_TIME,                     5.0 );
154 	init( ALTERNATIVES_FAILURE_MAX_DELAY,                      1.0 );
155 	init( ALTERNATIVES_FAILURE_MIN_DELAY,                     0.05 );
156 	init( ALTERNATIVES_FAILURE_DELAY_RATIO,                    0.2 );
157 	init( FUTURE_VERSION_INITIAL_BACKOFF,                      1.0 );
158 	init( FUTURE_VERSION_MAX_BACKOFF,                          8.0 );
159 	init( FUTURE_VERSION_BACKOFF_GROWTH,                       2.0 );
160 }
161 
setKnob(std::string const & knob,std::string const & value)162 bool Knobs::setKnob( std::string const& knob, std::string const& value ) {
163 	if (double_knobs.count(knob)) {
164 		double v;
165 		int n=0;
166 		if (sscanf(value.c_str(), "%lf%n", &v, &n) != 1 || n != value.size())
167 			throw invalid_option_value();
168 		*double_knobs[knob] = v;
169 		return true;
170 	}
171 	if (int64_knobs.count(knob) || int_knobs.count(knob)) {
172 		int64_t v;
173 		int n=0;
174 		if (StringRef(value).startsWith(LiteralStringRef("0x"))) {
175 			if (sscanf(value.c_str(), "0x%llx%n", &v, &n) != 1 || n != value.size())
176 				throw invalid_option_value();
177 		} else {
178 			if (sscanf(value.c_str(), "%lld%n", &v, &n) != 1 || n != value.size())
179 				throw invalid_option_value();
180 		}
181 		if (int64_knobs.count(knob))
182 			*int64_knobs[knob] = v;
183 		else {
184 			if ( v < std::numeric_limits<int>::min() || v > std::numeric_limits<int>::max() )
185 				throw invalid_option_value();
186 			*int_knobs[knob] = v;
187 		}
188 		return true;
189 	}
190 	if (string_knobs.count(knob)) {
191 		*string_knobs[knob] = value;
192 		return true;
193 	}
194 	return false;
195 }
196 
toLower(std::string const & name)197 static std::string toLower( std::string const& name ) {
198 	std::string lower_name;
199 	for(auto c = name.begin(); c != name.end(); ++c)
200 		if (*c >= 'A' && *c <= 'Z')
201 			lower_name += *c - 'A' + 'a';
202 		else
203 			lower_name += *c;
204 	return lower_name;
205 }
206 
initKnob(double & knob,double value,std::string const & name)207 void Knobs::initKnob( double& knob, double value, std::string const& name ) {
208 	knob = value;
209 	double_knobs[toLower(name)] = &knob;
210 }
211 
initKnob(int64_t & knob,int64_t value,std::string const & name)212 void Knobs::initKnob( int64_t& knob, int64_t value, std::string const& name ) {
213 	knob = value;
214 	int64_knobs[toLower(name)] = &knob;
215 }
216 
initKnob(int & knob,int value,std::string const & name)217 void Knobs::initKnob( int& knob, int value, std::string const& name ) {
218 	knob = value;
219 	int_knobs[toLower(name)] = &knob;
220 }
221 
initKnob(std::string & knob,const std::string & value,const std::string & name)222 void Knobs::initKnob( std::string& knob, const std::string& value, const std::string& name ) {
223 	knob = value;
224 	string_knobs[toLower(name)] = &knob;
225 }
226 
trace()227 void Knobs::trace() {
228 	for(auto &k : double_knobs)
229 		TraceEvent("Knob").detail("Name", k.first.c_str()).detail("Value", *k.second);
230 	for(auto &k : int_knobs)
231 		TraceEvent("Knob").detail("Name", k.first.c_str()).detail("Value", *k.second);
232 	for(auto &k : int64_knobs)
233 		TraceEvent("Knob").detail("Name", k.first.c_str()).detail("Value", *k.second);
234 	for(auto &k : string_knobs)
235 		TraceEvent("Knob").detail("Name", k.first.c_str()).detail("Value", *k.second);
236 }
237