diff --git a/files.html b/files.html
index 9eda2983198cc13972727a3ad0cd106200b2dc2e..3b1336cd8988dc51aafb385f9eb89f76a62ef239 100644
--- a/files.html
+++ b/files.html
@@ -234,6 +234,7 @@
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./programs/machines/ShopBot/mill%202D%20svg'>mill 2D svg</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./programs/machines/ShopBot/mill%202D%20svg%20connect'>mill 2D svg connect</a><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;math</i><br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./programs/math/benchmark'>benchmark</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='./programs/math/expressions'>expressions</a><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processes</i><br>
 <i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cut</i><br>
diff --git a/modules/math/benchmark b/modules/math/benchmark
index 0292d5bf0c67a84599d22654755822f7e5ae0bcf..6849f55822b2ba767787123c16479b6188e58f93 100644
--- a/modules/math/benchmark
+++ b/modules/math/benchmark
@@ -32,7 +32,7 @@ var init = function() {
 // inputs
 //
 var inputs = {
-   start:{type:'event',
+   start:{type:'',
       event:function(evt){
          benchmark()}}}
 //
@@ -94,16 +94,16 @@ function benchmark() {
    var time = 0
    var workers = []
    var tstart = Date.now()
+   var blob = new Blob(['('+worker.toString()+'())'])
+   var url = window.URL.createObjectURL(blob)
    for (var index = 0; index < nworkers; ++index) {
-      var blob = new Blob(['('+worker.toString()+'())'])
-      var url = window.URL.createObjectURL(blob)
       workers[index] = new Worker(url)
       workers[index].addEventListener('message',function(evt) {
-         window.URL.revokeObjectURL(url)
          pi += evt.data.pi
          workers[evt.data.index].terminate()
          count += 1
          if (count == nworkers) {
+            window.URL.revokeObjectURL(url)
             var tend = Date.now()
             time = (tend-tstart)/1000
             mod.value.nodeValue = 'value: '+pi
diff --git a/programs/index.js b/programs/index.js
index 21ccdcbdbf19f41d69e7c18c9f7a5495761d4303..106fd214cb1c8480ca53969dd9237ed1cbca7907 100644
--- a/programs/index.js
+++ b/programs/index.js
@@ -36,6 +36,7 @@ program_menu('      mill 2D stl','programs/machines/ShopBot/mill%202D%20st
 program_menu('      mill 2D svg','programs/machines/ShopBot/mill%202D%20svg')
 program_menu('      mill 2D svg connect','programs/machines/ShopBot/mill%202D%20svg%20connect')
 program_label('math')
+program_menu('   benchmark','programs/math/benchmark')
 program_menu('   expressions','programs/math/expressions')
 program_label('processes')
 program_label('   cut')
diff --git a/programs/math/benchmark b/programs/math/benchmark
new file mode 100644
index 0000000000000000000000000000000000000000..709626013d68a61787316229ae7a11663898a163
--- /dev/null
+++ b/programs/math/benchmark
@@ -0,0 +1 @@
+{"modules":{"0.5638807172368232":{"definition":"//\n// benchmark\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2018\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'benchmark'\n//\n// initialization\n//\nvar init = function() {\n   mod.terms.value = '1e8'\n   mod.workers.value = '4'\n   }\n//\n// inputs\n//\nvar inputs = {\n   start:{type:'',\n      event:function(evt){\n         benchmark()}}}\n//\n// outputs\n//\nvar outputs = {\n   }\n//\n// interface\n//\nvar interface = function(div){\n   mod.div = div\n   div.appendChild(document.createTextNode('terms: '))\n   var input = document.createElement('input')\n      input.type = 'text'\n      input.size = 6\n      div.appendChild(input)\n      mod.terms = input\n   div.appendChild(document.createElement('br'))\n   div.appendChild(document.createTextNode('workers: '))\n   var input = document.createElement('input')\n      input.type = 'text'\n      input.size = 6\n      div.appendChild(input)\n      mod.workers = input\n   div.appendChild(document.createElement('br'))\n   var btn = document.createElement('button')\n      btn.style.padding = mods.ui.padding\n      btn.style.margin = 1\n      var text = document.createTextNode('calculate pi')\n         mod.label = text\n         btn.appendChild(text)\n      btn.addEventListener('click',function() {\n         benchmark()\n         })\n      mod.button = btn\n      div.appendChild(btn)\n   div.appendChild(document.createElement('br'))\n   var text = document.createTextNode('value: ')\n      div.appendChild(text)\n      mod.value = text\n   div.appendChild(document.createElement('br'))\n   var text = document.createTextNode('time (s): ')\n      div.appendChild(text)\n      mod.time = text\n   div.appendChild(document.createElement('br'))\n   var text = document.createTextNode('Mflops: ')\n      div.appendChild(text)\n      mod.mflops = text\n   }\n//\n// local functions\n//\nfunction benchmark() {\n   mod.label.nodeValue = 'calculating'\n   var nworkers = parseInt(mod.workers.value)\n   var count = 0\n   var pi = 0\n   var time = 0\n   var workers = []\n   var tstart = Date.now()\n   var blob = new Blob(['('+worker.toString()+'())'])\n   var url = window.URL.createObjectURL(blob)\n   for (var index = 0; index < nworkers; ++index) {\n      workers[index] = new Worker(url)\n      workers[index].addEventListener('message',function(evt) {\n         pi += evt.data.pi\n         workers[evt.data.index].terminate()\n         count += 1\n         if (count == nworkers) {\n            window.URL.revokeObjectURL(url)\n            var tend = Date.now()\n            time = (tend-tstart)/1000\n            mod.value.nodeValue = 'value: '+pi\n            mod.time.nodeValue = 'time (s): '+time\n            var mflops = nworkers*5*terms/(time*1e6)\n            mod.mflops.nodeValue = 'Mflops: '+mflops.toFixed(0)\n            mod.label.nodeValue = 'calculate pi'\n            mods.fit(mod.div)\n            }\n         })\n      var terms = parseFloat(mod.terms.value)\n      workers[index].postMessage({terms:terms,index:index})\n      }\n   }\nfunction worker() {\n   self.addEventListener('message',function(evt) {\n      var terms = evt.data.terms\n      var index = evt.data.index\n      var start = 1+index*terms\n      var end = (index+1)*terms\n      var pi = 0\n      for (var term = start; term <= end; ++term)\n         pi += 0.5/((term-0.75)*(term-0.25))\n      self.postMessage({pi:pi,index:index})\n      })\n   }\n//\n// return values\n//\nreturn ({\n   mod:mod,\n   name:name,\n   init:init,\n   inputs:inputs,\n   outputs:outputs,\n   interface:interface\n   })\n}())\n","top":"133","left":"217","inputs":{},"outputs":{}}},"links":[]}
\ No newline at end of file