Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context stats enhancement #695

Merged
merged 10 commits into from
Mar 7, 2022
12 changes: 12 additions & 0 deletions dbux-code/resources/dark/nodejs.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions dbux-code/resources/light/nodejs.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion dbux-data/src/dataProviderUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export default {
},

/** @param {DataProvider} dp */
getContextModuleName(dp, contextId) {
getContextPackageName(dp, contextId) {
const context = dp.collections.executionContexts.getById(contextId);
const staticContext = dp.collections.staticContexts.getById(context.staticContextId);
return dp.util.getExternalProgramModuleName(staticContext.programId);
Expand Down
90 changes: 66 additions & 24 deletions dbux-data/src/impl/queries/StatsByContextQuery.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,75 @@ import SubscribableQuery from '../../queries/SubscribableQuery';


export class ContextStats {
/**
*
* @param {...ContextStats} stats
*/
static merge(...stats) {
const newStats = new ContextStats();

for (const s of stats) {
newStats.nTreeContexts += s.nTreeContexts;
newStats.nTreeTraces += s.nTreeTraces;

s._staticContextIds.forEach(newStats._staticContextIds.add, newStats._staticContextIds);
s._programIds.forEach(newStats._programIds.add, newStats._programIds);
s._packageNames.forEach(newStats._packageNames.add, newStats._packageNames);
}

return newStats;
}

/**
* Amount of contexts in context, plus it's entire sub-tree.
* @type {number}
*/
nTreeContexts = 0;

/**
* Amount of traces in context, plus it's entire sub-tree.
* @type {number}
*/
nTreeTraces = 0;

/**
* Amount of referenced staticContexts in context, plus it's entire sub-tree.
* @type {number}
*/
nTreeStaticContexts = 0;
get nTreeStaticContexts() {
return this._staticContextIds.size;
}

/**
* Amount of file called in context, plus it's entire sub-tree.?
* @type {number}
*/
nTreeFileCalled = 0;
get nTreeFileCalled() {
return this._programIds.size;
}

/**
* Amount of traces in context, plus it's entire sub-tree.
* Amount of packages in context, plus it's entire sub-tree.
* @type {number}
*/
nTreeTraces = 0;
get nTreePackages() {
return this._packageNames.size;
}

/**
* @type {Set<number>}
*/
_staticContextIds = new Set();

/**
* @type {Set<number>}
*/
_programIds = new Set();

/**
* @type {Set<number>}
*/
_packageNames = new Set();
}

export default class StatsByContextQuery extends SubscribableQuery {
Expand All @@ -50,18 +96,8 @@ export default class StatsByContextQuery extends SubscribableQuery {
* @param {number[]} contextIds
*/
getCombinedStats(contextIds) {
let stats = this._cache.get(contextIds[0]);
const keys = Object.keys(stats);
if (contextIds.length > 1) {
stats = { ...stats };
for (let i = 1; i < contextIds.length; ++i) {
const next = this._cache.get(contextIds[i]);
for (const key of keys) {
stats[key] += next[key];
}
}
}
return stats;
const allStats = contextIds.map((contextId) => this._cache.get(contextId));
return ContextStats.merge(...allStats);
}

/** ###########################################################################
Expand All @@ -80,34 +116,40 @@ export default class StatsByContextQuery extends SubscribableQuery {
const { contextId } = context;
const stats = this._cache.get(contextId) || new ContextStats();

const staticContexts = new Set();
const programIds = new Set();
const staticContextIds = stats._staticContextIds;
const programIds = stats._programIds;
const packageNames = stats._packageNames;

const staticContextId = dp.util.getContextStaticContextId(contextId);
staticContexts.add(staticContextId);
stats.nTreeContexts = 1;
const childTraces = dp.indexes.traces.byContext.get(contextId);
stats.nTreeTraces = childTraces?.length || 0;

const staticContextId = dp.util.getContextStaticContextId(contextId);
staticContextIds.add(staticContextId);
const staticContextProgramId = dp.util.getContextStaticContext(contextId)?.programId;
programIds.add(staticContextProgramId);
const packageName = dp.util.getContextPackageName(contextId);
packageNames.add(packageName);

for (const child of children) {
const childSets = dfs(child);

// add childSet to staticContextSet
childSets.staticContextSet.forEach(staticContexts.add, staticContexts);
childSets.staticContextIdSet.forEach(staticContextIds.add, staticContextIds);
childSets.programIdSet.forEach(programIds.add, programIds);
childSets.packageNameSet.forEach(packageNames.add, packageNames);

stats.nTreeContexts += this.getContextNTreeContexts(child.contextId);
stats.nTreeTraces += this.getContextNTreeTraces(child.contextId);
}
stats.nTreeStaticContexts = staticContexts.size;
stats.nTreeFileCalled = programIds.size;
// data are directly added into the set
// stats._staticContextIds = staticContextIds;
// stats._programIds = programIds;
// stats._packageNames = packageNames;

this.storeByKey(contextId, stats);

const sets = { staticContextSet: staticContexts, programIdSet: programIds };
const sets = { staticContextIdSet: staticContextIds, programIdSet: programIds, packageNameSet: packageNames };
return sets;
}
);
Expand Down
15 changes: 14 additions & 1 deletion dbux-graph-client/src/graph/Toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Toolbar extends ClientComponentEndpoint {
style="left: inherit; right: 0; min-width: 0;"
aria-labelledby="dropdownMenuButton">
<!--button data-el="showIdsBtn" class="toolbar-btn btn btn-info full-width" href="#">ids</button-->
<button title="Toggle context stats" data-el="statsBtn" class="toolbar-btn btn btn-info full-width" href="#">stats</button>
<div class="dropdown-divider"></div>
<button title="Restart the Webview (can eliviate some bugs)" data-el="restartBtn" class="toolbar-btn btn btn-danger full-width" href="#">Restart</button>
</div>
Expand Down Expand Up @@ -126,6 +127,7 @@ class Toolbar extends ClientComponentEndpoint {
graphMode,
stackMode,
asyncDetailMode,
statsEnabled,
} = this.parent.state;

const {
Expand Down Expand Up @@ -179,6 +181,9 @@ class Toolbar extends ClientComponentEndpoint {
decorateClasses(this.els.clearThreadSelectionBtn, {
hidden: !isThreadSelectionActive
});
decorateClasses(this.els.statsBtn, {
active: statsEnabled
});
[`navbar-${themeModeName}`, `bg-${themeModeName}`].forEach(mode => this.el.classList.add(mode));
this.els.thinModeBtn.innerHTML = `${!!thinMode && '||&nbsp;' || '|&nbsp;|'}`;
this.els.hideNewRunBtn.innerHTML = `${hideAfter ? '⚪' : '🔴'}`;
Expand All @@ -194,14 +199,16 @@ class Toolbar extends ClientComponentEndpoint {
valueMode,
thinMode,
asyncDetailMode,
statsEnabled,
} = this.parent.state;

const docEl = this.parent.el;
decorateClasses(docEl, {
'hide-locs': !locMode,
'hide-values': !valueMode,
'show-values': valueMode,
'thin-mode': thinMode
'thin-mode': thinMode,
'stats-disabled': !statsEnabled,
});

decorateAttr(docEl, {
Expand Down Expand Up @@ -326,6 +333,12 @@ class Toolbar extends ClientComponentEndpoint {
},
focus(evt) { evt.target.blur(); }
},
statsBtn: {
async click(evt) {
evt.preventDefault();
await this.remote.toggleStats();
}
},

searchContextsBtn: {
async click(evt) {
Expand Down
63 changes: 34 additions & 29 deletions dbux-graph-client/src/graph/asyncGraph/AsyncGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,19 @@ class AsyncGraph extends GraphBase {

isProgramRoot,
realStaticContextid,
moduleName,
packageName,
postAsyncEventUpdateType,
hasError,
nestingDepth,
stats: {
nTreeContexts,
nTreeStaticContexts,
nTreeFileCalled,
nTreeTraces,
},
stats,
} = nodeData;

const { themeMode, screenshotMode, statsEnabled } = this.context;
// const { asyncDetailMode } = graphDocument.state;
const { themeMode, screenshotMode } = this.context;
// const highContractMode = screenshotMode && !asyncDetailMode;
const highContractMode = screenshotMode;
// const moduleLabel = moduleName ? `${moduleName} | ` : '';
// const moduleLabel = packageName ? `${packageName} | ` : '';

const backgroundColor = makeStaticContextColor(themeMode, realStaticContextid, { bland: !!moduleName, highContractMode });
const backgroundColor = makeStaticContextColor(themeMode, realStaticContextid, { bland: !!packageName, highContractMode });

let leftLabel = '', errorLabel = '', statsRawEl = '';
let shortLabel, fullLabel = displayName;
Expand Down Expand Up @@ -189,25 +183,36 @@ class AsyncGraph extends GraphBase {
// shortLabel = `${depthLabel}${shortLabel}`;
// fullLabel = `${depthLabel}${fullLabel}`;
}
if (statsEnabled) {
const { statsIconUris } = this.context;
statsRawEl = /*html*/`
<div class="grid" style="width: max-content;">
<div style="grid-row: 1; grid-column:1;" class="context-stats" title="Amount of child contexts in subgraph">
<img src="${statsIconUris.nTreeContexts}" /><span>${nTreeContexts}</span>
</div>
<div style="grid-row: 1; grid-column:2;" class="context-stats" title="Amount of static contexts involved in subgraph">
<img src="${statsIconUris.nTreeStaticContexts}" /><span>${nTreeStaticContexts}</span>
</div>
<div style="grid-row: 2; grid-column:1;" class="context-stats" title="Amount of files involved in subgraph">
<img src="${statsIconUris.nTreeFileCalled}" /><span>${nTreeFileCalled}</span>
</div>
<div style="grid-row: 2; grid-column:2;" class="context-stats" title="Amount of traces in subgraph. This is a rough measure.">
<img src="${statsIconUris.nTreeTraces}" /><span>${nTreeTraces}</span>
</div>

// generate stats label
const { statsIconUris } = this.context;
const {
nTreeContexts,
nTreeStaticContexts,
nTreeFileCalled,
nTreeTraces,
nTreePackages,
} = stats;
statsRawEl = /*html*/`
<div class="grid" style="width: max-content;">
<div style="grid-row: 1; grid-column:1;" class="context-stats" title="Amount of child contexts in subgraph">
<img src="${statsIconUris.nTreeContexts}" /><span>${nTreeContexts}</span>
</div>
`;
}
<div style="grid-row: 1; grid-column:2;" class="context-stats" title="Amount of static contexts involved in subgraph">
<img src="${statsIconUris.nTreeStaticContexts}" /><span>${nTreeStaticContexts}</span>
</div>
<div style="grid-row: 2; grid-column:1;" class="context-stats" title="Amount of files involved in subgraph">
<img src="${statsIconUris.nTreeFileCalled}" /><span>${nTreeFileCalled}</span>
</div>
<div style="grid-row: 2; grid-column:2;" class="context-stats" title="Amount of traces in subgraph. This is a rough measure.">
<img src="${statsIconUris.nTreeTraces}" /><span>${nTreeTraces}</span>
</div>
<div style="grid-row: 3; grid-column:1;" class="context-stats" title="Amount of packages in subgraph">
<img src="${statsIconUris.nTreePackages}" /><span>${nTreePackages}</span>
</div>
</div>
`;

const { asyncNodeId, applicationId, isTerminalNode } = asyncNode;
const asyncNodeData = {
'async-node-id': asyncNodeId,
Expand Down
5 changes: 5 additions & 0 deletions dbux-graph-client/src/graph/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ div {
margin-left: 3px;
}

.stats-disabled .context-stats {
display: none !important;
}

.show-values .async-context-label {
display: none !important;
}
Expand Down Expand Up @@ -667,6 +671,7 @@ body:not(.theme-mode-dark) .highlight {
.context-stats img {
width: 13px;
height: 13px;
filter: grayscale(1);
}

/** ###########################################################################
Expand Down
Loading