github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/lua/basic.quotas.lua (about) 1 -- 2 -- Check that recursion consumes memory 3 -- 4 5 -- Naive recursive fibonacci implementation 6 function rfib(n) 7 if n < 2 then return n 8 else return rfib(n-1) + rfib(n-2) 9 end 10 end 11 12 -- Check the implementation is correct 13 print(rfib(1), rfib(2), rfib(3), rfib(10)) 14 --> =1 1 2 55 15 16 -- Recursion blows memory budget 17 print(runtime.callcontext({kill={memory=1000}}, rfib, 100)) 18 --> =killed 19 20 -- Recursion blows cpu budget 21 print(runtime.callcontext({kill={cpu=10000}}, rfib, 100)) 22 --> =killed 23 24 -- 25 -- Check that iteration consumes CPU 26 -- 27 28 -- Iterative fibonacci implementation 29 function ifib(n) 30 local a, b = 0, 1 31 while n > 0 do 32 a, b = b, a+b 33 n = n - 1 34 end 35 return a 36 end 37 38 -- Check the implementation is correct 39 print(ifib(1), ifib(2), ifib(3), ifib(10)) 40 --> =1 1 2 55 41 42 -- memory usage doesn't explode 43 print(runtime.callcontext({kill={memory=1000}}, ifib, 100)) 44 --> =done 3736710778780434371 45 46 -- cpu usage doesn't explode 47 print(runtime.callcontext({kill={cpu=10000}}, ifib, 100)) 48 --> =done 3736710778780434371 49 50 -- we can run out of cpu eventually! 51 print(runtime.callcontext({kill={cpu=1000}}, ifib, 1000)) 52 --> =killed 53 54 -- 55 -- Check that tail recursion does not consume memory 56 -- 57 58 -- Tail-recursive fibonacci implementation 59 function trfib(n, a, b) 60 a, b = a or 0, b or 1 61 if n == 0 then return a end 62 return trfib(n - 1, b, a + b) 63 end 64 65 -- Check the implementation is correct 66 print(trfib(1), trfib(2), trfib(3), trfib(10)) 67 --> =1 1 2 55 68 69 -- memory usage doesn't explode 70 print(runtime.callcontext({kill={memory=1000}}, ifib, 100)) 71 --> =done 3736710778780434371 72 73 -- cpu usage doesn't explode 74 print(runtime.callcontext({kill={cpu=10000}}, ifib, 100)) 75 --> =done 3736710778780434371 76 77 -- we can run out of cpu eventually! 78 print(runtime.callcontext({kill={cpu=1000}}, ifib, 1000)) 79 --> =killed 80 81 -- 82 -- Check that string concatenation consumes memory 83 -- 84 85 -- strpex(x, n) is x concatenated to itself 2^n timees 86 function strexp(s, n) 87 if n == 0 then 88 return "" 89 end 90 while n > 1 do 91 s = s..s 92 n = n - 1 93 end 94 return s 95 end 96 97 print(strexp("hi", 2)) 98 --> =hihi 99 100 print(strexp("hi", 3)) 101 --> =hihihihi 102 103 --> strexp doesn't consume much cpu 104 ctx, bigs = runtime.callcontext({kill={cpu=1000}}, strexp, "hi", 16) 105 print(ctx, #bigs) 106 --> =done 65536 107 108 --> but it consumes memory! 109 print(runtime.callcontext({kill={memory=50000}}, strexp, "hi", 16)) 110 --> =killed 111 112 -- 113 -- Check that it costs memory to pass many arguments to a function 114 -- 115 116 function len(...) 117 return select('#', ...) 118 end 119 120 function numbers(n) 121 local t = {} 122 for i = 1, n do 123 t[i] = i 124 end 125 return t 126 end 127 128 print(table.unpack(numbers(5))) 129 --> =1 2 3 4 5 130 131 print(len(table.unpack(numbers(4)))) 132 --> =4 133 134 print(runtime.callcontext({kill={memory=1000}}, len, table.unpack(numbers(10)))) 135 --> =done 10 136 137 -- Passing a long list of arguments requires a lot of memory. 138 print(runtime.callcontext({kill={memory=2000}}, len, table.unpack(numbers(200)))) 139 --> =killed 140 141 -- 142 -- Check soft limits and stopping 143 -- 144 145 local c = 0 146 print(runtime.callcontext({stop={cpu=1000}}, function() 147 print(runtime.context().stop.cpu) 148 --> =1000 149 while not runtime.contextdue() do 150 c = c + 1 151 end 152 runtime.killcontext() 153 end)) 154 --> =killed 155 print(c > 10) 156 --> =true 157 158 -- 159 -- Check time limits 160 -- 161 local c = 0 162 print(runtime.callcontext({kill={millis=10}}, function() 163 while true do 164 c = c + 1 165 end 166 end)) 167 --> =killed 168 print(c > 10) 169 --> =true 170 171 -- 172 -- Check compliance flags 173 -- 174 print(runtime.callcontext({flags="timesafe"}, function() 175 io.write("hello") 176 end)) 177 --> ~error\t.*missing flags: timesafe