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

When menu is open, CPU thread congestion from Vue causes choppy video and frame drop every second #159

Open
ehfd opened this issue Jun 7, 2024 · 3 comments
Labels
bug Something isn't working performance Performance or latency issues, not critical but impacts usage web Web components including gst-web

Comments

@ehfd
Copy link
Member

ehfd commented Jun 7, 2024

NOTE: This has been partially fixed so that this will not affect the stream as long as the side menu is closed.

image

image

image

The above spike in CPU usage every second represents a stutter/frame drop that exists exclusively with lower power mode (Windows, for example) in clients, which gets better when the highest power mode (and thus a higher ceiling in CPU clock).

It becomes worse if the stream is actively moving.

image

Interestingly, the heap either notably increases or sharply decreases during that spike.

The source of this issue is from Vue, where the microtasks every second originate with nextTick, flushCallbacks, flushSchedulerQueue, Watcher.run, Watcher.get, updateComponent, Vue._update, Vue._render, patch, render, normalizeScopedSlots, patchVnode, etc... from vue.js, causes massive lag in the WebRTC video element.

However, this could be a result of our own code components, which would be less concerning than requiring an overhaul in the web interface or a major update in the libraries.

Also note that ff0ba43 is another source that contributes to elevated CPU clocks which must be optimized, but this is separate where the elevated CPU usage is distributed across the whole timeframe and not a brief and sharply blocking CPU spike every second.

Designating as a blocker for project release and a high-priority issue.

@ehfd ehfd added bug Something isn't working web Web components including gst-web high-priority Must be addressed as soon as possible, remove when resolved labels Jun 7, 2024
@ehfd
Copy link
Member Author

ehfd commented Jun 7, 2024

I think this is triggered as part of the UI updating the stats (especially because RTCPeerConnection.getStats is in the mix) and everything else that gets periodically updated in the menus.

The CPU spike is completely eliminated when the stats update is disabled.

@ehfd
Copy link
Member Author

ehfd commented Jun 8, 2024

The core issue seems to be that each of these variables are linked to a Vue element and it's generating massive numbers of render ticks.

// Connection latency in milliseconds
app.connectionLatency = 0.0;
app.connectionVideoLatency = (stats.general.currentRoundTripTime !== null) ? (stats.general.currentRoundTripTime * 1000.0) : (app.serverLatency * 2.0);
app.connectionAudioLatency = (audioStats.general.currentRoundTripTime !== null) ? (audioStats.general.currentRoundTripTime * 1000.0) : (app.serverLatency * 2.0);
app.connectionLatency += Math.max(app.connectionVideoLatency, app.connectionAudioLatency);
// Sum of video+audio packets
app.connectionPacketsReceived = 0;
app.connectionPacketsLost = 0;
// Connection stats
app.connectionStatType = stats.general.connectionType == audioStats.general.connectionType ? stats.general.connectionType : (stats.general.connectionType + " / " + audioStats.general.connectionType);
app.connectionBytesReceived = ((stats.general.bytesReceived + audioStats.general.bytesReceived) * 1e-6).toFixed(2) + " MBytes";
app.connectionBytesSent = ((stats.general.bytesSent + audioStats.general.bytesSent) * 1e-6).toFixed(2) + " MBytes";
app.connectionAvailableBandwidth = ((parseInt(stats.general.availableReceiveBandwidth) + parseInt(audioStats.general.availableReceiveBandwidth)) / 1e+6).toFixed(2) + " mbps";
// Video stats
app.connectionPacketsReceived += stats.video.packetsReceived;
app.connectionPacketsLost += stats.video.packetsLost;
app.connectionCodec = stats.video.codecName;
app.connectionVideoDecoder = stats.video.decoder;
app.connectionResolution = stats.video.frameWidth + "x" + stats.video.frameHeight;
app.connectionFrameRate = stats.video.framesPerSecond;
app.connectionVideoBitrate = (((stats.video.bytesReceived - videoBytesReceivedStart) / (now - statsStart)) * 8 / 1e+6).toFixed(2);
videoBytesReceivedStart = stats.video.bytesReceived;
// Audio stats
app.connectionPacketsReceived += audioStats.audio.packetsReceived;
app.connectionPacketsLost += audioStats.audio.packetsLost;
app.connectionAudioCodecName = audioStats.audio.codecName;
app.connectionAudioBitrate = (((audioStats.audio.bytesReceived - audioBytesReceivedStart) / (now - statsStart)) * 8 / 1e+3).toFixed(2);
audioBytesReceivedStart = audioStats.audio.bytesReceived;
// Latency stats
app.connectionVideoLatency = parseInt(Math.round(app.connectionVideoLatency + (1000.0 * (stats.video.jitterBufferDelay - previousVideoJitterBufferDelay) / (stats.video.jitterBufferEmittedCount - previousVideoJitterBufferEmittedCount) || 0)));
previousVideoJitterBufferDelay = stats.video.jitterBufferDelay;
previousVideoJitterBufferEmittedCount = stats.video.jitterBufferEmittedCount;
app.connectionAudioLatency = parseInt(Math.round(app.connectionAudioLatency + (1000.0 * (audioStats.audio.jitterBufferDelay - previousAudioJitterBufferDelay) / (audioStats.audio.jitterBufferEmittedCount - previousAudioJitterBufferEmittedCount) || 0)));
previousAudioJitterBufferDelay = audioStats.audio.jitterBufferDelay;
previousAudioJitterBufferEmittedCount = audioStats.audio.jitterBufferEmittedCount;
// Format latency
app.connectionLatency = parseInt(Math.round(app.connectionLatency));
statsStart = now;

@ehfd ehfd removed the high-priority Must be addressed as soon as possible, remove when resolved label Jun 8, 2024
@ehfd
Copy link
Member Author

ehfd commented Jun 8, 2024

Honestly, I have never imagined DOM updates could be so taxing.

5a17b10

Disabled DOM updates when the menu is not open (It's not possible to interactively control anything anyways with the menu open).
Therefore, it is no longer a high-priority issue but another reason #108 should be done, in consideration with this issue.

However, it feels like reactive libraries should not be used in the same place and perhaps jQuery might be the answer.

@ehfd ehfd changed the title CPU thread congestion from Vue causes choppy video and frame drop every second CPU thread congestion from Vue when menu is open causes choppy video and frame drop every second Jun 8, 2024
@ehfd ehfd added the performance Performance or latency issues, not critical but impacts usage label Jun 8, 2024
@ehfd ehfd changed the title CPU thread congestion from Vue when menu is open causes choppy video and frame drop every second When menu is open, CPU thread congestion from Vue causes choppy video and frame drop every second Jun 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working performance Performance or latency issues, not critical but impacts usage web Web components including gst-web
Projects
None yet
Development

No branches or pull requests

1 participant