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