Skip to content

Conversation

@aiAdrian
Copy link
Contributor

@aiAdrian aiAdrian commented Oct 8, 2025

Description

Graphical Timetable Performance Optimization

The calculation time for the extractSectionTracks method has been significantly reduced:

  • Google Chrome: Improved by a factor of 3 (from ~75ms to ~25ms)
  • Microsoft Edge: Improved by a factor of 5 (from ~620ms to ~115ms)

These optimizations enhance responsiveness and reduce latency across browsers, especially for Edge users.

Performance Improvement: extractSectionTracks Method

Goal: Improve rendering performance of the graphical timetable by introducing caching and more efficient data structures.

Extended Functionality

Caching introduced: Added getTrainrunSectionFromCacheDuringRendering() method using a Map<number, TrainrunSection> to avoid redundant service calls.

Cache integration: The cache is now used across multiple methods:

  • render()
  • extractStreckenGleis()
  • extractSectionTracks()
  • calculateMinimumHeadwayTimeAtNode()
  • computeTrackAlignments()
  • setMaxTrackMap()

 Performance Improvements

  • Optimized data structure: Replaced number[][] with Uint8Array for dataMatrix to reduce memory usage and improve access speed.

  • Frequency unrolling refactored: New method extractSectionTracksUnrollFreq() handles train frequency loops more efficiently.

  • Occupation band optimization: extractSectionTracksFillOccupationBand() fills occupancy data with bounds checking and performance tuning.

 Logic Enhancements

  • headwayTime calculation now uses the cache.

  • Precomputations like travelTimeIdxPart and baseTimeCellIdx improve loop performance

Issues

#553

Checklist

  • This PR contains a description of the changes I'm making
  • I've read the Contribution Guidelines
  • I've added tests for changes or features I've introduced
  • I documented any high-level concepts I'm introducing in documentation/
  • CI is currently green and this is ready for review

@aiAdrian aiAdrian linked an issue Oct 8, 2025 that may be closed by this pull request
3 tasks
@aiAdrian aiAdrian self-assigned this Oct 8, 2025
@aiAdrian aiAdrian added the enhancement New feature or request label Oct 8, 2025
…. To improve rendering performance, we’ve introduced a lookup cache that handles frequent access more efficiently.
@aiAdrian aiAdrian added this to the 2.10 milestone Oct 10, 2025
Copy link
Contributor

@shenriotpro shenriotpro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't say I understand the logic, but I love the result :)

@aiAdrian aiAdrian requested a review from shenriotpro October 10, 2025 14:42
@aiAdrian
Copy link
Contributor Author

#556

@aiAdrian aiAdrian requested a review from louisgreiner October 13, 2025 15:31
@shenriotpro shenriotpro removed their request for review October 20, 2025 07:35
@aiAdrian aiAdrian requested a review from Copilot November 11, 2025 17:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR optimizes the performance of the graphical timetable rendering by introducing caching and more efficient data structures, achieving ~3x improvement in Chrome and ~5x improvement in Edge for the extractSectionTracks method.

Key changes:

  • Introduced a Map<number, TrainrunSection> cache to eliminate redundant service calls during rendering
  • Replaced number[][] with Uint8Array for the data matrix to reduce memory usage and improve access speed
  • Refactored the track extraction logic into smaller, more focused methods with precomputed values

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return;
}

// prepare fast look (cache for big netzgrafik)
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected incomplete comment 'prepare fast look' to 'prepare fast lookup'.

Suggested change
// prepare fast look (cache for big netzgrafik)
// prepare fast lookup (cache for big netzgrafik)

Copilot uses AI. Check for mistakes.
Comment on lines +260 to +261
// We restrict the number of section tracks to 255 tracks (between two nodes we could only
// have 255 tracks - this improves the performance
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment explains why 255 tracks is the limit but doesn't explain the underlying constraint. Consider clarifying why the limit exists (e.g., Uint8Array max value) and whether this is a technical or business constraint.

Suggested change
// We restrict the number of section tracks to 255 tracks (between two nodes we could only
// have 255 tracks - this improves the performance
// We restrict the number of section tracks to 255 tracks (between two nodes) because we use Uint8Array
// to store track occupancy, and Uint8Array can only store values from 0 to 255. This is a technical constraint,
// not a business constraint, and allows for efficient memory usage and performance.

Copilot uses AI. Check for mistakes.
departureMod: number,
timeRes: number,
headwayTime: number,
dataMatrix: any[],
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter type any[] is too generic. Based on the implementation, this should be typed as Uint8Array[] for better type safety and code clarity.

Suggested change
dataMatrix: any[],
dataMatrix: Uint8Array[],

Copilot uses AI. Check for mistakes.
const startIdx =
baseTimeCellIdx < 0 ? 0 : baseTimeCellIdx > nTimeCells ? nTimeCells : baseTimeCellIdx;

// const endIdx = Math.max(0, Math.min(baseTimeCellIdx + bandLength, nTimeCells)); (perf. opt.)
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the startIdx comment above, this commented-out code should either be removed or the comment should explain why the ternary operator approach is a performance optimization over Math.max/Math.min.

Suggested change
// const endIdx = Math.max(0, Math.min(baseTimeCellIdx + bandLength, nTimeCells)); (perf. opt.)
// Instead of using: const endIdx = Math.max(0, Math.min(baseTimeCellIdx + bandLength, nTimeCells));
// we use the ternary operator below for performance reasons, as this code is in a hot loop and
// avoiding function calls (Math.max/Math.min) can be measurably faster in JavaScript/TypeScript.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@louisgreiner louisgreiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some testing, the performances seem way better indeed, however, on the demo reticular, I notice different result between the current version and this one.

image
Old version New version
image image

:/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request]: Graphical Timetable (Streckengrafik) performance optimisation

4 participants