Skip to content

Commit

Permalink
Initialize view range and render time charts during trace indexing
Browse files Browse the repository at this point in the history
Initialize the unit controller view range with either the trace full
range, or the persisted state view range if it is set. When the
experiment hasn't been indexed yet, the initial view range may be empty.

When a new output is opened while the trace is indexing, and the view
range has never been set yet, initialize the view range to the current
partial trace full range. This view range will remain during and after
indexing unless the user changes the view range manually or presses the
Reset button.

When indexing completes, if the view range has never been set yet,
initialize the view range to the final trace full range.

In TimegraphOutputComponent, render the timegraph content and use the
analysis-running-overflow overlay while the analysis is running.

Let the analysis-running-overflow pass through pointer events to the
underlying layer.

In TimegraphOutputComponent componentDidUpdate(), update the chart
layers only if the outputStatus has changed, not always when the
outputStatus is RUNNING. This prevents recursive change of state causing
stack overflow exceptions. Update the chart layers also if the
timegraphTree state has changed. Perform a 'soft' update that does not
refresh rows that already have the correct data. Perform a 'hard' update
only where the marker categories or marker set have changed. Prevent a
possible double update of the markers chart layer.

Extract search bar code to private method and fix typo in its className.

Use a different id for the markers chart layer to help debugging.

Fix AbstractXYOutputComponent checkedSeries array comparison.

Signed-off-by: Patrick Tasse <patrick.tasse@gmail.com>
  • Loading branch information
PatrickTasse committed Sep 23, 2024
1 parent aa3b745 commit 98da981
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { ChartOptions } from 'chart.js';
import { Line, Scatter } from 'react-chartjs-2';
import { getAllExpandedNodeIds } from './utils/filter-tree/utils';
import { debounce } from 'lodash';
import { isEqual } from 'lodash';

export const ZOOM_IN_RATE = 0.8;
export const ZOOM_OUT_RATE = 1.25;
Expand Down Expand Up @@ -226,7 +227,7 @@ export abstract class AbstractXYOutputComponent<

componentDidUpdate(prevProps: AbstractOutputProps, prevState: AbstractXYOutputState): void {
const viewRangeChanged = this.props.viewRange !== prevProps.viewRange;
const checkedSeriesChanged = this.state.checkedSeries !== prevState.checkedSeries;
const checkedSeriesChanged = !isEqual(this.state.checkedSeries, prevState.checkedSeries);
const collapsedNodesChanged = this.state.collapsedNodes !== prevState.collapsedNodes;
const chartWidthChanged =
this.props.style.width !== prevProps.style.width ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
}
});

this.markersChartLayer = new TimeGraphChart('timeGraphChart', markersProvider, this.markerRowController);
this.markersChartLayer = new TimeGraphChart('markersChart', markersProvider, this.markerRowController);
this.markerChartCursors = new TimeGraphMarkersChartCursors(
'chart-cursors-new',
this.markersChartLayer,
Expand Down Expand Up @@ -328,27 +328,30 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr

async componentDidUpdate(prevProps: TimegraphOutputProps, prevState: TimegraphOutputState): Promise<void> {
if (
prevState.outputStatus === ResponseStatus.RUNNING ||
!isEqual(this.state.collapsedNodes, prevState.collapsedNodes) ||
!isEqual(prevProps.markerCategories, this.props.markerCategories) ||
prevProps.markerSetId !== this.props.markerSetId
) {
this.selectedMarkerCategories = this.props.markerCategories;
if (this.state.searchString?.length > 0 || this.state.filters.length > 0) {
this._debouncedUpdateSearch();
} else {
this.chartLayer.updateChart();
}
this.chartLayer.updateChart();
this.markersChartLayer.updateChart();
this.arrowLayer.update();
this.rangeEventsLayer.update();
}
if (
!isEqual(this.state.markerCategoryEntries, prevState.markerCategoryEntries) ||
!isEqual(this.state.collapsedMarkerNodes, prevState.collapsedMarkerNodes) ||
!isEqual(this.state.markerLayerData, prevState.markerLayerData)
) {
this.markersChartLayer.updateChart();
this.arrowLayer.update();
} else {
if (
this.state.outputStatus !== prevState.outputStatus ||
!isEqual(this.state.timegraphTree, prevState.timegraphTree) ||
!isEqual(this.state.collapsedNodes, prevState.collapsedNodes)
) {
this.chartLayer.update();
this.arrowLayer.update();
}
if (
!isEqual(this.state.markerCategoryEntries, prevState.markerCategoryEntries) ||
!isEqual(this.state.collapsedMarkerNodes, prevState.collapsedMarkerNodes) ||
!isEqual(this.state.markerLayerData, prevState.markerLayerData)
) {
this.markersChartLayer.updateChart();
}
}
if (
!isEqual(this.state.searchString, prevState.searchString) ||
Expand Down Expand Up @@ -685,22 +688,23 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
renderChart(): React.ReactNode {
return (
<React.Fragment>
{this.state.outputStatus === ResponseStatus.COMPLETED ? (
<div
id="timegraph-main"
className="ps__child--consume"
onWheel={ev => {
ev.preventDefault();
ev.stopPropagation();
}}
style={{ height: this.props.style.height }}
>
{this.renderTimeGraphContent()}
</div>
) : (
<div className="analysis-running">
{<FontAwesomeIcon icon={faSpinner} spin style={{ marginRight: '5px' }} />}
{'Analysis running'}
<div
id="timegraph-main"
className="ps__child--consume"
onWheel={ev => {
ev.preventDefault();
ev.stopPropagation();
}}
style={{ height: this.props.style.height }}
>
{this.renderTimeGraphContent()}
</div>
{this.state.outputStatus === ResponseStatus.RUNNING && (
<div className="analysis-running-overflow" style={{ width: this.getChartWidth() }}>
<div>
<FontAwesomeIcon icon={faSpinner} spin style={{ marginRight: '5px' }} />
<span>Analysis running</span>
</div>
</div>
)}
</React.Fragment>
Expand Down Expand Up @@ -783,50 +787,56 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
<div id="main-timegraph-content" ref={this.horizontalContainer} style={{ height: this.props.style.height }}>
{this.getChartContainer()}
{this.getMarkersContainer()}
<div
id={this.props.traceId + this.props.outputDescriptor.id + 'searchBar'}
className="timgraph-search-bar"
>
<TextField
InputProps={{
placeholder: 'Search',
startAdornment: (
<InputAdornment
sx={{
color: 'var(--trace-viewer-ui-font-color0)'
}}
position="start"
>
<i className="codicon codicon-search"></i>
</InputAdornment>
),
className: 'timegraph-search-box',
endAdornment: (
<InputAdornment
sx={{
color: 'var(--trace-viewer-ui-font-color0)'
}}
position="end"
>
<button className="remove-search-button" onClick={this.clearSearchBox}>
<i className="codicon codicon-close"></i>
</button>
</InputAdornment>
)
}}
value={this.state.searchString}
onChange={this.handleSearchChange}
onKeyDown={this.handleKeyDown}
{this.getSearchBar()}
</div>
);
}

private getSearchBar() {
return (
<div
id={this.props.traceId + this.props.outputDescriptor.id + 'searchBar'}
className="timegraph-search-bar"
>
<TextField
InputProps={{
placeholder: 'Search',
startAdornment: (
<InputAdornment
sx={{
color: 'var(--trace-viewer-ui-font-color0)'
}}
position="start"
>
<i className="codicon codicon-search"></i>
</InputAdornment>
),
className: 'timegraph-search-box',
endAdornment: (
<InputAdornment
sx={{
color: 'var(--trace-viewer-ui-font-color0)'
}}
position="end"
>
<button className="remove-search-button" onClick={this.clearSearchBox}>
<i className="codicon codicon-close"></i>
</button>
</InputAdornment>
)
}}
value={this.state.searchString}
onChange={this.handleSearchChange}
onKeyDown={this.handleKeyDown}
/>
{this.state.filters.map((filter, index) => (
<Chip
key={index}
label={filter}
onDelete={() => this.removeFilter(filter)}
className="filter-chip"
/>
{this.state.filters.map((filter, index) => (
<Chip
key={index}
label={filter}
onDelete={() => this.removeFilter(filter)}
className="filter-chip"
/>
))}
</div>
))}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
backgroundTheme: this.props.backgroundTheme
};
const absoluteRange = traceRange.getDuration();
this.unitController = new TimeGraphUnitController(absoluteRange, { start: BigInt(0), end: absoluteRange });
const offset = viewRange.getOffset();
const viewRangeStart = viewRange.getStart() - (offset ? offset : BigInt(0));
const viewRangeEnd = viewRange.getEnd() - (offset ? offset : BigInt(0));
this.unitController = new TimeGraphUnitController(absoluteRange, { start: viewRangeStart, end: viewRangeEnd });
this.unitController.numberTranslator = (theNumber: bigint) => {
const originalStart = this.state.currentRange.getStart();
theNumber += originalStart;
Expand Down Expand Up @@ -238,10 +241,8 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
await this.updateTrace();
this.unitController.absoluteRange = this.state.experiment.end - this.state.timeOffset;
this.unitController.offset = this.state.timeOffset;
if (this.props.persistedState) {
const { start, end } = this.props.persistedState.unitControllerViewRange;
this.unitController.viewRange = { start: BigInt(start), end: BigInt(end) };
} else {
if (this.unitController.viewRangeLength === BigInt(0)) {
// set the initial view range if not set yet
this.unitController.viewRange = {
start: BigInt(0),
end: this.state.experiment.end - this.state.timeOffset
Expand Down Expand Up @@ -271,6 +272,10 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
)
});

this.unitController.absoluteRange = this.state.experiment.end - this.state.timeOffset;
this.unitController.offset = this.state.timeOffset;
signalManager().fireExperimentUpdatedSignal(updatedExperiment);

// Update status bar
this.props.messageManager.addStatusMessage(this.INDEXING_STATUS_BAR_KEY, {
text: `Indexing ${this.props.experiment.name}: ${this.state.experiment.nbEvents}`,
Expand Down Expand Up @@ -332,6 +337,13 @@ export class TraceContextComponent extends React.Component<TraceContextProps, Tr
if (prevProps.outputs.length < this.props.outputs.length) {
// added a new output - scroll to bottom
this.scrollToBottom();
if (this.unitController.viewRangeLength === BigInt(0)) {
// set the initial view range if not set yet
this.unitController.viewRange = {
start: BigInt(0),
end: this.state.experiment.end - this.state.timeOffset
};
}
} else if (
prevProps.outputs.length === this.props.outputs.length &&
prevState.pinnedView === undefined &&
Expand Down
3 changes: 2 additions & 1 deletion packages/react-components/style/output-components-style.css
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ canvas {
font-size: 24px;
display: flex;
position: absolute;
pointer-events: none;
top: 0;
height: 100%;
}
Expand Down Expand Up @@ -439,7 +440,7 @@ canvas {
color: var(--trace-viewer-foreground);
}

.timgraph-search-bar {
.timegraph-search-bar {
background: var(--trace-viewer-editor-background);
padding-top: 5px;
padding-bottom: 15px;
Expand Down

0 comments on commit 98da981

Please sign in to comment.