Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merged to trunk for next blog post release. This has the nominally working email when startled script that can be configured to either email a plot of SPL or an MP3 of the room audio around the event. |
---|---|
Timelines: | family | ancestors | descendants | both | blog-splear09 | trunk |
Files: | files | file ages | folders |
SHA1: |
8d8ccc7f52b757d10112b15fed1d83e9 |
User & Date: | rberteig 2015-06-16 22:18:12 |
Context
2015-06-25
| ||
21:36 | Change scared delta SPL threshold to 12dB from 6dB. check-in: dd66d0e331 user: rberteig tags: trunk | |
2015-06-16
| ||
22:18 | Merged to trunk for next blog post release. This has the nominally working email when startled script that can be configured to either email a plot of SPL or an MP3 of the room audio around the event. check-in: 8d8ccc7f52 user: rberteig tags: blog-splear09, trunk | |
22:11 | Fixed double noise gate stages in the SoX filter pipeline, restored the companding stage that should have been after a single noise gate. Tweaked levels on the noise gate. Also merged the recorder into the main scared.lua script, so that it can send email when scared based on the GPIO pin signalling. The email has a noise gated companded and MP3 encoded copy of the audio from just before the trigger to some time after the trigger. MP3 is used because both Android and iPhone appear to be able to play it directly from an email attachment. Leaf check-in: 8b86ec7568 user: rberteig tags: scared | |
2015-05-22
| ||
23:23 | Merge in the scared.lua scripts for the latest blog post. check-in: 26b540b327 user: rberteig tags: trunk | |
Changes
Added Scared/pinmmap.lua.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | local GPIO=require"GPIO" GPIO.setmode(GPIO.BOARD) --[[ table.foreach(GPIO,function(k,v) if type(v)=="string" or type(v)=="number" then print(k,v) end end ) --]] i2c={sda=3,scl=5} --GPIO.setup(i2c.sda,GPIO.I2C) --GPIO.setup(i2c.scl,GPIO.I2C) uart={tx=8,rx=10} --GPIO.setup(uart.tx,GPIO.SERIAL) --GPIO.setup(uart.rx,GPIO.SERIAL) spi={mosi=19,miso=21,sclk=23} --GIO.setup(spi.mosi, GPIO.SPI) --GIO.setup(spi.miso, GPIO.SPI) --GIO.setup(spi.sclk, GPIO.SPI) --[[ pins={11,12,13,15,16,18,22,24,26} for _,p in ipairs(pins) do GPIO.setup(p,GPIO.IN) end for _,p in ipairs(pins) do print(p, GPIO.input(p)) end --]] local b = false --GPIO.setup(26,GPIO.IN,GPIO.PUD_UP) GPIO.setup(26,GPIO.IN) while(true) do --GPIO.wait_for_edge(26, GPIO.BOTH) local b0 = GPIO.input(26) if b0 ~= b then print(b0) end b = b0 end local pinfuncs={} pinfuncs[GPIO.IN] = "in" pinfuncs[GPIO.OUT] = "out" pinfuncs[GPIO.SPI] = "spi" pinfuncs[GPIO.I2C] = "i2c" pinfuncs[GPIO.PWM] = "pwm" pinfuncs[GPIO.SERIAL] = "ser" pinfuncs[GPIO.UNKNOWN] = "unk" setmetatable(pinfuncs,{__index=function(k) return tostring(k) end}) pins={3,5,7,8,10} for i=1,#pins do print(i, pins[i], pinfuncs[GPIO.gpio_function(pins[i])]) end GPIO.cleanup() |
Added Scared/pinsysfs.lua.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | local P = require "posix" -- write str to the named file function putfile(name,str) local f = assert(io.open(name,"w")) f:write(str) f:close() end -- read the named file and return its content function getfile(name) local f = assert(io.open(name,"r")) local str f:read"*a" f:close() return str end -- transform a list into a set for quick lookup function SET(t) local s = {} for _,v in ipairs(t) do s[v] = true end return s end -- container for GPIO functions gpio={ pins1_1 = SET{ -- Original RPi A, B 0, 1, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23, 24, 25, }, pins1_2 = SET{ -- Rev 2 A, B 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 22, 23, 24, 25, 27}, pins2_0 = SET{ -- A+, B+, 2A, 2B 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}, } -- default to RPi B+ board -- TODO: Read /proc/cpuinfo and get this right gpio.pins = gpio.pins2_0 -- export a sysfs pin to userland function gpio.export(pin) assert(gpio.pins[pin], "Can't use pin") putfile("/sys/class/gpio/export",tostring(pin)) end -- return a sysfs pin to the kernel function gpio.unexport(pin) assert(gpio.pins[pin], "Can't use pin") putfile("/sys/class/gpio/unexport",tostring(pin)) end -- userland path to a specific pin's atribute file function gpio.pinpath(pin,attr) return ("/sys/class/gpio/gpio%d/%s"):format(pin,attr) end -- set pin direction function gpio.direction(pin,dir) local path = gpio.pinpath(pin, "direction") print("Setting "..path.." to "..dir) putfile(path, dir) end -- set pin edge detector function gpio.edge(pin,edge) local path = gpio.pinpath(pin, "edge") print("Setting "..path.." to "..edge) putfile(path, edge) end -- blocking wait with timeout for an edge on a pin function gpio.wait(pin) assert(gpio.pins[pin], "Can't use pin") local path = gpio.pinpath(pin, "value") if not gpio.pinfd then gpio.pinfd = P.open(path, P.O_RDONLY) end local p = gpio.pinfd if not gpio.fds then gpio.fds = {} end if not gpio.fds[p] then gpio.fds[p] = {events={}, revents={}} end gpio.fds[p].events.PRI=true local ret = P.poll(gpio.fds, 10000) if ret == 0 then return 0 end P.lseek(p,0,P.SEEK_SET) ret = tonumber(P.read(p,8)) --P.close(p) --gpio.pinfd = nil return ret end -- Use pin P1-28 aka GPIO7 for SPLear alerts gpio.export(7) gpio.direction(7,"in") gpio.edge(7,"rising") while(true) do local r = gpio.wait(7) if r == 0 then --print"timeout" elseif r==1 then local tim = P.gettimeofday() print("eek "..tim.sec..'.'..tim.usec) else print("???", r) end end if gpio.pinfd then P.close(gpio.pinfd) end |
Added Scared/record.lua.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #! lua local struct = require "struct" -- today's date in (almost) ISO-8601 format local function isodate() return os.date"%Y%m%d-%H%M%S" end -- Implement a buffer of samples. For simplicity, let the -- index increment without bound. Note that this will have -- a problem after 2^53 samples, which is about 30 million -- years at 10 samples per second. local recent = { depth=100, n=1, add=function(self,s) local n = self.n self[n] = s self[n-self.depth] = nil self.n = n + 1 end, buffer=function(self) local n1,n2 = self.n-self.depth, self.n-1 if n1 <= 0 or n2 <= 0 then return end return table.concat(self,'',self.n-self.depth,self.n-1) end } local function auheader(buf, rate) local fmt = ">c4LLLLLL" local hdr = struct.pack(fmt, ".snd", -- 0 magic number struct.size(fmt), -- 1 data offset #buf, -- 2 length or -1 1, -- 3 encoding uLaw rate, -- 4 8152 Hz sample rate 1, -- 5 mono 0) -- 6 empty metadata string return hdr end local function writeau(au, buf) local f = assert(io.open(au,"wb")) f:write(auheader(buf, 8152), buf) f:close() end function writemp3(name, udata) local soxgate = 'compand .1,.2 -inf,-55.1,-inf,-55,-55 0 -90 .1 ' local soxcompand = 'compand 0.3,1 6:-70,-60,-20 -5 -90 0.2 ' local soxcmd = 'sox -t au - -t wav -b 16 - ' .. soxgate .. soxcompand ..'| lame - '..name print(soxcmd) local fp = assert(io.popen('sh -c "'..soxcmd..'"', 'w')) fp:write(auheader(udata, 8152), udata) fp:close() end -- Quick and dirty way to force the UART to have the -- tty driver settings we need for clean raw access -- to the port. os.execute("stty -F /dev/ttyAMA0 115200" .." pass8 raw -iexten" .." -echo -echoe -echok -echoke -echoctl") -- Open the UART for both reading and writing, and send -- the SPLear command to go into uLaw recording mode. The -- output must be unbuffered because the current SPLear -- firmware would revert to 0.5 Hz summary mode if it -- receives a newline. local port = assert(io.open('/dev/ttyAMA0','r+')) port:setvbuf"no" -- no output buffer at all port:write"R" -- so this write is immediate -- Loop reading the audio stream and watching for loud -- noises, keeping a log of recent samples as we go. -- When a loud noise is heard, keep logging for a bit -- before sending email. Include the log in the email. while true do local buf = port:read(1000) -- sampled at 8153 Hz probably recent:add(buf) if recent.n % 8 == 0 then io.write(tostring(recent.n),"\r") io.flush() end if recent.n > recent.depth then local eek = "rec-"..isodate() --writeau(eek..".au", recent:buffer()) writemp3(eek..".mp3", recent:buffer()) return end end |
Changes to Scared/scared.lua.
1 2 3 | #! lua local plot = require "plotspl" | > > > | > > > > > > > | | | < | | | | > > > > > > > > > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | #! lua local lanes = require "lanes".configure() local plot = require "plotspl" local struct = require "struct" local rc = dofile"scared.rc" rc.address = rc.address or "user@example.com" rc.mode = rc.mode or "SPL" -- today's date in (almost) ISO-8601 format local function isodate() return os.date"%Y-%m-%d %H:%M:%S" end -- today's date for use in a file name local function namedate() return os.date"%Y%m%d-%H%M%S" end -- make its argument be a single double-quoted string function flatten(s) if type(s)=="string" then return '"'..s..'"' end if type(s)~="table" then return nil end return '"'..table.concat(s, '" "')..'"' end -- Send an email to addr with subject and body. If body -- is nil then just repeat the subject. This assumes that -- a "mail" command is available with the usual options. local function email(addr, subj, body) body = body or subj local mail = ("mail -s '%q' %s"):format(subj,addr) local b = assert(io.popen(mail, "w")) b:write([[I heard a noise on ]], isodate(), "\r\n\r\n") b:write(body, "\r\n\r\n") b:write"(This an automated message.)\r\n" b:close() end -- Send a MIME packed email containing a file related -- to the event to a recipient with a subject local function mpack(address, subject, file) assert(address) assert(subject) assert(file) local cmd = ("mpack -a -s %q %q %s"):format(subject, file, address) print(cmd) os.execute(cmd) end -- Implement a buffer of samples. For simplicity, let the -- index increment without bound. Note that this will have -- a problem after 2^53 samples, which is about 30 million -- years at 10 samples per second or 300 thousand years at -- about 1000 samples per second. local recent = { depth=200, n=1, -- clear the buffer and set a new depth clear=function(self,newdepth) newdepth = newdepth or 200 local offset = self.n-self.depth-1 for i=1,self.depth do self[i+offset] = nil end self.n = 1 self.depth = newdepth end, -- add a sample to the buffer add=function(self,spl) local n = self.n self[n] = spl self[n-self.depth] = nil self.n = n + 1 end, -- return the entire buffer as a raw blob raw=function(self) return table.concat(self,'',self.n-self.depth,self.n-1) end, -- return a CSV formatted buffer assuming the samples -- are SPL levels at 10 Hz CSVtext=function(self, header) local t = header and {"s, dB"} or {} local offset = self.n-self.depth-1 for i=1,self.depth do if self[i+offset] then t[#t+1] = ("%0.1f, %s"):format(i/10,self[i+offset]) end end return table.concat(t,"\n") end } local function auheader(buf, rate) local fmt = ">c4LLLLLL" local hdr = struct.pack(fmt, ".snd", -- 0 magic number struct.size(fmt), -- 1 data offset #buf, -- 2 length or -1 1, -- 3 encoding uLaw rate, -- 4 8152 Hz sample rate 1, -- 5 mono 0) -- 6 empty metadata string return hdr end local function writeau(au, buf) local f = assert(io.open(au,"wb")) f:write(auheader(buf, 8152), buf) f:close() end function writemp3(name, udata) local soxgate = 'compand .1,.2 -inf,-55.1,-inf,-55,-55 0 -90 .1 ' local soxcompand = 'compand 0.3,1 6:-70,-60,-20 -5 -90 0.2 ' local soxcmd = 'sox -t au - -t wav -b 16 - ' .. soxgate .. soxcompand ..'| lame - '..name print(soxcmd) local fp = assert(io.popen('sh -c "'..soxcmd..'"', 'w')) fp:write(auheader(udata, 8000), udata) fp:close() end -- Quick and dirty way to force the UART to have the -- tty driver settings we need for clean raw access -- to the port. os.execute("stty -F /dev/ttyAMA0 115200" .." pass8 raw -iexten" .." -echo -echoe -echok -echoke -echoctl") -- Open the UART for both reading and writing, and send -- the SPLear command to go into raw SPL sample mode. The -- output must be unbuffered because the current SPLear -- firmware would revert to 0.5 Hz summary mode if it -- receives a newline. local port = assert(io.open('/dev/ttyAMA0','r+')) port:setvbuf"no" -- no output buffer at all local addr = flatten(rc.address) print("Notifying "..addr) -- command the requested mode if rc.mode == "record" then port:write"R" -- so this write is immediate local msgs = lanes.linda() -- temporary simulation of noises by 10 second timer lanes.timer(msgs, "tick", 10, 10) -- Function running in a separate thread that watches for loud -- noises signled via GPIO pin pinwatcher = lanes.gen("*", function() gpio = require "sysfsgpio" gpio.export(7) gpio.direction(7, "in") gpio.edge(7, "rising") print("Watching GPIO07 which is pin P1-26") while true do --local _, t = msgs:receive"tick" -- external simulation timer local r = gpio.wait(7) if r == 0 then -- poll timed out elseif r == 1 then msgs:send("eek", isodate()) else -- something unexpected happened end end end )() -- main loop reads data as usual, keeping an eye out for -- being scared, after which it saves and emails a recording. local triggered = false local eek while true do local sample = port:read(800) -- read 1/10 sec audio if sample then io.write("Rec "..(triggered and "TRG " or " "), recent.n, "\r") io.flush() recent:add(sample) -- Notice GPIO pin local s = pinwatcher.status if not (s == "waiting" or s == "running" or s == "pending") then print("Watcher status: "..s) break end local eekflag, eekval = msgs:receive(0.0, "eek") if eekflag then if not triggered then triggered = math.floor(recent.depth * 2. / 3.) eek = "EEK! "..eekval end end if triggered then triggered = triggered - 1 if triggered == 0 then triggered = false local data = recent:raw(false) local mp3file = "eek-"..namedate()..".mp3" writemp3(mp3file, data) print("email " .. addr, mp3file, isodate()) mpack(addr, eek, mp3file) end end spl0 = spl end end else -- mode == "SPL" port:write"S" -- so this write is immediate -- Loop reading the SPL samples and watching for loud -- noises, keeping a log of recent samples as we go. -- When a loud noise is heard, keep logging for a bit -- before sending email. Include the log in the email. local spl, spl0 local triggered = false local eek = "" while true do local line = port:read"*l" -- read a single line spl = tonumber(line) if spl then spl = 0.75 * spl io.write("SPL "..(triggered and "TRG " or " "), spl, "\r") recent:add(spl) -- Watch for the trigger condition: 12 dB louder if not triggered and spl0 and (spl - spl0 > 12.) then triggered = math.floor(recent.depth * 2. / 3.) eek = "EEK! "..spl.." dB" end if triggered then triggered = triggered - 1 if triggered == 0 then triggered = false local data = recent:CSVtext(false) local pngfile = "tmp-SPL.png" plot.plot(data, pngfile, recent.depth/30., -- 1/3 trigger pos, 1/10 for time scale "Startled at "..isodate()) local body = eek.."\n"..data print("email " .. addr, eek, isodate()) mpack(addr, eek, pngfile) end end spl0 = spl end end end |
Added Scared/sysfsgpio.lua.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | -- Module to make GPIO via the sysfs gpio class interface easy -- for simple Lua applications. -- simplest minimal module framework, just return M local M = { _NAME=(...), _VERSION="v0.001", } -- Utility functions private to the module local P = require "posix" -- write str to the named file function putfile(name,str) local f = assert(io.open(name,"w")) f:write(str) f:close() end -- read the named file and return its content function getfile(name) local f = assert(io.open(name,"r")) local str f:read"*a" f:close() return str end -- transform a list into a set for quick lookup function SET(t) local s = {} for _,v in ipairs(t) do s[v] = true end return s end -- container for GPIO functions, alias to M local gpio=M gpio.pins1_1 = SET{ -- Original RPi A, B 0, 1, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23, 24, 25, } gpio.pins1_2 = SET{ -- Rev 2 A, B 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 22, 23, 24, 25, 27} gpio.pins2_0 = SET{ -- A+, B+, 2A, 2B 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27} -- default to RPi B+ board -- TODO: Read /proc/cpuinfo and get this right based on the -- Hardware and Revision fields. For now, just assume -- what I have will work. gpio.pins = gpio.pins2_0 -- export a sysfs pin to userland function gpio.export(pin) assert(gpio.pins[pin], "Can't use pin") putfile("/sys/class/gpio/export",tostring(pin)) end -- return a sysfs pin to the kernel function gpio.unexport(pin) assert(gpio.pins[pin], "Can't use pin") putfile("/sys/class/gpio/unexport",tostring(pin)) end -- userland path to a specific pin's atribute file function gpio.pinpath(pin,attr) return ("/sys/class/gpio/gpio%d/%s"):format(pin,attr) end -- set pin direction function gpio.direction(pin,dir) local path = gpio.pinpath(pin, "direction") --print("Setting "..path.." to "..dir) putfile(path, dir) end -- set pin edge detector function gpio.edge(pin,edge) local path = gpio.pinpath(pin, "edge") --print("Setting "..path.." to "..edge) putfile(path, edge) end -- blocking wait with timeout for an edge on a pin function gpio.wait(pin) assert(gpio.pins[pin], "Can't use pin") local path = gpio.pinpath(pin, "value") if not gpio.pinfd then gpio.pinfd = P.open(path, P.O_RDONLY) end local p = gpio.pinfd if not gpio.fds then gpio.fds = {} end if not gpio.fds[p] then gpio.fds[p] = {events={}, revents={}} end gpio.fds[p].events.PRI=true local ret = P.poll(gpio.fds, 10000) if ret == 0 then return 0 end P.lseek(p,0,P.SEEK_SET) ret = tonumber(P.read(p,8)) --P.close(p) --gpio.pinfd = nil return ret end --Example --[===[ -- Use pin P1-28 aka GPIO7 for SPLear alerts -- local gpio = require "sysfsgpio" gpio.export(7) gpio.direction(7,"in") gpio.edge(7,"rising") while(true) do local r = gpio.wait(7) if r == 0 then --print"timeout" elseif r==1 then local tim = P.gettimeofday() print("eek "..tim.sec..'.'..tim.usec) else print("???", r) end end if gpio.pinfd then P.close(gpio.pinfd) end --]===] -- TODO: Do some minimal validation that there actually is -- a sysfs and error out if not. return M |
Added Scared/volley.lua.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | local lanes = require 'lanes'.configure() local msg = lanes.linda() local function volley(n,isa) print("Starting "..(isa and "A" or "B"), n) local rkey,skey = "a","b" if isa then skey,rkey = rkey,skey end msg:send("done",true) for i=1,n do local ball,value = msg:receive(rkey) msg:send(skey, value+1) end msg:send("done",true) end print("starting threads") local gen = lanes.gen("",volley) local N = 1e5 local a = gen(N, true) local b = gen(N) local ok,_ = msg:receive(0.5, msg.batched, "done", 2) if not ok then print "ouch" return end local t0 = os.time() msg:send("a", 0) msg:receive(nil, msg.batched, "done", 2) local t1 = os.time() print((t1-t0).." sec") print(((t1-t0)/N).." sec") print((N/(t1-t0)).." per sec") |