cruise-automation / webviz

web-based visualization libraries
https://webviz.io/
Apache License 2.0
2.04k stars 413 forks source link

Custom panel is slow on first render #471

Open meyerjo opened 4 years ago

meyerjo commented 4 years ago

Hi,I created a custom panel in order to visualize some data from ROS in a more convenient way. However, I am struggling with the problem that at first render the framerate drops significantly when I am including the panel. Once the ros bag is replayed everything seems to be fine and the bag is replayed without any lag. I tried to get some inspiration from how RawMessages/index.js is implemented. Unfortunately I could not improve the performance really on first render. Here you find my simplified code without any optimizations. It would be great, if you could point me towards the problems causing the slow render. Unfortunately I could not find too much documentation regarding the development of new panel types. Thanks for the project :-)


import React from "react";
import { hot } from "react-hot-loader/root";
import styled from "styled-components";

import Flex from "webviz-core/src/components/Flex";
import Panel from "webviz-core/src/components/Panel";
import { useMessagesByTopic } from "webviz-core/src/PanelAPI";

const SSpan = styled.span`
  opacity: 0.8;
`;

const SRow = styled.div`
  display: flex;
  line-height: 24px;
  flex-shrink: 0;
`;

type GeoPositionsItemProps = {|
  longitude: number,
  latitude: number,
  altitude: number,
  status: number,
|};

function GeoPositionItem(props: GeoPositionsItemProps): React.Node {
  return (
    <SRow>
      <SSpan>Data:</SSpan>
      Longitude: {props.longitude} <br/>
      Latitude: {props.latitude} <br/>
      Altitude: {props.altitude} <br/>
      Status: {props.status} <br/>
    </SRow>
  );
}

let positionData = {
  latitude: 0,
  longitude: 0,
  altitude: 0,
  status: 0,
};
function RosmapPanel(): React.Node {
  const consecutiveMsgs = useMessagesByTopic({ topics: ["/gps/fix"], historySize: 1 })["/gps/fix"];

  if (consecutiveMsgs && consecutiveMsgs.length >= 1) {
    positionData.longitude = consecutiveMsgs[0].message.longitude;
    positionData.latitude = consecutiveMsgs[0].message.latitude;
    positionData.altitude = consecutiveMsgs[0].message.altitude;
    positionData.status = consecutiveMsgs[0].message.header.seq;
  }
  return (
    <Flex>
      <h1>Recording</h1>
      <Flex col wrap center start>
        <Flex col style={{ width: "100%", padding: "12px" }}>
          <GeoPositionItem longitude={positionData.longitude} latitude={positionData.latitude} altitude={positionData.altitude} status={positionData.status}></GeoPositionItem>
        </Flex>
      </Flex>
    </Flex>
  );
}

RosmapPanel.panelType = "Rosmap";
RosmapPanel.defaultConfig = {};

export default hot(Panel<Config>(RosmapPanel));
troygibb commented 4 years ago

Hi @meyerjo! One thing you could try is to move down the positionData declaration into the body of the RosmapPanel component. Generally you never use/update global variables in React.

function RosmapPanel(): React.Node {
  const consecutiveMsgs = useMessagesByTopic({ topics: ["/gps/fix"], historySize: 1 })["/gps/fix"];

  const positionData = {
    latitude: 0,
    longitude: 0,
    altitude: 0,
    status: 0,
  };

  if (consecutiveMsgs && consecutiveMsgs.length >= 1) {
    positionData.longitude = consecutiveMsgs[0].message.longitude;
    positionData.latitude = consecutiveMsgs[0].message.latitude;
    positionData.altitude = consecutiveMsgs[0].message.altitude;
    positionData.status = consecutiveMsgs[0].message.header.seq;
  }
  return (
    <Flex>
      <h1>Recording</h1>
      <Flex col wrap center start>
        <Flex col style={{ width: "100%", padding: "12px" }}>
          <GeoPositionItem
            longitude={positionData.longitude}
            latitude={positionData.latitude}
            altitude={positionData.altitude}
            status={positionData.status}
          />
        </Flex>
      </Flex>
    </Flex>
  );
}

There are ways to optimize this bit as well I could help you out with. But try this out first to see if that helps things!

Also if you're able to share a bag for this example, that would help debugging performance as well 😄

meyerjo commented 4 years ago

Thanks for the quick reply. For debugging the panel I used the demo rosbag https://open-source-webviz-ui.s3.amazonaws.com/demo.bag , with that I am still experiencing the same problem. I also tried to stream from a local rosbag file in this case the performance issue is not that drastic.

However, when streaming from the local rosbridge I encounter the problem that my memory is overflowing and the chrome process tries to allocate >35 GB. Can I specify somehow that no local cache is generated by webviz?

janpaul123 commented 4 years ago

It sounds like there's just an overflow of messages. Maybe create a topic that is a throttled version of this topic, e.g. one that only emits a message every 100ms or so?