mir3c/squashfs-root/usr/bin/download_speedtest

480 lines
11 KiB
Lua
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env lua
local posix = require("Posix")
local ubus = require ("ubus")
local fs = require "nixio.fs"
local cfg = {
['postfile'] = "/tmp/postfile.dat",
['postfilesize'] = 512, -- kbyte
['posturl'] = "http://netsp.master.qq.com/cgi-bin/netspeed",
['geturl'] = "http://dlied6.qq.com/invc/qqdoctor/other/test32mb.dat",
['nr'] = 200, --Number of requests to perform
['nc'] = 15, --Number of multiple requests to make at a time
['loopnum'] = 15,
['timelimit'] = 9,
['timestep'] = 1,
['interval'] = 1,
['weight'] = 0.95, -- smooth net tarffic burst at first second
['qos_weight'] = 1,
['burstrate'] = 2,
['ab'] = "/usr/bin/ab",
['dd'] = "/bin/dd",
['debug'] = 0,
['xmlfile'] = "/usr/share/speedtest.xml",
['tmp_speedtest_xml'] = "/tmp/speedtest_urls.xml",
}
VERSION="__UNDEFINED__"
if VERSION == "LESSMEM" then
cfg.nr = 120
cfg.nc = 10
end
local filename = ""
filexml = io.open(cfg.tmp_speedtest_xml)
if filexml then
filexml:close()
filename = cfg.tmp_speedtest_xml
else
filename = cfg.xmlfile
end
local pp = io.open(filename)
local line = pp:read("*line")
local size = 0
local resources = {}
local u = ""
local pids = {}
function die(err)
posix.openlog(arg[0], "cp", posix.LOG_LOCAL7)
posix.syslog(posix.LOG_ERR, err)
posix.closelog()
os.exit(1)
end
function logger(loglevel,msg)
posix.openlog("speedtest","np",LOG_USER)
posix.syslog(loglevel,msg)
posix.closelog()
end
print(string.format("download using %s...", filename))
logger(3, string.format("download using %s...", filename))
print(string.format("download using nr: %d nc: %d", cfg.nr, cfg.nc))
logger(3, string.format("download using nr: %d nc: %d", cfg.nr, cfg.nc))
function mrandom(min,max,num)
local reverse = {}
local t = {}
local ret = {}
local i = min
local index
while i <= max do
table.insert(t, i)
i = i + 1
end
i = num
math.randomseed(os.time())
while i > 0 do
index = math.random(table.getn(t))
table.insert(ret,t[index])
if index == table.getn(t) then
table.remove(t)
else
local top = table.remove(t)
t[index] = top
end
i = i - 1
end
return ret
end
function execa(cmd)
local p = io.popen(cmd)
local line = p:read("*l")
while(line) do
print(line)
line = p:read("*l")
end
p:close()
end
function wget_work(url)
local _url = url
pid = posix.fork()
if pid < 0 then
print("fork error")
return -1
elseif pid > 0 then
--print(string.format("child pid %d\n", pid))
else
os.execute('for i in $(seq '.. math.floor(cfg.nr/cfg.nc) ..'); do wget '.. url ..
" -q -O /dev/null; done")
end
return pid
end
function wget_work_loop(url)
local _url = url
local i = 1
local cmd = 'wget -q -O /dev/null '
while (i<=cfg.loopnum) do
cmd = string.format('%s %s',cmd, url)
i=i+1
end
pid = posix.fork()
if pid < 0 then
print("fork error")
return -1
elseif pid > 0 then
--print(string.format("child pid %d\n", pid))
else
os.execute(cmd)
end
return pid
end
function wan_device()
local conn = ubus.connect()
if not conn then
elog("Failed to connect to ubusd")
end
local status = conn:call("network.interface.wan", "status",{})
conn:close()
if not status then
return nil
else
return (status.l3_device and status.l3_device) or status.device
end
end
function get_pstree(root, pids)
local pp = io.popen("pgrep -P "..root)
pid = pp:read("*line")
while pid do
data = table.insert(pids, pid)
get_pstree(pid, pids)
pid = pp:read("*line")
end
pp:close()
end
function execl2(command)
local pp = io.popen(command)
local line = ""
local data = {}
while true do
line = pp:read()
if line == nil then
break
end
data[#data+1] = line
end
pp:close()
return data
end
function get_pstree2(root, pids)
local cmd = "pstree -p "..root
local res = execl2(cmd)
print("type root is: "..type(root))
if res and next(res)~=nil then
for k,v in ipairs(res) do
local j = 0
while true do
_,j,pid = string.find(v, '%(([0-9]+)%)', j+1)
if pid then
if tonumber(pid) ~= root then
table.insert(pids, pid)
end
else
break
end
end
end
end
end
function done(signo)
io.output("/dev/null")
local fd = io.open("/dev/null", "rw")
if not posix.dup(fd, io.stdout) then
die("error dup2-ing")
end
if not posix.dup(fd, io.stderr) then
die("error dup2-ing")
end
get_pstree2(posix.getpid("pid"), pids)
for k, pid in ipairs(pids) do
print("kill pid:" .. pid)
posix.kill(pid, posix.SIGINT)
end
os.exit(0)
end
function read_line(filename)
local fd = io.open(filename)
local line = fd:read("*line")
fd:close()
return line
end
function get_uptime()
local _, _, uptime, idle = string.find(read_line("/proc/uptime"),'^([0-9.]+)%s+([0-9.]+)$')
return tonumber(uptime)
end
function get_rt(ifname)
local line
local face, r_bytes, r_packets, r_errs, r_drop, r_fifo, r_frame, r_compressed, r_multicast
local t_bytes, t_packets, t_errs, t_drop, t_fifo, t_colls, t_carrier, t_compressed
local _nic = {}
if fs.access("/proc/net/dev") then
for line in io.lines("/proc/net/dev") do
_, _, face, r_bytes, r_packets, r_errs, r_drop, r_fifo, r_frame, r_compressed, r_multicast,
t_bytes, t_packets, t_errs, t_drop, t_fifo, t_colls, t_carrier, t_compressed = string.find(line,
'%s*(%S+):%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s*')
if (face == ifname) then
return {
r_bytes = tonumber(r_bytes),
r_packets = tonumber(r_packets),
t_bytes = tonumber(t_bytes),
t_packets = tonumber(t_packets),
uptime = get_uptime()
}
end
end
end
end
function print_rt(rt, rt_last)
local delta_time = rt.uptime - rt_last.uptime
print(string.format("Time(ms):%.0f\tr_x:%.2f t_x:%.2f",
delta_time*1000,
(rt.r_bytes - rt_last.r_bytes) / delta_time / 1024,
(rt.t_bytes - rt_last.t_bytes) / delta_time / 1024))
end
-----------------------------------------------------------------------
posix.signal(posix.SIGTERM, done);
local wan_ifname = wan_device()
if not wan_ifname then
print("got invalid wan device")
print(string.format("avg rx:%.2f", 0))
logger(3, "stat_points_privacy network_speedtest=10|download|no_wan_dev")
done()
end
while line do
local _, _, url = string.find(line,'<item url="(.*)"/>')
if url then
table.insert(resources, url)
end
line = pp:read("*line")
end
pp:close()
local urls = mrandom(1, table.getn(resources), cfg.nc)
for k, v in ipairs(urls) do
if VERSION == "LESSMEM" then
local pid = wget_work_loop(resources[v])
else
local pid = wget_work(resources[v])
end
if(pid == 0) then
os.exit(0)
elseif(pid == -1) then
done()
end
end
local rt = get_rt(wan_ifname)
if not rt then
print("got invalid data")
print(string.format("avg rx:%.2f", 0))
logger(3, "stat_points_privacy network_speedtest=10|download|no_wan_info")
done()
end
local rt_last
local dot_datas = {}
local dot = 1
dot_datas[dot] = rt
while dot <= cfg.timelimit do
posix.sleep(1)
dot = dot + 1
rt_last = rt
rt = get_rt(wan_ifname)
if not rt then
print("got invalid data")
print(string.format("avg rx:%.2f", 0))
logger(3, "stat_points_privacy network_speedtest=10|download|no_wan_info")
done()
end
dot_datas[dot] = rt
print_rt(rt, rt_last)
end
--function dotdata_show()
function dump_dot_data(dotdata)
for i=1,#dotdata do
print(string.format("[%.2d] %.2f %.2f %.2f", i, dotdata[i].r_bytes,dotdata[i].t_bytes, dotdata[i].uptime))
end
end
--<2D><><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD>ֵ
function rx_avg_speed(dotdata)
local sum,j = 0,1
local dlt_time
if #dotdata < 2 then
return 0
end
while j + 1 <= #dotdata do
if (dotdata[j+1].r_bytes <= dotdata[j].r_bytes) then
return 0
end
dlt_time = dotdata[j+1].uptime - dotdata[j].uptime
sum = sum + (dotdata[j+1].r_bytes - dotdata[j].r_bytes) / dlt_time / 1024
j = j + 1
end
return sum/(#dotdata-1)
end
--ÿ<><C3BF><EFBFBD><EFBFBD>cfg.interval<61><6C><EFBFBD><EFBFBD>rx<72><78><EFBFBD>ݼ<EFBFBD><DDBC><EFBFBD><EFBFBD>ٶȣ<D9B6>ȡ<EFBFBD><C8A1><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD>ֵ
function rx_max_avg_speed(dotdata, net_burst)
local rx_speed = 0
local i = 2 --i<><69>2<EFBFBD><32>ʼ<EFBFBD><CABC><EFBFBD>ܿ<EFBFBD><DCBF><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>burst<73><74><EFBFBD><EFBFBD>
while (i + cfg.interval) <= (cfg.timelimit + 1) do
if (dotdata[i+cfg.interval].r_bytes <= dotdata[i].r_bytes) then
return 0
end
local delta_time = dotdata[i+cfg.interval].uptime - dotdata[i].uptime
local tmp = (dotdata[i+cfg.interval].r_bytes - dotdata[i].r_bytes)/ delta_time / 1024
--print(string.format("sec[%d]%.2f sec[%d]%.2f delta_time %.2f, speed is %.2f",
-- i+cfg.interval, dotdata[i+cfg.interval].r_bytes, i,
-- dotdata[i].r_bytes, delta_time, tmp))
if (i == 1) and net_burst then
--print(string.format("sec[%d] weight %.2f burstrate %.2f : smooth from %.2f to %.2f",
-- i, cfg.weight, cfg.burstrate, tmp, tmp*cfg.weight))
tmp = tmp * cfg.weight
end
if tmp > rx_speed then
rx_speed = tmp
end
i = i + 1
end
return rx_speed
end
-- ȥ<><C8A5>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ȥ<EFBFBD><C8A5>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Сֵ, <20><>ƽ<EFBFBD><C6BD>
function avg_remove_max_min(tdata)
local sum = 0
table.sort(tdata)
--print(string.format("table remove max %.2f min %.2f",
-- tdata[#tdata], tdata[1]))
table.remove(tdata,#tdata)
table.remove(tdata,1)
for key, value in pairs(tdata) do
sum = sum + value
--print(string.format("%.2f", value))
end
return sum/#tdata
end
--ÿ<><C3BF><EFBFBD><EFBFBD>cfg.interval<61><6C><EFBFBD><EFBFBD>rx<72><78><EFBFBD>ݼ<EFBFBD><DDBC><EFBFBD><EFBFBD>ٶȣ<D9B6>ȥ<EFBFBD><C8A5>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>ȥ<EFBFBD><C8A5>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Сֵ, <20><>ƽ<EFBFBD><C6BD>
function rx_avg_interval_speed(dotdata)
local sum = {}
local rx_speed = 0
local i = 1
while (i + cfg.interval) <= (cfg.timelimit + 1) do
if (dotdata[i+cfg.interval].r_bytes <= dotdata[i].r_bytes) then
print("r_x data "..(i+cfg.interval).." <= "..i)
logger(3, "stat_points_privacy network_speedtest=10|download|data_invalid|"..i+cfg.interval.."|"..dotdata[i+cfg.interval].r_bytes.."|"..i.."|"..dotdata[i].r_bytes)
return 0
end
local delta_time = dotdata[i+cfg.interval].uptime - dotdata[i].uptime
local tmp = (dotdata[i+cfg.interval].r_bytes - dotdata[i].r_bytes)/ delta_time / 1024
--print(string.format("sec[%d]%.2f sec[%d]%.2f delta_time %.2f, speed is %.2f",
-- i+cfg.interval, dotdata[i+cfg.interval].r_bytes, i,
-- dotdata[i].r_bytes, delta_time, tmp))
table.insert(sum, tmp)
i = i + 1
end
rx_speed = avg_remove_max_min(sum)
if rx_speed*8 < 128 then
logger(3, "stat_points_privacy network_speedtest=10|download|data_small_value|"..rx_speed*8)
end
return rx_speed
end
--<2D>жϵ<D0B6>һ<EFBFBD><D2BB><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>net burst
function if_net_burst(dotdata)
if ((dotdata[2].r_bytes < dotdata[1].r_bytes) or (dotdata[3].r_bytes < dotdata[2].r_bytes)) then
return false
end
local delta_time = dotdata[2].uptime - dotdata[1].uptime
local first_speed = (dotdata[2].r_bytes - dotdata[1].r_bytes) / delta_time / 1024
delta_time = dotdata[3].uptime - dotdata[2].uptime
local second_speed = (dotdata[3].r_bytes - dotdata[2].r_bytes) / delta_time / 1024
if first_speed > (cfg.burstrate * second_speed) then
return true
end
return false
end
--dump_dot_data(dot_datas)
local res_speed = rx_avg_speed(dot_datas)
print(string.format("avg r_x:%.2f %.2fMB %.2fMbit", res_speed*8, res_speed/1024, res_speed*8/1024))
res_speed = rx_avg_interval_speed(dot_datas)
print(string.format("qos weight %.3f: from %.2f to %.2f",
cfg.qos_weight, res_speed, res_speed*cfg.qos_weight))
res_speed = res_speed * cfg.qos_weight
print(string.format("avg rx:%.2f %.2fMB %.2fMbit", res_speed*8, res_speed/1024, res_speed*8/1024))
done()