From 1e68c2d602eead2076b6a103eac35859c83702a2 Mon Sep 17 00:00:00 2001 From: kanoi Date: Sat, 14 Mar 2015 14:10:54 +1100 Subject: [PATCH 01/11] ckdb/php - pass statsconfirmed to php to flag estimate stats --- pool/page_blocks.php | 14 ++++++++++---- src/ckdb.h | 2 +- src/ckdb_cmd.c | 11 ++++++++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/pool/page_blocks.php b/pool/page_blocks.php index 1556323c..ba07472f 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -182,6 +182,12 @@ function doblocks($data, $user) if ($stat == 'Orphan') $stara = '*'; + $statsconf = $ans['statsconf:'.$i]; + if ($statsconf == 'Y') + $approx = ''; + else + $approx = '~'; + $diffacc = $ans['diffacc:'.$i]; $acc = number_format($diffacc, 0); @@ -200,7 +206,7 @@ function doblocks($data, $user) if ($stat != 'Orphan') $nettot += $netdiff; - $cdfdsp = number_format($cdf, 2); + $cdfdsp = number_format($cdf, 3); } else { @@ -218,9 +224,9 @@ function doblocks($data, $user) $pg .= "".htmlspecialchars($ans['workername:'.$i]).''; $pg .= "".btcfmt($ans['reward:'.$i]).''; $pg .= "".utcd($ans['firstcreatedate:'.$i]).''; - $pg .= "".$stat.''; - $pg .= "$stara$acc"; - $pg .= "$bpct"; + $pg .= "$stat"; + $pg .= "$stara$approx$acc"; + $pg .= "$approx$bpct"; $pg .= "$cdfdsp"; $pg .= "\n"; } diff --git a/src/ckdb.h b/src/ckdb.h index 6893ecfa..199d2361 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.031" +#define CKDB_VERSION DB_VERSION"-1.032" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 93c42a69..6a0e1cc3 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -902,6 +902,11 @@ redo: blocks_confirmed(blocks->confirmed), FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + snprintf(tmp, sizeof(tmp), + "statsconf:%d=%s%c", rows, + blocks->statsconfirmed, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + double_to_buf(blocks->diffacc, reply, sizeof(reply)); snprintf(tmp, sizeof(tmp), "diffacc:%d=%s%c", rows, reply, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); @@ -1016,8 +1021,8 @@ redo: "rows=%d%cflds=%s%c", rows, FLDSEP, "seq,height,blockhash,nonce,reward,workername,firstcreatedate," - "createdate,status,diffacc,diffinv,shareacc,shareinv,elapsed," - "netdiff,diffratio,cdf,luck", FLDSEP); + "createdate,status,statsconf,diffacc,diffinv,shareacc," + "shareinv,elapsed,netdiff,diffratio,cdf,luck", FLDSEP); APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks,BlockStats", FLDSEP, ",s"); @@ -5446,7 +5451,7 @@ struct CMDS ckdb_cmds[] = { { CMD_WORKERSTAT,"workerstats", false, true, cmd_workerstats,ACCESS_POOL }, { CMD_BLOCK, "block", false, true, cmd_blocks, ACCESS_POOL }, { CMD_BLOCKLIST,"blocklist", false, false, cmd_blocklist, ACCESS_WEB }, - { CMD_BLOCKSTATUS,"blockstatus",false, false, cmd_blockstatus,ACCESS_WEB }, + { CMD_BLOCKSTATUS,"blockstatus",false, false, cmd_blockstatus,ACCESS_SYSTEM }, { CMD_NEWID, "newid", false, false, cmd_newid, ACCESS_SYSTEM }, { CMD_PAYMENTS, "payments", false, false, cmd_payments, ACCESS_WEB }, { CMD_WORKERS, "workers", false, false, cmd_workers, ACCESS_WEB }, From e355d93bedf6e32ea86ef6aaa330f4e05e5e66b1 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 17 Mar 2015 01:53:35 +1100 Subject: [PATCH 02/11] php - add a simple shift perfomance graph --- html/can.js | 54 +++++++++++++++++++++++++++++++++++++++++++ pool/db.php | 55 ++++++++++++++++++++++++++++++++++++++++++-- pool/page_blocks.php | 12 ++++++---- pool/page_usperf.php | 26 +++++++++++++++++++++ pool/prime.php | 5 ++-- 5 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 html/can.js create mode 100644 pool/page_usperf.php diff --git a/html/can.js b/html/can.js new file mode 100644 index 00000000..06882e01 --- /dev/null +++ b/html/can.js @@ -0,0 +1,54 @@ +function hasCan(){var c=document.getElementById('can');return !!(c.getContext&&c.getContext('2d'));} +function sep(d){ans={};var ar=d.split("\t");var l=ar.length;for(var i=0;i(zm-1)){return(zm-1)}return z} +function gchx(c,x){return gch(x*c['xm']+c['xo'],c['ctx'].canvas.width)} +function gchy(c,y){return gch((1-y)*c['ym']+c['yo'],c['ctx'].canvas.height)} +function gx0(c){return -c['xo']/c['xm']}; +function gy0(c){return -c['yo']/c['ym']}; +function gto(c,xo,yo){c['xo']+=xo;c['yo']+=yo} +function gts(c,xs,ys){c['xm']*=xs;c['ym']*=ys} +function gtso(c,xs,ys){gto(c,c['xm']*(1.0-xs)/2.0,c['ym']*(1.0-ys)/2.0);gts(c,xs,ys)} +function gfs(c,bg){c['ctx'].fillStyle=bg} +function gss(c,fg){c['ctx'].strokeStyle=fg} +function glw(c,pct){c['ctx'].lineWidth=pct*c['ym']/100.0} +function glwr(c,rat){c['ctx'].lineWidth*=rat} +function gfz(c,x,y,ox,oy,t,co,a){gfs(c,co);c['ctx'].textAlign=a;c['ctx'].fillText(t,gchx(c,x)+ox,gchy(c,y)-oy)} +function gbe(c,x,y){c['ctx'].beginPath();c['ctx'].moveTo(gchx(c,x),gchy(c,y))} +function gln(c,x,y){c['ctx'].lineTo(gchx(c,x),gchy(c,y))} +function glm(c,x,y){c['ctx'].moveTo(gchx(c,x),gchy(c,y))} +function gle(c){c['ctx'].closePath()} +function gfl(c){c['ctx'].fill()} +function gst(c){c['ctx'].stroke()} +function gfi(c){gle(c);gst(c)} +function gbd(c){gbe(c,0,0);gln(c,1,0);gln(c,1,1);gln(c,0,1);gle(c);gfl(c);gst(c)} +function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av){ +gtso(c,xs,ys); +gss(c,'black');glw(c,0.25); +gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c); +glwr(c,0.1); +var hi=c['ctx'].measureText('M').width; +var wi=c['ctx'].measureText('1').width; +for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')} +gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left'); +var m=Math.round(0.5+xn/20.0); +var f=1; +for(var i=0;ic['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx'].canvas.width=c['xm'];c['ctx'].canvas.height=c['ym']} +function gdrw(d){var c={};gc(c); +gfs(c,'white');gss(c,'black');glw(c,1);gbd(c); +var rows=d['rows'];var ymin=-1;var ymax=0;var xmin=-1;var xmax=0; +var tda=0; +for(var i=0;iths){ymin=ths}if(ths>ymax)ymax=ths;d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax $user); + $msg = msgEncode('shifts', 'shift', $flds, $user); + $rep = sendsockreply('getShifts', $msg); + if (!$rep) + dbdown(); + return repData($rep); +} +# function getBlocks($user) { if ($user == false) diff --git a/pool/page_blocks.php b/pool/page_blocks.php index ba07472f..c294ba4c 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -182,11 +182,15 @@ function doblocks($data, $user) if ($stat == 'Orphan') $stara = '*'; - $statsconf = $ans['statsconf:'.$i]; - if ($statsconf == 'Y') - $approx = ''; + if (isset($ans['statsconf:'.$i])) + { + if ($ans['statsconf:'.$i] == 'Y') + $approx = ''; + else + $approx = '~'; + } else - $approx = '~'; + $approx = ''; $diffacc = $ans['diffacc:'.$i]; $acc = number_format($diffacc, 0); diff --git a/pool/page_usperf.php b/pool/page_usperf.php new file mode 100644 index 00000000..12e31e39 --- /dev/null +++ b/pool/page_usperf.php @@ -0,0 +1,26 @@ +User Shift Performance
'; + if ($ans['STATUS'] == 'ok' and $ans['DATA'] != '') + { + $pg .= ""; + $pg .= "A graph will show here if your browser supports html5/canvas"; + $pg .= "\n"; + $data = str_replace(array("\\","'"), array("\\\\","\\'"), $ans['DATA']); + $pg .= "\n"; + $pg .= "\n"; + } + + return $pg; +} +# +function show_usperf($info, $page, $menu, $name, $user) +{ + gopage($info, NULL, 'dousperf', $page, $menu, $name, $user); +} +# +?> diff --git a/pool/prime.php b/pool/prime.php index 6ee31cfb..9c0d2706 100644 --- a/pool/prime.php +++ b/pool/prime.php @@ -76,8 +76,9 @@ function check() 'User Settings' => 'userset' ), 'Workers' => array( - 'Shifts ' => 'shifts', - 'Workers ' => 'workers', + 'Shifts' => 'shifts', + 'Shift Graph' => 'usperf', + 'Workers' => 'workers', 'Management' => 'workmgt', ), 'Pool' => array( From 92675ab165f05a0c9b87d57c94c1d46d4b72ac98 Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 17 Mar 2015 02:07:14 +1100 Subject: [PATCH 03/11] php - correct graph base --- html/can.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/html/can.js b/html/can.js index 06882e01..b56e4f6d 100644 --- a/html/can.js +++ b/html/can.js @@ -49,6 +49,6 @@ var tda=0; for(var i=0;iths){ymin=ths}if(ths>ymax)ymax=ths;d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax Date: Tue, 17 Mar 2015 11:58:40 +1100 Subject: [PATCH 04/11] php - graph enhancements --- html/can.js | 22 ++++++++++++---------- pool/page_usperf.php | 12 +++++++++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/html/can.js b/html/can.js index b56e4f6d..a6c43794 100644 --- a/html/can.js +++ b/html/can.js @@ -1,6 +1,6 @@ -function hasCan(){var c=document.getElementById('can');return !!(c.getContext&&c.getContext('2d'));} +function hasCan(){var c0=document.getElementById('can0');c=document.getElementById('can');return !!(c0&&c&&c.getContext&&c.getContext('2d'));} function sep(d){ans={};var ar=d.split("\t");var l=ar.length;for(var i=0;i(zm-1)){return(zm-1)}return z} +function gch(z,zm){if(z<0.5){return 0.5}if(z>(zm-0.5)){return(zm-0.5)}return z} function gchx(c,x){return gch(x*c['xm']+c['xo'],c['ctx'].canvas.width)} function gchy(c,y){return gch((1-y)*c['ym']+c['yo'],c['ctx'].canvas.height)} function gx0(c){return -c['xo']/c['xm']}; @@ -23,32 +23,34 @@ function gfi(c){gle(c);gst(c)} function gbd(c){gbe(c,0,0);gln(c,1,0);gln(c,1,1);gln(c,0,1);gle(c);gfl(c);gst(c)} function ggr(c,xs,ys,yt,xn,x0,x1,y0,y1,ar,nx,vx,vy,av){ gtso(c,xs,ys); -gss(c,'black');glw(c,0.25); +gss(c,'black');glw(c,0.2); gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c); -glwr(c,0.1); +glw(c,0.01); var hi=c['ctx'].measureText('M').width; var wi=c['ctx'].measureText('1').width; for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')} gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left'); var m=Math.round(0.5+xn/20.0); var f=1; -for(var i=0;ic['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx'].canvas.width=c['xm'];c['ctx'].canvas.height=c['ym']} -function gdrw(d){var c={};gc(c); -gfs(c,'white');gss(c,'black');glw(c,1);gbd(c); +function gc(c,ok){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['ok']=ok} +function gdrw(ok,d){var c={};gc(c,ok); +gfs(c,'white');gss(c,'#0000c0');glw(c,0.5);gbd(c); var rows=d['rows'];var ymin=-1;var ymax=0;var xmin=-1;var xmax=0; var tda=0; for(var i=0;iths){ymin=ths}if(ths>ymax)ymax=ths;d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax Date: Wed, 18 Mar 2015 02:14:03 +1100 Subject: [PATCH 05/11] php - add display options to the graph --- html/can.js | 19 +++++++++++-------- pool/page.php | 1 + pool/page_usperf.php | 12 +++++++++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/html/can.js b/html/can.js index a6c43794..032e8c65 100644 --- a/html/can.js +++ b/html/can.js @@ -15,6 +15,7 @@ function glwr(c,rat){c['ctx'].lineWidth*=rat} function gfz(c,x,y,ox,oy,t,co,a){gfs(c,co);c['ctx'].textAlign=a;c['ctx'].fillText(t,gchx(c,x)+ox,gchy(c,y)-oy)} function gbe(c,x,y){c['ctx'].beginPath();c['ctx'].moveTo(gchx(c,x),gchy(c,y))} function gln(c,x,y){c['ctx'].lineTo(gchx(c,x),gchy(c,y))} +function gct(c,x1,y1,x2,y2,x3,y3){c['ctx'].bezierCurveTo(gchx(c,x1),gchy(c,y1),gchx(c,x2),gchy(c,y2),gchx(c,x3),gchy(c,y3))} function glm(c,x,y){c['ctx'].moveTo(gchx(c,x),gchy(c,y))} function gle(c){c['ctx'].closePath()} function gfl(c){c['ctx'].fill()} @@ -26,16 +27,17 @@ gtso(c,xs,ys); gss(c,'black');glw(c,0.2); gbe(c,0,1);gln(c,0,0);gln(c,1,0);gst(c); glw(c,0.01); -var hi=c['ctx'].measureText('M').width; -var wi=c['ctx'].measureText('1').width; +var hi=c['ctx'].measureText('M').width, wi=c['ctx'].measureText('1').width; for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+(((y1-y0)*i/10+y0).toFixed(2));gfz(c,0,y,-wi,0,t,'black','end')} gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left'); var m=Math.round(0.5+xn/20.0); var f=1; -for(var i=0;ic['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);c['ok']=ok} -function gdrw(ok,d){var c={};gc(c,ok); +function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);div=document.getElementById('smooth');c['smooth']=(div&&div.checked);div=document.getElementById('vlines');c['vlines']=(div&&div.checked);div=document.getElementById('zerob');c['zerob']=(div&&div.checked)} +function gdrw(d){var c={};gc(c); gfs(c,'white');gss(c,'#0000c0');glw(c,0.5);gbd(c); -var rows=d['rows'];var ymin=-1;var ymax=0;var xmin=-1;var xmax=0; +var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0; var tda=0; for(var i=0;iths){ymin=ths}if(ths>ymax)ymax=ths;d['nx:'+i]=sn(i,d['shift:'+i]);if(xmin==-1||xmin>s){xmin=s}if(xmax Date: Wed, 18 Mar 2015 03:45:40 +1100 Subject: [PATCH 06/11] php - graph time display options --- html/can.js | 8 ++++++-- pool/page_usperf.php | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/html/can.js b/html/can.js index 032e8c65..1c69bf14 100644 --- a/html/can.js +++ b/html/can.js @@ -1,5 +1,6 @@ function hasCan(){var c0=document.getElementById('can0');c=document.getElementById('can');return !!(c0&&c&&c.getContext&&c.getContext('2d'));} function sep(d){ans={};var ar=d.split("\t");var l=ar.length;for(var i=0;i(zm-0.5)){return(zm-0.5)}return z} function gchx(c,x){return gch(x*c['xm']+c['xo'],c['ctx'].canvas.width)} function gchy(c,y){return gch((1-y)*c['ym']+c['yo'],c['ctx'].canvas.height)} @@ -32,7 +33,10 @@ for(var i=0;i<11;i++){var y=i/10.0;gbe(c,-0.01,y);gln(c,1,y);gst(c);var t=''+((( gfz(c,gx0(c),0.55,wi,0,yt,'#0080ff','left'); var m=Math.round(0.5+xn/20.0); var f=1; -for(var i=0;i=x0;i-=(6*3600)){var n=dfmt(i);var xo=(i-x0)/(x1-x0);if(c['tkey']){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*1.5,n,'brown','center')}if(c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}} glw(c,0.1); gss(c,'black'); if(c['smooth']){var xa=0,ya=0,xb=0,yb=0; @@ -45,7 +49,7 @@ gbe(c,0,y);gln(c,1,y);gst(c); var t=''+av.toFixed(2);gfz(c,1,y,1,0,t,'red','left') } function sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}} -function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);div=document.getElementById('smooth');c['smooth']=(div&&div.checked);div=document.getElementById('vlines');c['vlines']=(div&&div.checked);div=document.getElementById('zerob');c['zerob']=(div&&div.checked)} +function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);div=document.getElementById('smooth');c['smooth']=(div&&div.checked);div=document.getElementById('skey');c['skey']=(div&&div.checked);div=document.getElementById('slines');c['slines']=(div&&div.checked);div=document.getElementById('tkey');c['tkey']=(div&&div.checked);div=document.getElementById('tlines');c['tlines']=(div&&div.checked);div=document.getElementById('zerob');c['zerob']=(div&&div.checked)} function gdrw(d){var c={};gc(c); gfs(c,'white');gss(c,'#0000c0');glw(c,0.5);gbd(c); var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0; diff --git a/pool/page_usperf.php b/pool/page_usperf.php index b098bdba..4c8aeed3 100644 --- a/pool/page_usperf.php +++ b/pool/page_usperf.php @@ -13,10 +13,13 @@ function dousperf($data, $user) $pg = '

User Shift Performance


'; if ($ans['STATUS'] == 'ok' and $ans['DATA'] != '') { - $pg .= "
Date: Wed, 18 Mar 2015 04:10:45 +1100 Subject: [PATCH 07/11] php - optionally draw time key below shift key --- html/can.js | 5 +++-- pool/page_usperf.php | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/html/can.js b/html/can.js index 1c69bf14..a7504f93 100644 --- a/html/can.js +++ b/html/can.js @@ -36,7 +36,8 @@ var f=1; for(var i=0;i=x0;i-=(6*3600)){var n=dfmt(i);var xo=(i-x0)/(x1-x0);if(c['tkey']){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*1.5,n,'brown','center')}if(c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}} +var tpos=2.7;if(c['over']){tpos=1.5} +for(var i=xhr;i>=x0;i-=(6*3600)){var n=dfmt(i);var xo=(i-x0)/(x1-x0);if(c['tkey']){gbe(c,xo,0);gln(c,xo,-0.02);gst(c);gfz(c,xo,0,0,-hi*tpos,n,'brown','center')}if(c['tlines']){gbe(c,xo,0);gln(c,xo,1);gst(c)}} glw(c,0.1); gss(c,'black'); if(c['smooth']){var xa=0,ya=0,xb=0,yb=0; @@ -49,7 +50,7 @@ gbe(c,0,y);gln(c,1,y);gst(c); var t=''+av.toFixed(2);gfz(c,1,y,1,0,t,'red','left') } function sn(i,shi){if(shi.indexOf(' Shift ')<0){return ''+(i%10)}else{return shi.replace(/.* ([a-z])[a-z]*$/,'$1')}} -function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);div=document.getElementById('smooth');c['smooth']=(div&&div.checked);div=document.getElementById('skey');c['skey']=(div&&div.checked);div=document.getElementById('slines');c['slines']=(div&&div.checked);div=document.getElementById('tkey');c['tkey']=(div&&div.checked);div=document.getElementById('tlines');c['tlines']=(div&&div.checked);div=document.getElementById('zerob');c['zerob']=(div&&div.checked)} +function gc(c){var div=document.getElementById('can0');while(div.firstChild){div.removeChild(div.firstChild)}c['can']=document.createElement('canvas');c['can'].id='can';c['wx']=window.innerWidth;c['wy']=window.innerHeight;c['xm']=Math.round(c['wx']*0.9+0.5);c['ym']=Math.round(c['wy']*0.8+0.5);if(c['ym']>c['xm']){c['ym']=c['xm']}c['xo']=0.0;c['yo']=0.0;c['ctx']=c['can'].getContext('2d');c['ctx'].canvas.width=c['xm']+1;c['ctx'].canvas.height=c['ym']+1;div.appendChild(c['can']);div=document.getElementById('smooth');c['smooth']=(div&&div.checked);div=document.getElementById('over');c['over']=(div&&div.checked);div=document.getElementById('skey');c['skey']=(div&&div.checked);div=document.getElementById('slines');c['slines']=(div&&div.checked);div=document.getElementById('tkey');c['tkey']=(div&&div.checked);div=document.getElementById('tlines');c['tlines']=(div&&div.checked);div=document.getElementById('zerob');c['zerob']=(div&&div.checked)} function gdrw(d){var c={};gc(c); gfs(c,'white');gss(c,'#0000c0');glw(c,0.5);gbd(c); var rows=d['rows'],ymin=-1,ymax=0,xmin=-1,xmax=0; diff --git a/pool/page_usperf.php b/pool/page_usperf.php index 4c8aeed3..650df30f 100644 --- a/pool/page_usperf.php +++ b/pool/page_usperf.php @@ -20,6 +20,7 @@ function dousperf($data, $user) $pg .= ">shift lines "; $pg .= " time key "; $pg .= " time lines "; + $pg .= " key overlap "; $pg .= " smooth "; $pg .= " zero based
"; $pg .= "
"; From bf1c2ef09bb39f377011db00a4d0d8d449b4cc53 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Wed, 18 Mar 2015 16:00:18 +1100 Subject: [PATCH 08/11] Cope with variable length ckdb responses on the heartbeat as well --- src/stratifier.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 0c732c72..32123a6d 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2350,6 +2350,7 @@ static int send_recv_auth(stratum_instance_t *client) sdata_t *sdata = ckp->data; char *buf = NULL, *json_msg; bool contended = false; + size_t responselen = 0; char cdfield[64]; int ret = 1; json_t *val; @@ -2389,15 +2390,16 @@ static int send_recv_auth(stratum_instance_t *client) contended = true; free(json_msg); - if (likely(buf)) { + /* Leave ample room for response based on buf length */ + if (likely(buf)) + responselen = strlen(buf); + if (likely(responselen > 0)) { char *cmd = NULL, *secondaryuserid = NULL, *response; worker_instance_t *worker = client->worker_instance; json_error_t err_val; - size_t responselen; json_t *val = NULL; LOGINFO("Got ckdb response: %s", buf); - responselen = strlen(buf); /* Leave ample room for response based on buf length */ response = alloca(responselen); memset(response, 0, responselen); if (unlikely(sscanf(buf, "id.%*d.%s", response) < 1 || strlen(response) < 1 || !strchr(response, '='))) { @@ -3782,6 +3784,7 @@ static bool test_and_clear(bool *val, mutex_t *lock) static void ckdbq_process(ckpool_t *ckp, char *msg) { sdata_t *sdata = ckp->data; + size_t responselen = 0; char *buf = NULL; while (!buf) { @@ -3801,9 +3804,12 @@ static void ckdbq_process(ckpool_t *ckp, char *msg) /* Process any requests from ckdb that are heartbeat responses with * specific requests. */ - if (likely(buf)) { - char response[PAGESIZE] = {}; + if (likely(buf)) + responselen = strlen(buf); + if (likely(responselen > 0)) { + char *response = alloca(responselen); + memset(response, 0, responselen); sscanf(buf, "id.%*d.%s", response); if (safecmp(response, "ok")) { char *cmd; From b32080e9a59bf10494d6afca6d2e48dae53596f5 Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 18 Mar 2015 23:51:07 +1100 Subject: [PATCH 09/11] ckdb - setup the first mandatory mark on a new pool --- src/ckdb.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ckdb.h | 3 ++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/ckdb.c b/src/ckdb.c index ecf4af24..6d12e221 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -1885,6 +1885,64 @@ static void make_a_shift_mark() char cd_buf[DATE_BUFSIZ], cd_buf2[DATE_BUFSIZ]; int used_wid; + /* If there are no CURRENT marks, make the first one by + * finding the first CURRENT workinfo and use that + * to create a MARKTYPE_OTHER_BEGIN for the pool + * This will keep being checked when the pool first starts + * until the first workinfo is created, but once the first + * marks has been created it will skip over the if code + * forever after that */ + K_RLOCK(marks_free); + m_item = last_in_ktree(marks_root, m_ctx); + K_RUNLOCK(marks_free); + DATA_MARKS_NULL(marks, m_item); + // Mark sorting means all CURRENT will be on the end + if (!m_item || !CURRENT(&(marks->expirydate))) { + K_RLOCK(workinfo_free); + wi_item = first_in_ktree(workinfo_root, wi_ctx); + DATA_WORKINFO_NULL(workinfo, wi_item); + if (!wi_item) { + K_RUNLOCK(workinfo_free); + LOGWARNING("%s() ckdb workinfo:'%s' marks:'%s' ..." + " start ckpool!", __func__, + "none", m_item ? "expired" : "none"); + return; + } + while (wi_item && !CURRENT(&(workinfo->expirydate))) { + wi_item = next_in_ktree(wi_ctx); + DATA_WORKINFO_NULL(workinfo, wi_item); + } + if (!wi_item) { + K_RUNLOCK(workinfo_free); + LOGWARNING("%s() ckdb workinfo:'%s' marks:'%s' ..." + " start ckpool!", __func__, + "expired", m_item ? "expired" : "none"); + return; + } + K_RUNLOCK(workinfo_free); + char description[TXT_BIG+1]; + tv_t now; + ok = marks_description(description, sizeof(description), + MARKTYPE_OTHER_BEGIN_STR, 0, NULL, + "Pool Start"); + if (!ok) + return; + + setnow(&now); + ok = marks_process(NULL, true, EMPTY, workinfo->workinfoid, + description, EMPTY, MARKTYPE_OTHER_BEGIN_STR, + MARK_USED_STR, (char *)by_default, + (char *)__func__, (char *)inet_default, + &now, NULL); + if (ok) { + LOGWARNING("%s() FIRST mark %"PRId64"/%s/%s/%s/", + __func__, workinfo->workinfoid, + MARKTYPE_OTHER_BEGIN_STR, MARK_USED_STR, + description); + } + return; + } + /* Find the last !new sharesummary workinfoid * If the shift needs to go beyond this, then it's not ready yet */ ss_age_wid = 0; diff --git a/src/ckdb.h b/src/ckdb.h index 199d2361..a26a04ac 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.032" +#define CKDB_VERSION DB_VERSION"-1.033" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -1596,6 +1596,7 @@ extern K_STORE *marks_store; #define MARKTYPE_SHIFT_END 'e' // 'o' used for manual marks #define MARKTYPE_OTHER_BEGIN 'o' +#define MARKTYPE_OTHER_BEGIN_STR "o" // 'f' used for manual marks #define MARKTYPE_OTHER_FINISH 'f' From 24d9155f623f0cf5f121bfffc5cbcdbc24360d27 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 19 Mar 2015 11:48:06 +1100 Subject: [PATCH 10/11] Recycle client instances in the connector --- src/connector.c | 58 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/src/connector.c b/src/connector.c index 92665bed..e2a743a4 100644 --- a/src/connector.c +++ b/src/connector.c @@ -23,6 +23,8 @@ #define MAX_MSGSIZE 1024 +typedef struct client_instance client_instance_t; + struct client_instance { /* For clients hashtable */ UT_hash_handle hh; @@ -34,8 +36,8 @@ struct client_instance { int ref; /* For dead_clients list */ - struct client_instance *next; - struct client_instance *prev; + client_instance_t *next; + client_instance_t *prev; struct sockaddr address; char address_name[INET6_ADDRSTRLEN]; @@ -49,8 +51,6 @@ struct client_instance { bool passthrough; }; -typedef struct client_instance client_instance_t; - struct sender_send { struct sender_send *next; struct sender_send *prev; @@ -81,6 +81,8 @@ struct connector_data { client_instance_t *clients; /* Linked list of dead clients no longer in use but may still have references */ client_instance_t *dead_clients; + /* Linked list of client structures we can reuse */ + client_instance_t *recycled_clients; int clients_generated; int dead_generated; @@ -120,6 +122,41 @@ static void dec_instance_ref(cdata_t *cdata, client_instance_t *client) ck_wunlock(&cdata->lock); } +/* Recruit a client structure from a recycled one if available, creating a + * new structure only if we have none to reuse. */ +static client_instance_t *recruit_client(cdata_t *cdata) +{ + client_instance_t *client = NULL; + + ck_wlock(&cdata->lock); + if (cdata->recycled_clients) { + client = cdata->recycled_clients; + DL_DELETE(cdata->recycled_clients, client); + } else + cdata->clients_generated++; + ck_wunlock(&cdata->lock); + + if (!client) { + LOGDEBUG("Connector created new client instance"); + client = ckzalloc(sizeof(client_instance_t)); + } else + LOGDEBUG("Connector recycled client instance"); + return client; +} + +static void __recycle_client(cdata_t *cdata, client_instance_t *client) +{ + memset(client, 0, sizeof(client_instance_t)); + DL_APPEND(cdata->recycled_clients, client); +} + +static void recycle_client(cdata_t *cdata, client_instance_t *client) +{ + ck_wlock(&cdata->lock); + __recycle_client(cdata, client); + ck_wunlock(&cdata->lock); +} + /* Accepts incoming connections on the server socket and generates client * instances */ static int accept_client(cdata_t *cdata, const int epfd, const uint64_t server) @@ -140,7 +177,7 @@ static int accept_client(cdata_t *cdata, const int epfd, const uint64_t server) } sockd = cdata->serverfd[server]; - client = ckzalloc(sizeof(client_instance_t)); + client = recruit_client(cdata); client->server = server; address_len = sizeof(client->address); fd = accept(sockd, &client->address, &address_len); @@ -152,7 +189,7 @@ static int accept_client(cdata_t *cdata, const int epfd, const uint64_t server) return 0; } LOGERR("Failed to accept on socket %d in acceptor", sockd); - dealloc(client); + recycle_client(cdata, client); return -1; } @@ -174,7 +211,7 @@ static int accept_client(cdata_t *cdata, const int epfd, const uint64_t server) LOGWARNING("Unknown INET type for client %d on socket %d", cdata->nfds, fd); Close(fd); - free(client); + recycle_client(cdata, client); return 0; } @@ -189,7 +226,7 @@ static int accept_client(cdata_t *cdata, const int epfd, const uint64_t server) event.events = EPOLLIN; if (unlikely(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) < 0)) { LOGERR("Failed to epoll_ctl add in accept_client"); - free(client); + recycle_client(cdata, client); return 0; } @@ -199,7 +236,6 @@ static int accept_client(cdata_t *cdata, const int epfd, const uint64_t server) __inc_instance_ref(client); ck_wlock(&cdata->lock); - cdata->clients_generated++; client->id = cdata->client_id++; HASH_ADD_I64(cdata->clients, id, client); cdata->nfds++; @@ -263,8 +299,8 @@ static int invalidate_client(ckpool_t *ckp, cdata_t *cdata, client_instance_t *c DL_FOREACH_SAFE(cdata->dead_clients, client, tmp) { if (!client->ref) { DL_DELETE(cdata->dead_clients, client); - LOGINFO("Connector discarding client %"PRId64, client->id); - dealloc(client); + LOGINFO("Connector recycling client %"PRId64, client->id); + __recycle_client(cdata, client); } } ck_wunlock(&cdata->lock); From 655f82f09d6e0b12b646e02a0ba3ff0f94bb45be Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 19 Mar 2015 12:13:58 +1100 Subject: [PATCH 11/11] Remove clients from the epoll list when invalidating them to avoid a receiver event and check they still exist in their original form on getting a receiver event --- src/connector.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/connector.c b/src/connector.c index e2a743a4..424483a8 100644 --- a/src/connector.c +++ b/src/connector.c @@ -72,6 +72,8 @@ struct connector_data { int *serverfd; /* All time count of clients connected */ int nfds; + /* The epoll fd */ + int epfd; bool accept; pthread_t pth_sender; @@ -147,6 +149,7 @@ static client_instance_t *recruit_client(cdata_t *cdata) static void __recycle_client(cdata_t *cdata, client_instance_t *client) { memset(client, 0, sizeof(client_instance_t)); + client->id = -1; DL_APPEND(cdata->recycled_clients, client); } @@ -255,6 +258,7 @@ static int drop_client(cdata_t *cdata, client_instance_t *client) if (fd != -1) { client_id = client->id; + epoll_ctl(cdata->epfd, EPOLL_CTL_DEL, client->fd, NULL); Close(client->fd); HASH_DEL(cdata->clients, client); DL_APPEND(cdata->dead_clients, client); @@ -409,6 +413,19 @@ reparse: goto retry; } +static client_instance_t *ref_client_by_id(cdata_t *cdata, int64_t id) +{ + client_instance_t *client; + + ck_wlock(&cdata->lock); + HASH_FIND_I64(cdata->clients, &id, client); + if (client) + __inc_instance_ref(client); + ck_wunlock(&cdata->lock); + + return client; +} + /* Waits on fds ready to read on from the list stored in conn_instance and * handles the incoming messages */ void *receiver(void *arg) @@ -422,7 +439,7 @@ void *receiver(void *arg) rename_proc("creceiver"); - epfd = epoll_create1(EPOLL_CLOEXEC); + epfd = cdata->epfd = epoll_create1(EPOLL_CLOEXEC); if (epfd < 0) { LOGEMERG("FATAL: Failed to create epoll in receiver"); return NULL; @@ -478,13 +495,18 @@ void *receiver(void *arg) continue; } client = event.data.ptr; + /* Recheck this client still exists in the same form when it + * was queued. */ + client = ref_client_by_id(cdata, client->id); + if (unlikely(!client)) + continue; if ((event.events & EPOLLERR) || (event.events & EPOLLHUP)) { /* Client disconnected */ LOGDEBUG("Client fd %d HUP in epoll", client->fd); invalidate_client(cdata->pi->ckp, cdata, client); - continue; - } - parse_client_msg(cdata, client); + } else + parse_client_msg(cdata, client); + dec_instance_ref(cdata, client); } return NULL; } @@ -645,19 +667,6 @@ static void send_client(cdata_t *cdata, int64_t id, char *buf) mutex_unlock(&cdata->sender_lock); } -static client_instance_t *ref_client_by_id(cdata_t *cdata, int64_t id) -{ - client_instance_t *client; - - ck_wlock(&cdata->lock); - HASH_FIND_I64(cdata->clients, &id, client); - if (client) - __inc_instance_ref(client); - ck_wunlock(&cdata->lock); - - return client; -} - static void passthrough_client(cdata_t *cdata, client_instance_t *client) { char *buf;