diff --git a/examples/stats.html b/examples/stats.html index 2693474f..324ff8e6 100644 --- a/examples/stats.html +++ b/examples/stats.html @@ -90,7 +90,7 @@ }); } //setInterval(fetchData, 15 * 1000); - setInterval(fetchData, 1000); + setInterval(fetchData, 5000); fetchData(); function Stats(key, chart){ diff --git a/gun.js b/gun.js index 281a379b..6a060d09 100644 --- a/gun.js +++ b/gun.js @@ -302,7 +302,7 @@ return; } var put = msg.put; - var DBG = ctx.DBG = msg.DBG; + var DBG = ctx.DBG = msg.DBG, S = +new Date; if(put['#'] && put['.']){ /*root && root.on('put', msg);*/ return } // TODO: BUG! This needs to call HAM instead. DBG && (DBG.p = S); ctx['#'] = msg['#']; @@ -310,10 +310,12 @@ ctx.all = 0; ctx.stun = 1; var nl = Object.keys(put).sort(); // TODO: This is unbounded operation, large graphs will be slower. Write our own CPU scheduled sort? Or somehow do it in below? + console.STAT && console.STAT(S, ((DBG||ctx).pk = +new Date) - S, 'put sort'); var ni = 0, nj, kl, soul, node, states, err, tmp; (function pop(o){ if(nj != ni){ nj = ni; if(!(soul = nl[ni])){ + console.STAT && console.STAT(S, ((DBG||ctx).pd = +new Date) - S, 'put'); fire(ctx); return; } @@ -420,7 +422,7 @@ //Gun.window? Gun.obj.copy(node) : node; // HNPERF: If !browser bump Performance? Is this too dangerous to reference root graph? Copy / shallow copy too expensive for big nodes. Gun.obj.to(node); // 1 layer deep copy // Gun.obj.copy(node); // too slow on big nodes var S = +new Date; var ack = msg['#'], id = text_rand(9), keys = Object.keys(node||''), soul = ((node||'')._||'')['#'], kl = keys.length, j = 0; - console.STAT && console.STAT(S, +new Date - S, 'got keys'); + console.STAT && console.STAT(S, ((DBG||ctx).gk = +new Date) - S, 'got keys'); // PERF: Consider commenting this out to force disk-only reads for perf testing? // TODO: .keys( is slow node && (function got(){ S = +new Date; @@ -434,7 +436,7 @@ tmp = keys.length; console.STAT && console.STAT(S, -(S - (S = +new Date)), 'got copied some'); DBG && (DBG.ga = +new Date); - root.on('in', {'@': ack, '#': id, put: put, '%': (tmp? (id = text_rand(9)) : u), ram: 1, $: gun, _: faith}); + root.on('in', {'@': ack, '#': id, put: put, '%': (tmp? (id = text_rand(9)) : u), ram: 1, $: gun, _: faith, DBG: DBG}); console.STAT && console.STAT(S, +new Date - S, 'got in'); //root.on('in', {'@': ack, '#': text_rand(9), put: put, '%': tmp? ((j+=i)+'/'+kl) : u, ram: 1, $: gun, _: faith}); console.log("???", j+'/'+kl); if(!tmp){ return } @@ -1160,14 +1162,15 @@ if(!raw){ return } if(opt.pack <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) } if(mesh === this){ - if('string' == typeof raw){ try{ + /*if('string' == typeof raw){ try{ var stat = console.STAT || {}; //console.log('HEAR:', peer.id, (raw||'').slice(0,250), ((raw||'').length / 1024 / 1024).toFixed(4)); - console.log(setTimeout.turn.s.length, 'stacks', parseFloat((-(LT - (LT = +new Date))/1000).toFixed(3)), 'sec', parseFloat(((LT-ST)/1000 / 60).toFixed(1)), 'up', stat.peers||0, 'peers', stat.has||0, 'has', stat.memhused||0, stat.memused||0, stat.memax||0, 'heap mem max'); - }catch(e){ console.log('DBG err', e) }} + //console.log(setTimeout.turn.s.length, 'stacks', parseFloat((-(LT - (LT = +new Date))/1000).toFixed(3)), 'sec', parseFloat(((LT-ST)/1000 / 60).toFixed(1)), 'up', stat.peers||0, 'peers', stat.has||0, 'has', stat.memhused||0, stat.memused||0, stat.memax||0, 'heap mem max'); + }catch(e){ console.log('DBG err', e) }}*/ hear.d += raw.length||0 ; ++hear.c } // STATS! + var S = peer.SH = +new Date; var tmp = raw[0], msg; if('[' === tmp){ parse(raw, function(err, msg){ @@ -1188,17 +1191,18 @@ return; } if('{' === tmp || ((raw['#'] || Object.plain(raw)) && (msg = raw))){ - if(msg){ return hear.one(msg, peer) } + if(msg){ return hear.one(msg, peer, S) } parse(raw, function(err, msg){ if(err || !msg){ return mesh.say({dam: '!', err: "DAM JSON parse error."}, peer) } - hear.one(msg, peer); + hear.one(msg, peer, S); }); return; } } - hear.one = function(msg, peer){ + hear.one = function(msg, peer, S){ // S here is temporary! Undo. var id, hash, tmp, ash, DBG; if(msg.DBG){ msg.DBG = DBG = {DBG: msg.DBG} } + DBG && (DBG.h = S); DBG && (DBG.hp = +new Date); if(!(id = msg['#'])){ id = msg['#'] = String.random(9) } if(tmp = dup_check(id)){ return } @@ -1215,12 +1219,12 @@ dup_track(id); return; } - var S = +new Date, ST; - DBG && (DBG.is = S); + var S = +new Date; + DBG && (DBG.is = S); peer.SI = id; root.on('in', mesh.last = msg); //ECHO = msg.put || ECHO; !(msg.ok !== -3740) && mesh.say({ok: -3740, put: ECHO, '@': msg['#']}, peer); DBG && (DBG.hd = +new Date); - console.STAT && (ST = +new Date - S) > 9 && console.STAT(S, ST, 'msg'); // TODO: PERF: caught one > 1.5s on tgif + console.STAT && console.STAT(S, +new Date - S, msg.get? 'msg get' : msg.put? 'msg put' : 'msg'); (tmp = dup_track(id)).via = peer; // don't dedup message ID till after, cause GUN has internal dedup check. if(msg.get){ tmp.it = msg } if(ash){ dup_track(ash) } //dup.track(tmp+hash, true).it = it(msg); @@ -1250,14 +1254,16 @@ if((tmp = this) && (tmp = tmp.to) && tmp.next){ tmp.next(msg) } // compatible with middleware adapters. if(!msg){ return false } var id, hash, raw, ack = msg['@']; - if((!ack || !msg.put)){ return } // TODO: MANHATTAN STUB //OBVIOUSLY BUG! But squelch relay. - var DBG = msg.DBG, S; if(!peer){ S = +new Date ; DBG && (DBG.y = S) } + if(opt.super && (!ack || !msg.put)){ return } // TODO: MANHATTAN STUB //OBVIOUSLY BUG! But squelch relay. // :( get only is 100%+ CPU usage :( var meta = msg._||(msg._=function(){}); + var DBG = msg.DBG, S = +new Date; meta.y = meta.y || S; if(!peer){ DBG && (DBG.y = S) } if(!(id = msg['#'])){ id = msg['#'] = String.random(9) } !loop && dup_track(id);//.it = it(msg); // track for 9 seconds, default. Earth<->Mars would need more! // always track, maybe move this to the 'after' logic if we split function. if(msg.put && (msg.err || (dup.s[id]||'').err)){ return false } // stop relaying a invalid message, like failed SEA. if(!(hash = msg['##']) && u !== msg.put && !meta.via && ack){ mesh.hash(msg, peer); return } // TODO: Should broadcasts be hashed? + DBG && (DBG.yh = +new Date); if(!(raw = meta.raw)){ mesh.raw(msg, peer); return } + DBG && (DBG.yr = +new Date); if(!peer && ack){ peer = ((tmp = dup.s[ack]) && (tmp.via || ((tmp = tmp.it) && (tmp = tmp._) && tmp.via))) || mesh.leap } // warning! mesh.leap could be buggy! if(!peer && ack){ console.STAT && console.STAT(+new Date, ++SMIA, 'total no peer to ack to'); @@ -1291,6 +1297,7 @@ if(id === peer.last){ return } peer.last = id; // was it just sent? if(peer === meta.via){ return false } // don't send back to self. if((tmp = meta.yo) && (tmp[peer.url] || tmp[peer.pid] || tmp[peer.id]) /*&& !o*/){ return false } + console.STAT && console.STAT(S, ((DBG||meta).yp = +new Date) - (meta.y || S), 'say prep'); if(peer.batch){ peer.tail = (tmp = peer.tail || 0) + raw.length; if(peer.tail <= opt.pack){ @@ -1300,12 +1307,13 @@ flush(peer); } peer.batch = '['; // Prevents double JSON! - var S = +new Date, ST; + var ST = +new Date; setTimeout(function(){ - console.STAT && (ST = +new Date - S) > 9 && console.STAT(S, ST, '0ms TO', id, peer.id); + console.STAT && console.STAT(ST, +new Date - ST, '0ms TO'); flush(peer); }, opt.gap); // TODO: queuing/batching might be bad for low-latency video game performance! Allow opt out? send(raw, peer); + console.STAT && (ack === peer.SI) && console.STAT(S, +new Date - peer.SH, 'say ack'); } mesh.say.c = mesh.say.d = 0; // TODO: this caused a out-of-memory crash! @@ -1426,7 +1434,7 @@ var gets = {}; root.on('bye', function(peer, tmp){ this.to.next(peer); - if(tmp = console.STAT){ tmp.peers = (tmp.peers || 0) - 1; console.log('bye', tmp.peers) } + if(tmp = console.STAT){ tmp.peers = (tmp.peers || 0) - 1; } if(!(tmp = peer.url)){ return } gets[tmp] = true; setTimeout(function(){ delete gets[tmp] },opt.lack || 9000); }); diff --git a/lib/stats.js b/lib/stats.js index 96ae618b..47f296c8 100644 --- a/lib/stats.js +++ b/lib/stats.js @@ -20,6 +20,7 @@ Gun.on('opt', function(root){ os.freemem = os.freemem || noop; os.loadavg = os.loadavg || noop; os.cpus = os.cpus || noop; + var S = +new Date, W; var obj_ify = function(o){try{o = JSON.parse(o)}catch(e){o={}};return o;} setTimeout(function(){ root.stats = obj_ify((fs.existsSync(__dirname+'/../stats.'+(root.opt.file||file)) && fs.readFileSync(__dirname+'/../stats.'+(root.opt.file||file)).toString())) || {}; @@ -27,14 +28,13 @@ Gun.on('opt', function(root){ root.stats.up.start = root.stats.up.start || +(new Date); root.stats.up.count = (root.stats.up.count || 0) + 1; root.stats.stay = root.stats.stay || {}; - root.stats.gap = {}; root.stats.over = +new Date; },1); setInterval(function(){ if(!root.stats){ root.stats = {} } - var S = +new Date; + if(W){ return } var stats = root.stats, tmp; - stats.over = S - (stats.over||S); + stats.over = -(S - (S = +new Date)); (stats.up||{}).time = process.uptime(); stats.memory = process.memoryUsage() || {}; stats.memory.totalmem = os.totalmem(); @@ -43,7 +43,8 @@ Gun.on('opt', function(root){ stats.cpu.loadavg = os.loadavg(); stats.cpu.stack = (((setTimeout||'').turn||'').s||'').length; stats.peers = {}; - stats.peers.count = Object.keys(root.opt.peers||{}).length; // TODO: .keys( is slow + + stats.peers.count = console.STAT.peers || Object.keys(root.opt.peers||{}).length; // TODO: .keys( is slow stats.node = {}; stats.node.count = Object.keys(root.graph||{}).length; // TODO: .keys( is slow stats.all = all; @@ -59,17 +60,13 @@ Gun.on('opt', function(root){ stats.rad = rad; root.opt.store.stats = {get:{time:{}, count:0}, put: {time:{}, count:0}}; // reset } - console.STAT && console.STAT(S, +new Date - S, 'stats'); - S = +new Date; - JSON.stringifyAsync(stats, function(err, raw){ if(err){ return } - fs.writeFile(__dirname+'/../stats.'+(root.opt.file||file), raw, function(err){ err && console.log(console.STAT.err = err); console.STAT && console.STAT(S, +new Date - S, 'stats stash') }); + JSON.stringifyAsync(stats, function(err, raw){ if(err){ return } W = true; + fs.writeFile(__dirname+'/../stats.'+(root.opt.file||file), raw, function(err){ W = false; err && console.log(console.STAT.err = err); console.STAT && console.STAT(S, +new Date - S, 'stats stash') }); }); - stats.over = S; - stats.gap = {}; //exec("top -b -n 1", function(err, out){ out && fs.writeFile(__dirname+'/../stats.top.'+(root.opt.file||file), out, noop) }); // was it really seriously actually this? //}, 1000 * 15); - }, 1000 * 1); + }, 1000 * 5); }); var exec = require("child_process").exec, noop = function(){};