diff --git a/LICENSE b/LICENSE index 44983fd1259e..3216134fd4b2 100644 --- a/LICENSE +++ b/LICENSE @@ -216,7 +216,8 @@ core/src/main/resources/org/apache/spark/ui/static/bootstrap* core/src/main/resources/org/apache/spark/ui/static/vis* docs/js/vendor/bootstrap.js connector/spark-ganglia-lgpl/src/main/java/com/codahale/metrics/ganglia/GangliaReporter.java - +core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.min.js +core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.css Python Software Foundation License ---------------------------------- diff --git a/LICENSE-binary b/LICENSE-binary index 30fca96a8832..c6f291f11088 100644 --- a/LICENSE-binary +++ b/LICENSE-binary @@ -413,7 +413,8 @@ core/src/main/java/org/apache/spark/util/collection/TimSort.java core/src/main/resources/org/apache/spark/ui/static/bootstrap* core/src/main/resources/org/apache/spark/ui/static/vis* docs/js/vendor/bootstrap.js - +core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.min.js +core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.css ------------------------------------------------------------------------------------ This product bundles various third-party components under other open source licenses. diff --git a/core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.css b/core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.css new file mode 100644 index 000000000000..92821ef10e0a --- /dev/null +++ b/core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.css @@ -0,0 +1,47 @@ +/** https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/d3-flamegraph.css */ +.d3-flame-graph rect { + stroke: #EEEEEE; + fill-opacity: .8; +} + +.d3-flame-graph rect:hover { + stroke: #474747; + stroke-width: 0.5; + cursor: pointer; +} + +.d3-flame-graph-label { + pointer-events: none; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + font-size: 12px; + font-family: Verdana; + margin-left: 4px; + margin-right: 4px; + line-height: 1.5; + padding: 0 0 0; + font-weight: 400; + color: black; + text-align: left; +} + +.d3-flame-graph .fade { + opacity: 0.6 !important; +} + +.d3-flame-graph .title { + font-size: 20px; + font-family: Verdana; +} + +.d3-flame-graph-tip { + background-color: black; + border: none; + border-radius: 3px; + padding: 5px 10px 5px 10px; + min-width: 250px; + text-align: left; + color: white; + z-index: 10; +} \ No newline at end of file diff --git a/core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.min.js b/core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.min.js new file mode 100644 index 000000000000..babc683f6b69 --- /dev/null +++ b/core/src/main/resources/org/apache/spark/ui/static/d3-flamegraph.min.js @@ -0,0 +1,2 @@ +/** https://cdn.jsdelivr.net/npm/d3-flame-graph@4.1.3/dist/d3-flamegraph.min.js */ +!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.flamegraph=n():t.flamegraph=n()}(self,(function(){return(()=>{"use strict";var t={d:(n,e)=>{for(var r in e)t.o(e,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:e[r]})},o:(t,n)=>Object.prototype.hasOwnProperty.call(t,n)},n={};function e(){}function r(t){return null==t?e:function(){return this.querySelector(t)}}function i(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}function o(){return[]}function u(t){return null==t?o:function(){return this.querySelectorAll(t)}}function a(t){return function(){return this.matches(t)}}function l(t){return function(n){return n.matches(t)}}t.d(n,{default:()=>xr});var s=Array.prototype.find;function c(){return this.firstElementChild}var h=Array.prototype.filter;function f(){return Array.from(this.children)}function p(t){return new Array(t.length)}function d(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function g(t){return function(){return t}}function v(t,n,e,r,i,o){for(var u,a=0,l=n.length,s=o.length;an?1:t>=n?0:NaN}d.prototype={constructor:d,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var b="http://www.w3.org/1999/xhtml";const x={svg:"http://www.w3.org/2000/svg",xhtml:b,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function M(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),x.hasOwnProperty(n)?{space:x[n],local:t}:t}function A(t){return function(){this.removeAttribute(t)}}function N(t){return function(){this.removeAttributeNS(t.space,t.local)}}function k(t,n){return function(){this.setAttribute(t,n)}}function E(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function S(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function C(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function j(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function q(t){return function(){this.style.removeProperty(t)}}function O(t,n,e){return function(){this.style.setProperty(t,n,e)}}function P(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function H(t,n){return t.style.getPropertyValue(n)||j(t).getComputedStyle(t,null).getPropertyValue(n)}function L(t){return function(){delete this[t]}}function T(t,n){return function(){this[t]=n}}function D(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function B(t){return t.trim().split(/^|\s+/)}function X(t){return t.classList||new z(t)}function z(t){this._node=t,this._names=B(t.getAttribute("class")||"")}function R(t,n){for(var e=X(t),r=-1,i=n.length;++r=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}function lt(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var pt=[null];function dt(t,n){this._groups=t,this._parents=n}function gt(){return new dt([[document.documentElement]],pt)}dt.prototype=gt.prototype={constructor:dt,select:function(t){"function"!=typeof t&&(t=r(t));for(var n=this._groups,e=n.length,i=new Array(e),o=0;o=k&&(k=N+1);!(A=b[k])&&++k=0;)(r=i[o])&&(u&&4^r.compareDocumentPosition(u)&&u.parentNode.insertBefore(r,u),u=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=_);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?q:"function"==typeof n?P:O)(t,n,null==e?"":e)):H(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?L:"function"==typeof n?D:T)(t,n)):this.node()[t]},classed:function(t,n){var e=B(t+"");if(arguments.length<2){for(var r=X(this.node()),i=-1,o=e.length;++i1?r[0]+r.slice(2):r,+t.slice(e+1)]}function wt(t){return(t=mt(Math.abs(t)))?t[1]:NaN}var _t,bt=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function xt(t){if(!(n=bt.exec(t)))throw new Error("invalid format: "+t);var n;return new Mt({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Mt(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function At(t,n){var e=mt(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}xt.prototype=Mt.prototype,Mt.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};const Nt={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>At(100*t,n),r:At,s:function(t,n){var e=mt(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(_t=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,u=r.length;return o===u?r:o>u?r+new Array(o-u+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+mt(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function kt(t){return t}var Et,St,Ct,jt=Array.prototype.map,qt=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Ot(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?kt:(n=jt.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],u=0,a=n[0],l=0;i>0&&a>0&&(l+a+1>r&&(a=Math.max(1,r-l)),o.push(t.substring(i-=a,i+a)),!((l+=a+1)>r));)a=n[u=(u+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",u=void 0===t.decimal?".":t.decimal+"",a=void 0===t.numerals?kt:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(jt.call(t.numerals,String)),l=void 0===t.percent?"%":t.percent+"",s=void 0===t.minus?"−":t.minus+"",c=void 0===t.nan?"NaN":t.nan+"";function h(t){var n=(t=xt(t)).fill,e=t.align,h=t.sign,f=t.symbol,p=t.zero,d=t.width,g=t.comma,v=t.precision,y=t.trim,m=t.type;"n"===m?(g=!0,m="g"):Nt[m]||(void 0===v&&(v=12),y=!0,m="g"),(p||"0"===n&&"="===e)&&(p=!0,n="0",e="=");var w="$"===f?i:"#"===f&&/[boxX]/.test(m)?"0"+m.toLowerCase():"",_="$"===f?o:/[%p]/.test(m)?l:"",b=Nt[m],x=/[defgprs%]/.test(m);function M(t){var i,o,l,f=w,M=_;if("c"===m)M=b(t)+M,t="";else{var A=(t=+t)<0||1/t<0;if(t=isNaN(t)?c:b(Math.abs(t),v),y&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),A&&0==+t&&"+"!==h&&(A=!1),f=(A?"("===h?h:s:"-"===h||"("===h?"":h)+f,M=("s"===m?qt[8+_t/3]:"")+M+(A&&"("===h?")":""),x)for(i=-1,o=t.length;++i(l=t.charCodeAt(i))||l>57){M=(46===l?u+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!p&&(t=r(t,1/0));var N=f.length+t.length+M.length,k=N>1)+f+t+M+k.slice(N);break;default:t=k+f+t+M}return a(t)}return v=void 0===v?6:/[gprs]/.test(m)?Math.max(1,Math.min(21,v)):Math.max(0,Math.min(20,v)),M.toString=function(){return t+""},M}return{format:h,formatPrefix:function(t,n){var e=h(((t=xt(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(wt(n)/3))),i=Math.pow(10,-r),o=qt[8+r/3];return function(t){return e(i*t)+o}}}}function Pt(t,n){return null==t||null==n?NaN:tn?1:t>=n?0:NaN}function Ht(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Lt(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&function(t,n,e,r,i){for(var o,u=t.children,a=-1,l=u.length,s=t.value&&(r-n)/t.value;++a=0;)n+=e[r].value;else n=1;t.value=n}function Dt(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Xt)):void 0===n&&(n=Bt);for(var e,r,i,o,u,a=new It(t),l=[a];e=l.pop();)if((i=n(e.data))&&(u=(i=Array.from(i)).length))for(e.children=i,o=u-1;o>=0;--o)l.push(r=i[o]=new It(i[o])),r.parent=e,r.depth=e.depth+1;return a.eachBefore(Rt)}function Bt(t){return t.children}function Xt(t){return Array.isArray(t)?t[1]:null}function zt(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Rt(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function It(t){this.data=t,this.depth=this.height=0,this.parent=null}Et=Ot({thousands:",",grouping:[3],currency:["$",""]}),St=Et.format,Ct=Et.formatPrefix,It.prototype=Dt.prototype={constructor:It,count:function(){return this.eachAfter(Tt)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,u=[o],a=[],l=-1;o=u.pop();)if(a.push(o),e=o.children)for(r=0,i=e.length;r=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Dt(this).eachBefore(zt)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e=0?(o>=$t?10:o>=Vt?5:o>=Yt?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=$t?10:o>=Vt?5:o>=Yt?2:1)}function Ut(t){let n=t,e=t,r=t;function i(t,n,i=0,o=t.length){if(i>>1;r(t[e],n)<0?i=e+1:o=e}while(it(n)-e,e=Pt,r=(n,e)=>Pt(t(n),e)),{left:i,center:function(t,e,r=0,o=t.length){const u=i(t,e,r,o-1);return u>r&&n(t[u-1],e)>-n(t[u],e)?u-1:u},right:function(t,n,i=0,o=t.length){if(i>>1;r(t[e],n)<=0?i=e+1:o=e}while(i>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?mn(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?mn(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=an.exec(t))?new bn(n[1],n[2],n[3],1):(n=ln.exec(t))?new bn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=sn.exec(t))?mn(n[1],n[2],n[3],n[4]):(n=cn.exec(t))?mn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=hn.exec(t))?Nn(n[1],n[2]/100,n[3]/100,1):(n=fn.exec(t))?Nn(n[1],n[2]/100,n[3]/100,n[4]):pn.hasOwnProperty(t)?yn(pn[t]):"transparent"===t?new bn(NaN,NaN,NaN,0):null}function yn(t){return new bn(t>>16&255,t>>8&255,255&t,1)}function mn(t,n,e,r){return r<=0&&(t=n=e=NaN),new bn(t,n,e,r)}function wn(t){return t instanceof Qt||(t=vn(t)),t?new bn((t=t.rgb()).r,t.g,t.b,t.opacity):new bn}function _n(t,n,e,r){return 1===arguments.length?wn(t):new bn(t,n,e,null==r?1:r)}function bn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function xn(){return"#"+An(this.r)+An(this.g)+An(this.b)}function Mn(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function An(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Nn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new En(t,n,e,r)}function kn(t){if(t instanceof En)return new En(t.h,t.s,t.l,t.opacity);if(t instanceof Qt||(t=vn(t)),!t)return new En;if(t instanceof En)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,l=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(e0&&l<1?0:u,new En(u,a,l,t.opacity)}function En(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Sn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}function Cn(t,n,e,r,i){var o=t*t,u=o*t;return((1-3*t+3*o-u)*n+(4-6*o+3*u)*e+(1+3*t+3*o-3*u)*r+u*i)/6}Wt(Qt,vn,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:dn,formatHex:dn,formatHsl:function(){return kn(this).formatHsl()},formatRgb:gn,toString:gn}),Wt(bn,_n,Jt(Qt,{brighter:function(t){return t=null==t?nn:Math.pow(nn,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?tn:Math.pow(tn,t),new bn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:xn,formatHex:xn,formatRgb:Mn,toString:Mn})),Wt(En,(function(t,n,e,r){return 1===arguments.length?kn(t):new En(t,n,e,null==r?1:r)}),Jt(Qt,{brighter:function(t){return t=null==t?nn:Math.pow(nn,t),new En(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?tn:Math.pow(tn,t),new En(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new bn(Sn(t>=240?t-240:t+120,i,r),Sn(t,i,r),Sn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const jn=t=>()=>t;function qn(t,n){return function(e){return t+e*n}}function On(t){return 1==(t=+t)?Pn:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):jn(isNaN(n)?e:n)}}function Pn(t,n){var e=n-t;return e?qn(t,e):jn(isNaN(t)?n:t)}const Hn=function t(n){var e=On(n);function r(t,n){var r=e((t=_n(t)).r,(n=_n(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),u=Pn(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=u(n),t+""}}return r.gamma=t,r}(1);function Ln(t){return function(n){var e,r,i=n.length,o=new Array(i),u=new Array(i),a=new Array(i);for(e=0;e=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],u=r>0?t[r-1]:2*i-o,a=ro&&(i=n.slice(o,i),a[u]?a[u]+=i:a[++u]=i),(e=e[0])===(r=r[0])?a[u]?a[u]+=r:a[++u]=r:(a[++u]=null,l.push({i:u,x:Bn(e,r)})),o=Rn.lastIndex;return on&&(e=t,t=n,n=e),s=function(e){return Math.max(t,Math.min(n,e))}),r=l>2?Wn:Kn,i=o=null,h}function h(n){return null==n||isNaN(n=+n)?e:(i||(i=r(u.map(t),a,l)))(t(s(n)))}return h.invert=function(e){return s(n((o||(o=r(a,u.map(t),Bn)))(e)))},h.domain=function(t){return arguments.length?(u=Array.from(t,Fn),c()):u.slice()},h.range=function(t){return arguments.length?(a=Array.from(t),c()):a.slice()},h.rangeRound=function(t){return a=Array.from(t),l=Yn,c()},h.clamp=function(t){return arguments.length?(s=!!t||Zn,c()):s!==Zn},h.interpolate=function(t){return arguments.length?(l=t,c()):l},h.unknown=function(t){return arguments.length?(e=t,h):e},function(e,r){return t=e,n=r,c()}}function te(){return Qn()(Zn,Zn)}function ne(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function ee(t,n,e,r){var i,o=function(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=$t?i*=10:o>=Vt?i*=5:o>=Yt&&(i*=2),n0)return[t];if((r=n0){let e=Math.round(t/u),r=Math.round(n/u);for(e*un&&--r,o=new Array(i=r-e+1);++an&&--r,o=new Array(i=r-e+1);++a0;){if((i=Ft(l,s,e))===r)return o[u]=l,o[a]=s,n(o);if(i>0)l=Math.floor(l/i)*i,s=Math.ceil(s/i)*i;else{if(!(i<0))break;l=Math.ceil(l*i)/i,s=Math.floor(s*i)/i}r=i}return t},t}function ie(){var t=te();return t.copy=function(){return Jn(t,ie())},ne.apply(t,arguments),re(t)}function oe(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var ue={value:()=>{}};function ae(){for(var t,n=0,e=arguments.length,r={};n=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}}))}function ce(t,n){for(var e,r=0,i=t.length;r0)for(var e,r,i=new Array(e),o=0;o=0&&n._call.call(void 0,t),n=n._next;--ge}()}finally{ge=0,function(){var t,n,e=pe,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:pe=n);de=t,Ce(r)}(),we=0}}function Se(){var t=be.now(),n=t-me;n>1e3&&(_e-=n,me=t)}function Ce(t){ge||(ve&&(ve=clearTimeout(ve)),t-we>24?(t<1/0&&(ve=setTimeout(Ee,t-be.now()-_e)),ye&&(ye=clearInterval(ye))):(ye||(me=be.now(),ye=setInterval(Se,1e3)),ge=1,xe(Ee)))}function je(t,n,e){var r=new Ne;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Ne.prototype=ke.prototype={constructor:Ne,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Me():+e)+(null==n?0:+n),this._next||de===this||(de?de._next=this:pe=this,de=this),this._call=t,this._time=e,Ce()},stop:function(){this._call&&(this._call=null,this._time=1/0,Ce())}};var qe=fe("start","end","cancel","interrupt"),Oe=[];function Pe(t,n,e,r,i,o){var u=t.__transition;if(u){if(e in u)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=1,e.timer.restart(u,e.delay,e.time),e.delay<=t&&u(t-e.delay)}function u(o){var s,c,h,f;if(1!==e.state)return l();for(s in i)if((f=i[s]).name===e.name){if(3===f.state)return je(u);4===f.state?(f.state=6,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[s]):+s0)throw new Error("too late; already scheduled");return e}function Le(t,n){var e=Te(t,n);if(e.state>3)throw new Error("too late; already running");return e}function Te(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}var De,Be=180/Math.PI,Xe={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function ze(t,n,e,r,i,o){var u,a,l;return(u=Math.sqrt(t*t+n*n))&&(t/=u,n/=u),(l=t*e+n*r)&&(e-=t*l,r-=n*l),(a=Math.sqrt(e*e+r*r))&&(e/=a,r/=a,l/=a),t*r180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Bn(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,u.rotate,a,l),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Bn(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,u.skewX,a,l),function(t,n,e,r,o,u){if(t!==e||n!==r){var a=o.push(i(o)+"scale(",null,",",null,")");u.push({i:a-4,x:Bn(t,e)},{i:a-2,x:Bn(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,u.scaleX,u.scaleY,a,l),o=u=null,function(t){for(var n,e=-1,r=l.length;++e=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?He:Le;return function(){var u=o(this,t),a=u.on;a!==r&&(i=(r=a).copy()).on(n,e),u.on=i}}var cr=vt.prototype.constructor;function hr(t){return function(){this.style.removeProperty(t)}}function fr(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}function pr(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&fr(t,o,e)),r}return o._value=n,o}function dr(t){return function(n){this.textContent=t.call(this,n)}}function gr(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&dr(r)),n}return r._value=t,r}var vr=0;function yr(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function mr(){return++vr}var wr=vt.prototype;yr.prototype=function(t){return vt().transition(t)}.prototype={constructor:yr,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=r(t));for(var i=this._groups,o=i.length,u=new Array(o),a=0;a{p&&(p.textContent="search: "+n+" of "+e+" total samples ( "+St(".3f")(n/e*100,3)+"%)")},d()};const E=k;let S=(t,n,e=!1)=>{if(!n)return!1;let r=b(t);e&&(n=n.toLowerCase(),r=r.toLowerCase());const i=new RegExp(n);return void 0!==r&&r&&r.match(i)};const C=S;let j=function(t){p&&(t?p.textContent=t:"function"==typeof d?d():p.textContent="")};const q=j;let O=function(t){return b(t)+" ("+St(".3f")(100*(t.x1-t.x0),3)+"%, "+x(t)+" samples)"},P=function(t){return t.highlight?"#E600E6":function(t,n){let e=_||"warm";_||void 0===n||""===n||(e="red",void 0!==t&&t&&t.match(/::/)&&(e="yellow"),"kernel"===n?e="orange":"jit"===n?e="green":"inlined"===n&&(e="aqua"));const r=function(t){let n=0;if(t){const e=t.split("`");e.length>1&&(t=e[e.length-1]),n=function(t){let n=0,e=0,r=1;if(t){for(let i=0;i6);i++)n+=r*(t.charCodeAt(i)%10),e+=9*r,r*=.7;e>0&&(n/=e)}return n}(t=t.split("(")[0])}return n}(t);return function(t,n){let e,r,i;return"red"===t?(e=200+Math.round(55*n),r=50+Math.round(80*n),i=r):"orange"===t?(e=190+Math.round(65*n),r=90+Math.round(65*n),i=0):"yellow"===t?(e=175+Math.round(55*n),r=e,i=50+Math.round(20*n)):"green"===t?(e=50+Math.round(60*n),r=200+Math.round(55*n),i=e):"pastelgreen"===t?(e=163+Math.round(75*n),r=195+Math.round(49*n),i=72+Math.round(149*n)):"blue"===t?(e=91+Math.round(126*n),r=156+Math.round(76*n),i=221+Math.round(26*n)):"aqua"===t?(e=50+Math.round(60*n),r=165+Math.round(55*n),i=r):"cold"===t?(e=0+Math.round(55*(1-n)),r=0+Math.round(230*(1-n)),i=200+Math.round(55*n)):(e=200+Math.round(55*n),r=0+Math.round(230*(1-n)),i=0+Math.round(55*(1-n))),"rgb("+e+","+r+","+i+")"}(e,r)}(b(t),A(t))};const H=P;function L(t){t.data.fade=!1,t.data.hide=!1,t.children&&t.children.forEach(L)}function T(t){t.parent&&(t.parent.data.fade=!0,T(t.parent))}function D(t){if(i&&i.hide(),function(t){let n,e,r,i=t,o=i.parent;for(;o;){for(n=o.children,e=n.length;e--;)r=n[e],r!==i&&(r.data.hide=!0);i=o,o=i.parent}}(t),L(t),T(t),I(),y){const n=yt(this).select("svg")._groups[0][0].parentNode.offsetTop,r=(window.innerHeight-n)/e,i=(t.height-r+10)*e;window.scrollTo({top:n+i,left:0,behavior:"smooth"})}"function"==typeof c&&c(t)}function B(t,n){if(t.id===n)return t;{const e=M(t);if(e)for(let t=0;t0){const r=t/(n.x1-n.x0);e=e.filter((function(t){return(t.x1-t.x0)*r>f}))}return e}(r),y=yt(this).select("svg");y.attr("width",t);let w=y.selectAll("g").data(g,(function(t){return t.id}));if(!n||v){const t=Math.max.apply(null,g.map((function(t){return t.depth})));n=(t+3)*e,n{D(n)})),w.exit().remove(),w.on("mouseover",(function(t,n){i&&i.show(n,this),j(O(n)),"function"==typeof h&&h(n)})).on("mouseout",(function(){i&&i.hide(),j(null)}))}))}function $(t,n){n.forEach((function(n){const e=t.find((function(t){return t.name===n.name}));e?(e.value+=n.value,n.children&&(e.children||(e.children=[]),$(e.children,n.children))):t.push(n)}))}function V(t){let n,e,r,i,o,u,a,l;const s=[],c=[],h=[],f=!g;let p=t.data;for(p.hide?(t.value=0,e=t.children,e&&h.push(e)):(t.value=p.fade?0:x(p),s.push(t));n=s.pop();)if(e=n.children,e&&(o=e.length)){for(i=0;o--;)a=e[o],p=a.data,p.hide?(a.value=0,r=a.children,r&&h.push(r)):(p.fade?a.value=0:(l=x(p),a.value=l,i+=l),s.push(a));f&&n.value&&(n.value-=i),c.push(e)}for(o=c.length;o--;){for(e=c[o],i=0,u=e.length;u--;)i+=e[u].value;e[0].parent.value+=i}for(;h.length;)for(e=h.pop(),u=e.length;u--;)a=e[u],a.value=0,r=a.children,r&&h.push(r)}function Y(){r.datum((t=>{if("Node"!==t.constructor.name){const n=Dt(t,M);return function(t){let n=0;!function(t,n){n(t);let e=t.children;if(e){const t=[e];let r,i,o;for(;t.length;)for(e=t.pop(),r=e.length;r--;)i=e[r],n(i),o=i.children,o&&t.push(o)}}(t,(function(t){t.id=n++}))}(n),V(n),n.originalValue=n.value,w&&n.eachAfter((t=>{let n=N(t);const e=t.children;let r=e&&e.length;for(;--r>=0;)n+=e[r].delta;t.delta=n})),n}}))}function F(e){if(!arguments.length)return F;r=e,Y(),r.each((function(e){if(0===yt(this).select("svg").size()){const e=yt(this).append("svg:svg").attr("width",t).attr("class","partition d3-flame-graph");n&&(n($([n.data],[t]),n.data))),Y(),I(),F):F},F.update=function(t){return r?(t&&(r.datum(t),Y()),I(),F):F},F.destroy=function(){return r?(i&&(i.hide(),"function"==typeof i.destroy&&i.destroy()),r.selectAll("svg").remove(),F):F},F.setColorMapper=function(t){return arguments.length?(P=n=>{const e=H(n);return t(n,e)},F):(P=H,F)},F.color=F.setColorMapper,F.setColorHue=function(t){return arguments.length?(_=t,F):(_=null,F)},F.minFrameSize=function(t){return arguments.length?(f=t,F):f},F.setDetailsElement=function(t){return arguments.length?(p=t,F):p},F.details=F.setDetailsElement,F.selfValue=function(t){return arguments.length?(g=t,F):g},F.resetHeightOnZoom=function(t){return arguments.length?(v=t,F):v},F.scrollOnZoom=function(t){return arguments.length?(y=t,F):y},F.getName=function(t){return arguments.length?(b=t,F):b},F.getValue=function(t){return arguments.length?(x=t,F):x},F.getChildren=function(t){return arguments.length?(M=t,F):M},F.getLibtype=function(t){return arguments.length?(A=t,F):A},F.getDelta=function(t){return arguments.length?(N=t,F):N},F.setSearchHandler=function(t){return arguments.length?(k=t,F):(k=E,F)},F.setDetailsHandler=function(t){return arguments.length?(j=t,F):(j=q,F)},F.setSearchMatch=function(t){return arguments.length?(S=t,F):(S=C,F)},F}return vt.prototype.interrupt=function(t){return this.each((function(){!function(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>2&&e.state<5,e.state=6,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):u=!1;u&&delete t.__transition}}(this,t)}))},vt.prototype.transition=function(t){var n,e;t instanceof yr?(n=t._id,t=t._name):(n=mr(),(e=_r).time=Me(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o chart.width(width); +} +/* eslint-enable no-unused-vars */ diff --git a/core/src/main/scala/org/apache/spark/ui/exec/ExecutorThreadDumpPage.scala b/core/src/main/scala/org/apache/spark/ui/exec/ExecutorThreadDumpPage.scala index 0be9df921d1b..4a00777c509f 100644 --- a/core/src/main/scala/org/apache/spark/ui/exec/ExecutorThreadDumpPage.scala +++ b/core/src/main/scala/org/apache/spark/ui/exec/ExecutorThreadDumpPage.scala @@ -22,7 +22,10 @@ import javax.servlet.http.HttpServletRequest import scala.xml.{Node, Text} import org.apache.spark.SparkContext +import org.apache.spark.status.api.v1.ThreadStackTrace import org.apache.spark.ui.{SparkUITab, UIUtils, WebUIPage} +import org.apache.spark.ui.UIUtils.prependBaseUri +import org.apache.spark.ui.flamegraph.FlamegraphNode private[ui] class ExecutorThreadDumpPage( parent: SparkUITab, @@ -67,8 +70,10 @@ private[ui] class ExecutorThreadDumpPage(

Updated at {UIUtils.formatDate(time)}

+ {drawExecutorFlamegraph(request, threadDump)} { // scalastyle:off +

Expand All Collapse All @@ -106,4 +111,19 @@ private[ui] class ExecutorThreadDumpPage( }.getOrElse(Text("Error fetching thread dump")) UIUtils.headerSparkPage(request, s"Thread dump for executor $executorId", content, parent) } + + // scalastyle:off + private def drawExecutorFlamegraph(request: HttpServletRequest, thread: Array[ThreadStackTrace]): Seq[Node] = { +
+
{FlamegraphNode(thread).toJsonString}
+
+ + + + + +
+
+ } + // scalastyle:off } diff --git a/core/src/main/scala/org/apache/spark/ui/flamegraph/FlamegraphNode.scala b/core/src/main/scala/org/apache/spark/ui/flamegraph/FlamegraphNode.scala new file mode 100644 index 000000000000..a0a59f0572d9 --- /dev/null +++ b/core/src/main/scala/org/apache/spark/ui/flamegraph/FlamegraphNode.scala @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.spark.ui.flamegraph + +import scala.collection.mutable.HashMap + +import org.apache.commons.text.StringEscapeUtils + +import org.apache.spark.status.api.v1.ThreadStackTrace + +case class FlamegraphNode(name: String) { + private val children = new HashMap[String, FlamegraphNode]() + private var value: Int = 0 + def toJsonString: String = { + // scalastyle:off line.size.limit + s"""{"name":"$name","value":$value,"children":[${children.map(_._2.toJsonString).mkString(",")}]}""" + // scalastyle:on line.size.limit + } +} + +object FlamegraphNode { + def apply(stacks: Array[ThreadStackTrace]): FlamegraphNode = { + val root = FlamegraphNode("root") + stacks.foreach { stack => + root.value += 1 + var cur = root + stack.stackTrace.elems.reverse.foreach { e => + val head = e.split("\n").head + val name = StringEscapeUtils.escapeJson(head) + cur = cur.children.getOrElseUpdate(name, FlamegraphNode(name)) + cur.value += 1 + } + } + root + } +} diff --git a/dev/.rat-excludes b/dev/.rat-excludes index a27319f16aaa..4f0fcf085bea 100644 --- a/dev/.rat-excludes +++ b/dev/.rat-excludes @@ -26,6 +26,8 @@ bootstrap.bundle.min.js bootstrap.min.css jquery-3.5.1.min.js d3.min.js +d3-flamegraph.css +d3-flamegraph.min.js dagre-d3.min.js graphlib-dot.min.js sorttable.js