String concatenations that assign their result to an operand of the concatenation are significantly slower than those that do not
i.e.:
result = a; result += b
and
result = a; result = "[result][b]"
are significantly slower (~50% slower for 2-character strings, 13x slower for 400-character strings) than:
result = a + b
and
result = "[a][b]"
Numbered Steps to Reproduce Problem:
- Write two string concatenations concatenating long strings; one result = s1 + s2, and one result = s1; result += s2, where s1 and s2 are relatively long (~200+ character) strings.
- Execute both
- Observe that result = s1; result += s2 is approximately 50% slower for very small strings, 6x slower for 128-char strings, and 13x slower for 400-char strings.
Code Snippet (if applicable) to Reproduce Problem:
/world/loop_checks = 0
#define BENCHTK(NAME, ITERS, CODE) do{ var/s = world.tick_usage; for(var/j = 1 to 1000) { for(var/i = 1 to (ITERS)) { CODE ; } ; } ; var/e = world.tick_usage; world.log << "[NAME]:[(e-s) * world.tick_lag] ms"; } while(0)
// 400 chars each. The strings are just random data base64'd.
var/s1 = "oRmfshgsduoMKt8gsN0GybDdINIc0dpBJPHt9Vw9VoBabSXyPIs+JdUcyINr8fqpjAeR9tzbeYaozMwSC7VyppWMEozQCGNF53anE1+SfmNh7GnaeykB71atgYxtQv7lwlxjaLNAbjxP5fzhGIowVn5ZFNrigejPQ4o1yc1A7pjGCgRvo0cQKYQqcXOGLoZNfouWIogmZq7rblh8eENG/yjPE+Z7GL31h4fqzjm+KmwOs5esvT/N6vP+wCK2jM+6d3MvnmLMLZfDPaPwpxQJC0XnpAuEL26mnDqgQ9DSp8FellF/wgFdMakRiUuzSovfO6hQkkF8IZOrzvWttIql/jXjEApu0Rvr/RyPWGFtqrLJqsSAgil5QZ3yacd+pNzYVmERk+BQza+S+aXP"
var/s2 = "owfqYceSPQtxG+43xKoEY3qw9+QT20qhQhTV9A96Q7e4h4oI0CkUurrdMi4xcchjZzObFb4WD+wUmm8+Sf+R1K56Kh6ip72M/P/oi9cPSx7gNUJ5QSKwi8rvgvR3jETVPfo/vrWLuSeNWHGU6BNZwuSa7zbt/Of93bqUYPlSp4kSLWFhcoftj7jE9vYGRY9xUhaiwHBonVAh9CujM3MHqfJPsKc55j4n6zbbr+RVEAqaZM8kiVBXHl0V2Y1SS5ZXmyiOCoiE6kgVqBVJMNxxbnJJo02tIWgUDq+EsB0nlQ8Rpiy4MqX+ermXfrQib8UsXrJtfmc09wQcRwQgzTZ+0HCQD1F8jRA5NZLTwsD/io5tFd8/53crL3uyF7VlrINcw/n/GQR2IB4TtP0o"
/world/New()
BENCHTK("plus1", 5000, r = s1 + s2) // Straight concat. 1.68s
BENCHTK("embed1", 5000, r = "[s1][s2]") // Embedded strings. 1.90s
BENCHTK("join1", 5000, r = jointext(list(s1,s2),null)) // jointext. 3.84s
BENCHTK("plusM", 5000, r = s1; r += s2) // Straight concat, in-place. 22.5s (13.4x)
BENCHTK("embedM", 5000, r = s1; r = "[r][s2]") // Embedded strings, in-place. 24.4s (12.8x)
BENCHTK("joinM", 5000, r = list(s1); r += s2; r = jointext(r,null)) // jointext, in-place. 27.0s (7.0x)
Expected Results:
r = s1 + s2 and r = s1; r += s2 to be approximately equivalent
r = "[s1][s2]" and r = s1; r = "[r][s2]" to be approximately equivalent
Actual Results:
128-char | 400-char | |
r = s1 + s2 | 1346ms | 1683ms |
r = s1; r += s2 | 8247ms | 22498ms |
r = "[s1][s2]" | 1565ms | 1901ms |
r = s1; r = "[r][s2]" | 9348ms | 24417ms |
Additionally, r = s1; r = r + s2 is approximately 2.5x slower than r = s1; r += s2.
Does the problem occur:
Every time? Or how often? Every time
In other games? Yes
In other user accounts? Yes
On other computers? Yes
When does the problem NOT occur? When you don't put the resulting string into the variable you're concatenating from.
Did the problem NOT occur in any earlier versions? If so, what was the last version that worked?
Workarounds: Don't reuse a variable to hold the result of your string concatenation?