Skip to content

Improve string.end/start with function performance#2406

Open
wrefgtzweve wants to merge 4 commits intoFacepunch:masterfrom
wrefgtzweve:patch-4
Open

Improve string.end/start with function performance#2406
wrefgtzweve wants to merge 4 commits intoFacepunch:masterfrom
wrefgtzweve:patch-4

Conversation

@wrefgtzweve
Copy link
Contributor

Improves the speed of string.StartsWith and string.EndsWith

local string = string

local function EndsWith( str, endStr )

	      return endStr == "" or string.sub( str, -string.len( endStr ) ) == endStr

end

local function EndsWith2(str, suffix)
    local n = #suffix
    return n == 0 or string.sub(str, -n) == suffix
end

local math_random = math.random
local string_char = string.char
local table_concat = table.concat
local function randomString()
    local strTbl = {}
    for i = 1, math_random( 32, 64 ) do
        strTbl[i] = math_random( 65, 122 )
    end

    return table_concat( strTbl )
end

local str1 = randomString()
local str2 = randomString()

GMN.TestCompare(
function()
    return EndsWith2( str1, str2 )
end,
function()
    return EndsWith( str1, str2 )
end,
100000
)

Test lib https://github.com/CFC-Servers/gm_nitrous/blob/main/lua/nitrous/utils/testlib.lua

[GMN] Starting test..
[GMN] Ran 100000 iterations of each test.
1 JIT ON took 0.01236259999996 seconds, average: 1.236259999996e-07 seconds, garbage collected: 1 KB
2 JIT ON took 0.005109100000027 seconds, average: 5.109100000027e-08 seconds, garbage collected: 2 KB
1 JIT OFF took 0.008799000000181 seconds, average: 8.799000000181e-08 seconds, garbage collected: 0 KB
2 JIT OFF took 0.0097935999997389 seconds, average: 9.7935999997389e-08 seconds, garbage collected: 0 KB
JIT ON 2 is 141.972% faster than test 1
JIT OFF 1 is 11.304% faster than test 2
JIT ON tests produced different garbage amounts: 1 KB vs 2 KB

@wrefgtzweve wrefgtzweve marked this pull request as draft December 10, 2025 12:47
@wrefgtzweve wrefgtzweve marked this pull request as ready for review December 10, 2025 12:56
@robotboy655 robotboy655 added the Enhancement The pull request enhances current functionality. label Dec 12, 2025
@robotboy655
Copy link
Collaborator

Uh, I am a bit confused. Your own tests show 140% slowdown that the proposed changes would create? (with JIT on, the default)

In your test code test 1 is your new implementation, and test 2 is old implementation.

With my own testing, it seems to be extremely inconsistent, and between +-1% faster/slower for string.EndsWith and ~40% slower for StartsWith.

Replacing the input strings with your randomString() does seem to show a consistent improvement though.

Code used for testing
function string.StartsWithOld( str, start )
	return string.sub( str, 1, string.len( start ) ) == start
end

function string.EndsWithOld( str, endStr )
	return endStr == "" or string.sub( str, -string.len( endStr ) ) == endStr
end

function string.StartsWithNew( str, start )
	local n = #start
    return n == 0 or string.sub(str, 1, n) == start
end

function string.EndsWithNew( str, endStr )
    local n = #endStr
    return n == 0 or string.sub(str, -n) == endStr
end

local count = 10000000
local strings = {
	"testing", "te",
	"testing", "da",
	"testing", "",
	"test", "",
	"fuck", "ck",
	"dadaodjnaiduahioduhaidouhadg", "da",
}

local StartTime = SysTime()

for i = 1, count do
	local id1 = ( ( i * 2 ) - 1 ) % (#strings)
	string.StartsWithOld( strings[ id1 ], strings[ id1 + 1 ] )
	//string.ExplodeOld( " ", "test test test" )
end

local OldTotal =  SysTime() - StartTime

print("Old: " .. OldTotal .. " seconds.")



 

local StartTime = SysTime()

for i = 1, count do
	local id1 = ( ( i * 2 ) - 1 ) % (#strings)
	string.StartsWithNew( strings[ id1 ], strings[ id1 + 1 ] )
	//string.Explode( " ", "test test test" )
end

local NewTotal = SysTime()- StartTime

print("New: " .. NewTotal .. " seconds. ")

if ( NewTotal > OldTotal ) then
	MsgN("New is " .. math.Round( ( NewTotal - OldTotal ) / OldTotal * 100, 3	), "% slower than old" )
else
	MsgN("New is " .. math.Round( ( OldTotal - NewTotal ) / NewTotal * 100, 3 ), "% faster than old" )
end


end )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement The pull request enhances current functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants