├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── aftman.toml ├── default.project.json ├── selene.toml ├── sourcemap.json ├── src ├── ArrayClone.bench.lua ├── ArrayFill.bench.lua ├── ArrayIteration.bench.lua ├── ArrayRemoval.bench.lua ├── ArraySearch.bench.lua ├── BeginnerTemplate.bench.lua ├── RandomInt.bench.lua ├── TableClear.bench.lua ├── TableCreation.bench.lua ├── Template.bench.lua └── init.lua └── wally.toml /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened, synchronize, ready_for_review] 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | Code-Quality: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Aftman installation 18 | uses: ok-nick/setup-aftman@v0.3.0 19 | with: 20 | token: ${{ secrets.GITHUB_TOKEN }} 21 | version: 'v0.2.7' 22 | 23 | - name: Format 24 | shell: bash 25 | run: stylua src --check 26 | 27 | - name: Lint 28 | shell: bash 29 | run: selene src 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **.rbxm 2 | **.rbxmx 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 boatbomber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BenchmarkerLibrary 2 | A collection of bench files for my Benchmarker plugin 3 | 4 | Get Benchmarker here: [boatbomber.itch.io/benchmarker](https://boatbomber.itch.io/benchmarker) 5 | 6 | ## Contributing 7 | 8 | Create a new bench file by copying `src/Template.bench.lua`. Add an entry to Index for the new bench. Open a PR. 9 | By contributing code, you agree that your contibutions are licensed under the same license as this repo. 10 | -------------------------------------------------------------------------------- /aftman.toml: -------------------------------------------------------------------------------- 1 | # This file lists tools managed by Aftman, a cross-platform toolchain manager. 2 | # For more information, see https://github.com/LPGhatguy/aftman 3 | 4 | # To add a new tool, add an entry to this table. 5 | [tools] 6 | rojo = "rojo-rbx/rojo@7.2.0" 7 | run-in-roblox = "rojo-rbx/run-in-roblox@0.3.0" 8 | wally = "upliftgames/wally@0.3.1" 9 | selene = "Kampfkarren/selene@0.25.0" 10 | stylua = "JohnnyMorganz/stylua@0.17.1" 11 | -------------------------------------------------------------------------------- /default.project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Library", 3 | "tree": { 4 | "$path": "src" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /selene.toml: -------------------------------------------------------------------------------- 1 | std = "roblox" 2 | 3 | [lints] 4 | unused_variable = "allow" # Templates provide nice variables for users to tinker with 5 | -------------------------------------------------------------------------------- /sourcemap.json: -------------------------------------------------------------------------------- 1 | {"name":"Library","className":"Folder","filePaths":["default.project.json"],"children":[{"name":"ArrayClone.bench","className":"ModuleScript","filePaths":["src\\ArrayClone.bench.lua"]},{"name":"ArrayFill.bench","className":"ModuleScript","filePaths":["src\\ArrayFill.bench.lua"]},{"name":"ArrayIteration.bench","className":"ModuleScript","filePaths":["src\\ArrayIteration.bench.lua"]},{"name":"ArrayRemoval.bench","className":"ModuleScript","filePaths":["src\\ArrayRemoval.bench.lua"]},{"name":"ArraySearch.bench","className":"ModuleScript","filePaths":["src\\ArraySearch.bench.lua"]},{"name":"BeginnerTemplate.bench","className":"ModuleScript","filePaths":["src\\BeginnerTemplate.bench.lua"]},{"name":"RandomInt.bench","className":"ModuleScript","filePaths":["src\\RandomInt.bench.lua"]},{"name":"TableClear.bench","className":"ModuleScript","filePaths":["src\\TableClear.bench.lua"]},{"name":"TableCreation.bench","className":"ModuleScript","filePaths":["src\\TableCreation.bench.lua"]},{"name":"Template.bench","className":"ModuleScript","filePaths":["src\\Template.bench.lua"]},{"name":"_Index","className":"ModuleScript","filePaths":["src\\_Index.lua"]}]} -------------------------------------------------------------------------------- /src/ArrayClone.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local ARRAY_SIZE = 3000 8 | 9 | return { 10 | ParameterGenerator = function() 11 | local arr = table.create(ARRAY_SIZE) 12 | for i = 1, ARRAY_SIZE do 13 | arr[i] = math.random(10000) 14 | end 15 | return table.freeze(arr) 16 | end, 17 | 18 | Functions = { 19 | ["table.clone"] = function(Profiler, arr) 20 | local copy = table.clone(arr) 21 | end, 22 | 23 | ["table.move"] = function(Profiler, arr) 24 | Profiler.Begin("length") 25 | local len = #arr 26 | Profiler.End() 27 | 28 | Profiler.Begin("create") 29 | local copy = table.create(len) 30 | Profiler.End() 31 | 32 | Profiler.Begin("move") 33 | table.move(arr, 1, len, 1, copy) 34 | Profiler.End() 35 | end, 36 | 37 | ["gen-iter"] = function(Profiler, arr) 38 | Profiler.Begin("create") 39 | local copy = table.create(#arr) 40 | Profiler.End() 41 | Profiler.Begin("iter") 42 | for k, v in arr do 43 | copy[k] = v 44 | end 45 | Profiler.End() 46 | end, 47 | 48 | ["numeric-iter"] = function(Profiler, arr) 49 | Profiler.Begin("create") 50 | local copy = table.create(#arr) 51 | Profiler.End() 52 | Profiler.Begin("iter") 53 | for i = 1, #arr do 54 | copy[i] = arr[i] 55 | end 56 | Profiler.End() 57 | end, 58 | 59 | ["table.unpack"] = function(Profiler, arr) 60 | local copy = { table.unpack(arr) } 61 | end, 62 | }, 63 | } 64 | -------------------------------------------------------------------------------- /src/ArrayFill.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local ARRAY_SIZE = 3000 8 | 9 | return { 10 | ParameterGenerator = function() 11 | return 12 | end, 13 | 14 | Functions = { 15 | ["t[i]"] = function(Profiler) 16 | Profiler.Begin("create") 17 | local arr = table.create(ARRAY_SIZE) 18 | Profiler.End() 19 | Profiler.Begin("fill") 20 | for i = 1, ARRAY_SIZE do 21 | arr[i] = math.random(10000) 22 | end 23 | Profiler.End() 24 | end, 25 | 26 | ["table.insert"] = function(Profiler) 27 | Profiler.Begin("create") 28 | local arr = table.create(ARRAY_SIZE) 29 | Profiler.End() 30 | Profiler.Begin("fill") 31 | for i = 1, ARRAY_SIZE do 32 | table.insert(arr, math.random(10000)) 33 | end 34 | Profiler.End() 35 | end, 36 | 37 | ["t[#t+1]"] = function(Profiler) 38 | Profiler.Begin("create") 39 | local arr = table.create(ARRAY_SIZE) 40 | Profiler.End() 41 | Profiler.Begin("fill") 42 | for i = 1, ARRAY_SIZE do 43 | arr[#arr + 1] = math.random(10000) 44 | end 45 | Profiler.End() 46 | end, 47 | }, 48 | } 49 | -------------------------------------------------------------------------------- /src/ArrayIteration.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local ARRAY_SIZE = 3000 8 | 9 | local __ipairs = ipairs 10 | local __pairs = pairs 11 | local __next = next 12 | 13 | return { 14 | ParameterGenerator = function() 15 | local len = math.random(ARRAY_SIZE * 0.7, ARRAY_SIZE * 1.3) 16 | return table.create(len, math.random(10)), len 17 | end, 18 | 19 | Functions = { 20 | ["gen-iter"] = function(Profiler, arr) 21 | for Index, Value in arr do 22 | local _ = Index + Value 23 | end 24 | end, 25 | 26 | ["ipairs"] = function(Profiler, arr) 27 | for Index, Value in ipairs(arr) do 28 | local _ = Index + Value 29 | end 30 | end, 31 | 32 | ["local ipairs"] = function(Profiler, arr) 33 | for Index, Value in __ipairs(arr) do 34 | local _ = Index + Value 35 | end 36 | end, 37 | 38 | ["pairs"] = function(Profiler, arr) 39 | for Index, Value in pairs(arr) do 40 | local _ = Index + Value 41 | end 42 | end, 43 | 44 | ["local pairs"] = function(Profiler, arr) 45 | for Index, Value in __pairs(arr) do 46 | local _ = Index + Value 47 | end 48 | end, 49 | 50 | ["next"] = function(Profiler, arr) 51 | for Index, Value in next, arr do 52 | local _ = Index + Value 53 | end 54 | end, 55 | 56 | ["local next"] = function(Profiler, arr) 57 | for Index, Value in __next, arr do 58 | local _ = Index + Value 59 | end 60 | end, 61 | 62 | ["numeric #length"] = function(Profiler, arr) 63 | for Index = 1, #arr do 64 | local Value = arr[Index] 65 | local _ = Index + Value 66 | end 67 | end, 68 | 69 | ["numeric given Length"] = function(Profiler, arr, Length) 70 | for Index = 1, Length do 71 | local Value = arr[Index] 72 | local _ = Index + Value 73 | end 74 | end, 75 | }, 76 | } 77 | -------------------------------------------------------------------------------- /src/ArrayRemoval.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local N = 5000 8 | 9 | return { 10 | ParameterGenerator = function() 11 | local Length = math.random(N * 0.7, N * 1.3) 12 | return table.create(Length, 1), Length 13 | end, 14 | 15 | Functions = { 16 | ["table.remove"] = function(Profiler, Array, Length) 17 | -- Removes in O(n) by removing the element and shifting all subsequent elements 18 | for Index = Length, 1, -1 do 19 | table.remove(Array, Index) 20 | end 21 | end, 22 | 23 | ["unordered remove"] = function(Profiler_, Array, Length) 24 | -- Removes in O(1) by moving the last element to your remove index (which loses order) 25 | 26 | local CurrentLength = Length 27 | 28 | for Index = Length, 1, -1 do 29 | Array[Index] = Array[CurrentLength] 30 | Array[CurrentLength] = nil 31 | CurrentLength -= 1 32 | end 33 | end, 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /src/ArraySearch.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local N = 1000 8 | 9 | local function BinarySearch(Array, Value) 10 | local Low = 1 11 | local High = #Array 12 | 13 | while Low <= High do 14 | local Middle = Low + math.floor((High - Low) / 2) 15 | local MiddleValue = Array[Middle] 16 | 17 | if Value < MiddleValue then 18 | High = Middle - 1 19 | elseif MiddleValue < Value then 20 | Low = Middle + 1 21 | else 22 | while Middle >= 1 and not (Array[Middle] < Value or Value < Array[Middle]) do 23 | Middle -= 1 24 | end 25 | 26 | return Middle + 1 27 | end 28 | end 29 | 30 | return nil 31 | end 32 | 33 | return { 34 | ParameterGenerator = function() 35 | local Length = math.random(N * 0.7, N * 1.3) 36 | local Array = table.create(Length) 37 | for Index = 1, Length do 38 | Array[Index] = Index 39 | end 40 | 41 | return Array, math.random(Length) 42 | end, 43 | 44 | Functions = { 45 | ["binary search"] = function(Profiler, Array, Index) 46 | for i = 1, 100 do 47 | local idx = BinarySearch(Array, Index) 48 | end 49 | end, 50 | 51 | ["table.find"] = function(Profiler, Array, Index) 52 | for i = 1, 100 do 53 | local idx = table.find(Array, Index) 54 | end 55 | end, 56 | }, 57 | } 58 | -------------------------------------------------------------------------------- /src/BeginnerTemplate.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | You may alter workspace, DataStores, etc. This is useful for testing 6 | the performance of functions that interact with the game environment, 7 | but be careful! 8 | --]] 9 | 10 | return { 11 | ParameterGenerator = function() 12 | -- This function is called before running your function (outside the timer) 13 | -- and the return(s) are passed into your function arguments (after the Profiler). This sample 14 | -- will pass the function a random number, but you can make it pass 15 | -- arrays, Vector3s, or anything else you want to test your function on. 16 | return math.random(1000) / 10 17 | end, 18 | 19 | -- This is called once, before running all your functions 20 | BeforeAll = function() end, 21 | -- This is called once, after running all your functions 22 | AfterAll = function() end, 23 | -- This is called right before your function, each time the function is called 24 | BeforeEach = function() end, 25 | -- This is called right after your function, each time the function is called 26 | AfterEach = function() end, 27 | 28 | Functions = { 29 | ["Function A"] = function(Profiler, RandomNumber) -- You can change "Function A" to a descriptive name for your function 30 | 31 | -- The first argument passed is always our Profiler tool, so you can put 32 | -- Profiler.Begin("UNIQUE_LABEL_NAME") ... Profiler.End() around portions of your code 33 | -- to break your function into labels that are viewable under the results 34 | -- histogram graph to see what parts of your function take the most time. 35 | 36 | -- Your code here 37 | end, 38 | 39 | ["Function B"] = function(Profiler, RandomNumber) end, 40 | 41 | -- You can add as many functions as you like! 42 | }, 43 | } 44 | -------------------------------------------------------------------------------- /src/RandomInt.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local N = 1000 8 | local SEED = 10 9 | math.randomseed(SEED) 10 | 11 | local RandomObj = Random.new(SEED) 12 | local NextInteger = RandomObj.NextInteger 13 | local LocalMathRandom = math.random 14 | 15 | local LengthPlusOne = N + 1 16 | 17 | return { 18 | ParameterGenerator = function() 19 | return 20 | end, 21 | 22 | Functions = { 23 | ["Random:NextInteger"] = function(Profiler) 24 | for Index = 1, N do 25 | local int = RandomObj:NextInteger(Index, LengthPlusOne) 26 | end 27 | end, 28 | 29 | ["local NextInteger"] = function(Profiler) 30 | for Index = 1, N do 31 | local int = NextInteger(RandomObj, Index, LengthPlusOne) 32 | end 33 | end, 34 | 35 | ["math.random"] = function(Profiler) 36 | for Index = 1, N do 37 | local int = math.random(Index, LengthPlusOne) 38 | end 39 | end, 40 | 41 | ["local math.random"] = function(Profiler) 42 | for Index = 1, N do 43 | local int = LocalMathRandom(Index, LengthPlusOne) 44 | end 45 | end, 46 | }, 47 | } 48 | -------------------------------------------------------------------------------- /src/TableClear.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local N = 5000 8 | 9 | return { 10 | ParameterGenerator = function() 11 | return table.create(N, math.random(10)) 12 | end, 13 | 14 | Functions = { 15 | ["table.clear()"] = function(Profiler, t) 16 | table.clear(t) 17 | end, 18 | 19 | ["t[key] = nil"] = function(Profiler, t) 20 | for key in t do 21 | t[key] = nil 22 | end 23 | end, 24 | 25 | ["numeric nil"] = function(Profiler, t) 26 | -- Only works on arrays 27 | for i = #t, 1, -1 do 28 | t[i] = nil 29 | end 30 | end, 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /src/TableCreation.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | local N = 5000 8 | 9 | return { 10 | ParameterGenerator = function() 11 | return math.random(1000) / 10 12 | end, 13 | 14 | Functions = { 15 | ["table.create()"] = function(Profiler, RandomNumber) 16 | Profiler.Begin("init") 17 | local t = table.create(N) 18 | Profiler.End() 19 | 20 | Profiler.Begin("fill") 21 | for i = 1, N do 22 | t[i] = RandomNumber 23 | end 24 | Profiler.End() 25 | end, 26 | 27 | ["t = {}"] = function(Profiler, RandomNumber) 28 | Profiler.Begin("init") 29 | local t = {} 30 | Profiler.End() 31 | 32 | Profiler.Begin("fill") 33 | for i = 1, N do 34 | t[i] = RandomNumber 35 | end 36 | Profiler.End() 37 | end, 38 | }, 39 | } 40 | -------------------------------------------------------------------------------- /src/Template.bench.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | This file is for use by Benchmarker (https://boatbomber.itch.io/benchmarker) 3 | 4 | |WARNING| THIS RUNS IN YOUR REAL ENVIRONMENT. |WARNING| 5 | --]] 6 | 7 | return { 8 | ParameterGenerator = function() 9 | return 10 | end, 11 | 12 | BeforeAll = function() end, 13 | AfterAll = function() end, 14 | BeforeEach = function() end, 15 | AfterEach = function() end, 16 | 17 | Functions = { 18 | ["A"] = function(Profiler) end, 19 | 20 | ["B"] = function(Profiler) end, 21 | }, 22 | } 23 | -------------------------------------------------------------------------------- /src/init.lua: -------------------------------------------------------------------------------- 1 | local Index = { 2 | ["BeginnerTemplate.bench"] = { 3 | LayoutOrder = 1, 4 | Description = "A bench template with a guide for beginners", 5 | RunOnInsert = false, 6 | }, 7 | ["Template.bench"] = { 8 | LayoutOrder = 2, 9 | Description = "Default bench template", 10 | RunOnInsert = false, 11 | }, 12 | ["TableCreation.bench"] = { 13 | LayoutOrder = 3, 14 | Description = "Compare methods of creating a new table", 15 | RunOnInsert = true, 16 | }, 17 | ["TableClear.bench"] = { 18 | LayoutOrder = 4, 19 | Description = "Compare methods of emptying a table", 20 | RunOnInsert = true, 21 | }, 22 | ["ArrayClone.bench"] = { 23 | LayoutOrder = 5, 24 | Description = "Compare methods of cloning an array", 25 | RunOnInsert = true, 26 | }, 27 | ["ArrayFill.bench"] = { 28 | LayoutOrder = 6, 29 | Description = "Compare methods of filling an array", 30 | RunOnInsert = true, 31 | }, 32 | ["ArrayRemoval.bench"] = { 33 | LayoutOrder = 7, 34 | Description = "Compare methods of removing elements from an array", 35 | RunOnInsert = true, 36 | }, 37 | ["ArraySearch.bench"] = { 38 | LayoutOrder = 8, 39 | Description = "Compare methods of searching for a value in an array", 40 | RunOnInsert = true, 41 | }, 42 | ["ArrayIteration.bench"] = { 43 | LayoutOrder = 9, 44 | Description = "Compare methods of iterating over an array", 45 | RunOnInsert = true, 46 | }, 47 | ["RandomInt.bench"] = { 48 | LayoutOrder = 10, 49 | Description = "Compare methods of generating a random integer", 50 | RunOnInsert = true, 51 | }, 52 | } 53 | 54 | -- Add GetModule functions to the index 55 | for _, module in script:GetChildren() do 56 | -- Skip non-ModuleScript children 57 | if not module:IsA("ModuleScript") then 58 | continue 59 | end 60 | 61 | -- Validate index 62 | if Index[module.Name] == nil then 63 | warn("BenchmarkerLibrary module '" .. module.Name .. "' is missing an entry in the library index") 64 | Index[module.Name] = { 65 | LayoutOrder = math.huge, 66 | Description = "No description provided", 67 | RunOnInsert = false, 68 | } 69 | continue 70 | end 71 | 72 | -- Add GetModule function for ease of use 73 | Index[module.Name].GetModule = function() 74 | return module:Clone() 75 | end 76 | end 77 | 78 | return Index 79 | -------------------------------------------------------------------------------- /wally.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "boatbomber/benchmarkerlibrary" 3 | description = "Collection of benchmark templates and examples for Benchmarker" 4 | version = "0.2.3" 5 | license = "MIT" 6 | authors = ["boatbomber (https://boatbomber.com)"] 7 | registry = "https://github.com/upliftgames/wally-index" 8 | realm = "shared" 9 | include = ["src", "src/**", "wally.toml", "wally.lock", "default.project.json"] 10 | exclude = ["**"] 11 | --------------------------------------------------------------------------------