Add benchmark for saved state performance
- Introduced `benchmark_saved_state.gd` to evaluate the performance of the saved state restoration process. - Implemented JSON integer restoration to handle large integers accurately. - Added command-line argument parsing for specifying the path to the diagnostic JSON file and optional delta seconds. - Conducted performance tests at different speeds and logged the elapsed time for six consecutive steps. - Created a new UID file for the benchmark script.
This commit is contained in:
@@ -62,6 +62,7 @@ static func multiply(a: Array, b: Array) -> Array:
|
||||
|
||||
static func divmod(a: Array, b: Array) -> Array:
|
||||
assert(b != [0], "Division by zero")
|
||||
if b == [1]: return [a.duplicate(), [0]]
|
||||
if compare(a, b) < 0: return [[0], a.duplicate()]
|
||||
if b.size() == 1:
|
||||
var quotient: Array = []
|
||||
@@ -96,6 +97,7 @@ static func divmod(a: Array, b: Array) -> Array:
|
||||
|
||||
static func gcd(a: Array, b: Array) -> Array:
|
||||
while b != [0]:
|
||||
if b == [1]: return [1]
|
||||
var remainder: Array = divmod(a, b)[1]
|
||||
a = b
|
||||
b = remainder
|
||||
|
||||
@@ -14,6 +14,11 @@ static func make(n: Array, d: Array = [1], polarity: int = 1):
|
||||
var common: Array = Big.gcd(n, d)
|
||||
n = Big.divmod(n, common)[0]
|
||||
d = Big.divmod(d, common)[0]
|
||||
return _make_reduced(n, d, polarity)
|
||||
|
||||
## Internal: operands already reduced; do not repeat Euclid's algorithm.
|
||||
static func _make_reduced(n: Array, d: Array, polarity: int):
|
||||
if n == [0]: return 0
|
||||
if d == [1] and (n.size() == 1 or (n.size() == 2 and n[1] < SMALL)):
|
||||
return polarity * (n[0] + (n[1] * SMALL if n.size() == 2 else 0))
|
||||
if d == [1] and n.size() == 3:
|
||||
@@ -139,9 +144,18 @@ static func add(a, b):
|
||||
var left: Array = Big.multiply(x[0], yd)
|
||||
var right: Array = Big.multiply(y[0], xd)
|
||||
var denominator: Array = Big.multiply(xd, y[1])
|
||||
if x[2] == y[2]: return make(Big.add(left, right), denominator, x[2])
|
||||
var order: int = Big.compare(left, right)
|
||||
return make(Big.subtract(left, right) if order >= 0 else Big.subtract(right, left), denominator, x[2] if order >= 0 else y[2])
|
||||
var numerator: Array
|
||||
var polarity: int = x[2]
|
||||
if x[2] == y[2]:
|
||||
numerator = Big.add(left, right)
|
||||
else:
|
||||
var order: int = Big.compare(left, right)
|
||||
numerator = Big.subtract(left, right) if order >= 0 else Big.subtract(right, left)
|
||||
polarity = x[2] if order >= 0 else y[2]
|
||||
# Reduced inputs can only share a remaining factor from gcd(d1, d2).
|
||||
# Testing the entire new denominator repeats expensive long division.
|
||||
var reduction: Array = Big.gcd(numerator, common)
|
||||
return _make_reduced(Big.divmod(numerator, reduction)[0], Big.divmod(denominator, reduction)[0], polarity)
|
||||
|
||||
static func subtract(a, b):
|
||||
if not numeric(a) or not numeric(b): return a - b
|
||||
@@ -150,7 +164,7 @@ static func subtract(a, b):
|
||||
if not finite(a) or not finite(b): return approx(a) - approx(b)
|
||||
if b is int and b == 0: return of(a)
|
||||
var y: Array = parts(b)
|
||||
return add(a, make(y[0], y[1], -y[2]))
|
||||
return add(a, _make_reduced(y[0], y[1], -y[2]))
|
||||
|
||||
static func multiply(a, b):
|
||||
if not numeric(a) or not numeric(b): return a * b
|
||||
@@ -164,7 +178,7 @@ static func multiply(a, b):
|
||||
var y: Array = parts(b)
|
||||
var g1: Array = Big.gcd(x[0], y[1])
|
||||
var g2: Array = Big.gcd(y[0], x[1])
|
||||
return make(Big.multiply(Big.divmod(x[0], g1)[0], Big.divmod(y[0], g2)[0]), Big.multiply(Big.divmod(x[1], g2)[0], Big.divmod(y[1], g1)[0]), x[2] * y[2])
|
||||
return _make_reduced(Big.multiply(Big.divmod(x[0], g1)[0], Big.divmod(y[0], g2)[0]), Big.multiply(Big.divmod(x[1], g2)[0], Big.divmod(y[1], g1)[0]), x[2] * y[2])
|
||||
|
||||
static func divide(a, b):
|
||||
if not numeric(a) or not numeric(b): return a / b
|
||||
@@ -174,7 +188,7 @@ static func divide(a, b):
|
||||
if a % b == 0: return a / b
|
||||
var y: Array = parts(b)
|
||||
assert(y[0] != [0], "Exact division by zero")
|
||||
return multiply(a, make(y[1], y[0], y[2]))
|
||||
return multiply(a, _make_reduced(y[1], y[0], y[2]))
|
||||
|
||||
static func floor_value(a):
|
||||
if not finite(a): return a
|
||||
|
||||
@@ -55,12 +55,26 @@ func append_batch(target: Dictionary, id: String, amount: Variant, created_from:
|
||||
if E.le(E.add(origin, E.multiply((E.add(window_index, 1)), batch_duration)), cursor):
|
||||
window_index = E.add(window_index, 1)
|
||||
var batches_by_start: Dictionary = {}
|
||||
var skip_empty_expired: bool = E.gt(duration, 0) and E.finite(completed_before) and E.eq(amount, E.floor_value(amount))
|
||||
for existing : Dictionary in batches:
|
||||
var start: Variant = existing.get("created_from", E.neg(INF))
|
||||
if (not batches_by_start.has(str(start))):
|
||||
batches_by_start[str(start)] = []
|
||||
batches_by_start[str(start)].append(existing)
|
||||
while true:
|
||||
# Whole allocation changes only when its cumulative quota reaches the
|
||||
# next integer. Skip expired empty windows without changing the span
|
||||
# passed to the next generation or the lifetime production integral.
|
||||
if skip_empty_expired:
|
||||
var threshold = E.add(created_from, E.divide(E.multiply(duration, E.add(E.subtract(amount, remaining_amount), 1)), amount))
|
||||
var next_nonempty = E.subtract(E.ceil_value(E.divide(E.subtract(threshold, origin), batch_duration)), 1)
|
||||
var expired_end = E.floor_value(E.divide(E.subtract(E.subtract(completed_before, lifespan), origin), batch_duration))
|
||||
var skip_to = E.minimum(next_nonempty, expired_end)
|
||||
if E.gt(skip_to, window_index):
|
||||
completed_from = E.minimum(completed_from, E.add(E.add(origin, E.multiply(window_index, batch_duration)), lifespan))
|
||||
completed_to = E.maximum(completed_to, E.add(E.add(origin, E.multiply(skip_to, batch_duration)), lifespan))
|
||||
window_index = skip_to
|
||||
cursor = E.add(origin, E.multiply(window_index, batch_duration))
|
||||
var window_start: Variant = E.add(origin, E.multiply(window_index, batch_duration))
|
||||
var window_end: Variant = E.add(origin, E.multiply((E.add(window_index, 1)), batch_duration))
|
||||
if E.le(window_end, cursor):
|
||||
|
||||
@@ -1110,6 +1110,10 @@ autostart = true
|
||||
wait_time = 2.0
|
||||
autostart = true
|
||||
|
||||
[node name="FXPlayer" type="AudioStreamPlayer" parent="." unique_id=1306204231]
|
||||
|
||||
[node name="MusicPlayer" type="AudioStreamPlayer" parent="." unique_id=707734847]
|
||||
|
||||
[connection signal="timeout" from="Background/Timer" to="Background" method="randomize_parallax"]
|
||||
[connection signal="pressed" from="Stage/World/TopMenu/BurgerButton" to="Stage" method="_on_topmenu_button_pressed" binds= ["MainMenu"]]
|
||||
[connection signal="pressed" from="Stage/World/TopMenu/TimeMinus" to="Stage" method="_change_speed" binds= [-1]]
|
||||
|
||||
Reference in New Issue
Block a user