Skip to content

Dashboard for RRGraph API refactoring status #1868

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

Open
44 tasks done
tangxifan opened this issue Oct 11, 2021 · 19 comments
Open
44 tasks done

Dashboard for RRGraph API refactoring status #1868

tangxifan opened this issue Oct 11, 2021 · 19 comments
Assignees

Comments

@tangxifan
Copy link
Contributor

tangxifan commented Oct 11, 2021

Motivation of Refactoring effort

A detailed technical plan can be found at link

The overall refactoring effort aims to

  • create a unified data structure RRGraphView as a centralized storage for all the routing resource graph -related information. See Fig. 1
  • create a set of frame view object from the centralized storage RRGraph for client functions, which are suitable for rr_graph builder, placer, router, GUI, timing analyzer etc. See Fig. 2.
  • This is to avoid massive updates to the codes of client functions when there is a change on the unified data structure.
  • Also it avoid large memory footprint for client functions, since each client function may only use a small portion (typically <50%) APIs of the unified object.

image
Fig. 1 Illustration of the relationship between data structures

image
Fig. 2 Different levels of frame views of routing resource graphs to satisfy various needs from client functions.

The result/benefits of the refactoring efforts is

  • The routing resource graph can be decoupled from VPR's core engine as a library. Unit tests can be enabled
  • It is much easier for developers to develop custom routing resource graph builders thanks to the APIs of the unified data structure RRGraph. A routing resource graph builder can be a library, decoupled from VPR's core engine. Many checking codes can be efficiently merged into the data structure and developers can save a lot of efforts in writing the atom-level sanity checks.
  • Ensure that each client functions have a clean view of the routing resource graph, i.e. RRGraphView. In other words, routing resource graph will be read-only and only accessors are exposed to client functions. Developers have no worries on developing their own placer/router etc.

Checklist

RRGraphBuilder API to be refactored:

RRGraphView API to be refactored:

@tangxifan
Copy link
Contributor Author

@ethanroj23 @hariszafar-lm @hamzakhan-rs
I summarized our ongoing refactoring effort here and created a checklist.
The idea is to keep a memo for all of us on the progress bar, so that we all know where we are and how far we are to reach the destination.

@baberali-rs
Copy link

@tangxifan There are some new APIs which do not exist in rr_node.h or anywhere you mentioned above and we will implement them in RRGraphView or RRGraphBuilder, right?
@ethanroj23 Can you please tell me which APIs you are currently working on? So that we can work on others.

@ethanroj23
Copy link
Contributor

@baberali-rs I am currently working on node_type(), node_type_string(), and node_side_string() in RRGraphView.

@tangxifan
Copy link
Contributor Author

@ethanroj23 Thanks for the update. While are you working these APIs, would you mind the Rapidsilicon team working on merging the rr_segment into RRGraphView? We will be active in resolving any merging conflicts.

@ethanroj23
Copy link
Contributor

@tangxifan I would not mind. That would be very helpful, thanks!

@tangxifan
Copy link
Contributor Author

@baberali-rs Yes. I have discussed with @vaughnbetz and @kmurray. We agree to

  • Force the use of strong ids for the rr_index_data, rr_switch and rr_segment. For any node/edge-level data query API in RRGraphBuilder and RRGraphView, it should return the strong id rather than an int as the unique index.
  • Merge the rr_index_data, rr_switch and rr_segment into RRGraphBuilder and RRGraphView as an internal storage. It will be part of the internal data at
    /* -- Internal data storage -- */
    private:
    /* TODO: When the refactoring effort finishes,
    * the builder data structure will be the owner of the data storages.
    * That is why the reference to storage/lookup is used here.
    * It can avoid a lot of code changes once the refactoring is finished
    * (there is no function get data directly through the node_storage in DeviceContext).
    * If pointers are used, it may cause many codes in client functions
    * or inside the data structures to be changed later.
    * That explains why the reference is used here temporarily
    */
    /* node-level storage including edge storages */
    t_rr_graph_storage& node_storage_;
    /* Fast look-up for rr nodes */
    RRSpatialLookup node_lookup_;

/* -- Internal data storage -- */
/* Note: only read-only object or data structures are allowed!!! */
private:
/* node-level storage including edge storages */
const t_rr_graph_storage& node_storage_;
/* Fast look-up for rr nodes */
const RRSpatialLookup& node_lookup_;
/* rr_indexed_data_ and rr_segments_ are needed to lookup the segment information in node_coordinate_to_string() */
const vtr::vector<RRIndexedDataId, t_rr_indexed_data>& rr_indexed_data_;
/* Segment info for rr nodes */
const std::vector<t_segment_inf>& rr_segments_;

  • Evaluate if we should directly return the data of rr_index_data, rr_switch and rr_segment, e.g., seg_type(RRNodeId) with a given node id, rather than a two-step process (get RRSegmentId first and then get the data from rr_segments). @vaughnbetz mentioned it may cause some CPU penalties. But we do not know if it is going to be trivial or huge. If trivial, I believe it is worthy.

See details in #1843

I believe you and your team can start developing the step 1 & 2 in the checklist and create pull requests.

Let me know if you have any questions.

@tangxifan
Copy link
Contributor Author

As discussed with @vaughnbetz, once the API refactoring is done. We should do the follow-up refactoring

  • Extract the rr_graph -related data structure to a separated library librrgraph. Then VPR will use linker to access the data structures
    • This library will include RRGraphBuilder, RRGraphView and RRGraphReader and RRGraphWriter
    • **Caution: We have to run QoR tests for this effort and carefully check any QoR degradation. @vaughnbetz mentioned the problem on inline functions. Once we move to a separated library, the linker may be challenged. It may cause a serious performance degradation on router (could be 50%). We should be very careful on this effort
  • Apply unit tests for RRGraph to test it efficiency, especially on the runtime and peak memory usage
  • Rework internal data storage for these APIs to accelerate runtime and reduce peak memory usage.

@tangxifan
Copy link
Contributor Author

@vaughnbetz If I misunderstood your message, feel free to comment. I will formulate the problem.

@tangxifan
Copy link
Contributor Author

As discussed with @ethanroj23 , some of the remaining tasks on the APIs will be assigned to Rapidsilicon team

  • node_ptc_num()/node_pin_num()/node_track_num()/node_class_num() -> @ethanroj23
  • edges()/num_edges() -> Rapidsilicon team
  • configurable_edges()/non_configurable_edges()/num_configurable_edges()/num_non_configurable_edges() -> Rapidsilicon team
  • first_edge()/last_edge() -> Rapidsilicon team
  • edge_sink_node()/edge_switch() -> Rapidsilicon team
  • nodes() -> @ethanroj23
  • rr_switches() -> @ethanroj23

@vaughnbetz
Copy link
Contributor

Thanks @tangxifan. You captured my thoughts well. Basically refactoring into a separate library may not be desirable with a low-level function interface (which is what we have) as we may need inlining for acceptable performance, and that will be left the linker and may not be possible or reliable.

@tangxifan tangxifan added this to the RRGraph Refactoring milestone Nov 18, 2021
@ethanroj23
Copy link
Contributor

ethanroj23 commented Dec 3, 2021

@tangxifan which API are you referencing above called nodes()? I could only find usages of a function called nodes() for the TimingGraph. The same is true for rr_switches(). Are these meant to be brand new APIs? If so, what would be your desired functionality for each?

@tangxifan
Copy link
Contributor Author

tangxifan commented Dec 4, 2021

@ethanroj23 You are right.

  • nodes() should be a new API in place of the current methods that are used to walk through all the nodes

/*
* Node proxy methods
*
* The following methods implement an interface that appears to be
* equivalent to the interface exposed by std::vector<t_rr_node>.
* This was done for backwards compability. See t_rr_node for more details.
*
* Proxy methods:
*
* - begin()
* - end()
* - operator[]
* - at()
* - front
* - back
*
* These methods should not be used by new VPR code, and instead access
* methods that use RRNodeId and RREdgeId should be used.
*
**********************/

It is designed when we consider the context of t_rr_node (there are only nodes and we can access a node using rr_node[i])
However, now, this is a graph. The accessor API should be more precise. For example,

  • We should support range-based loop which is enabled by nodes()
  for (const RRNodeId& node : rr_graph.nodes()) {
     // Use node as the id to get more attributes
  }

You can refer to my implementation at

/* Aggregates: create range-based loops for nodes/edges/switches/segments
* To iterate over the nodes/edges/switches/segments in a RRGraph,
* using a range-based loop is suggested.
* -----------------------------------------------------------------
* Example: iterate over all the nodes
* // Strongly suggest to use a read-only rr_graph object
* const RRGraph& rr_graph;
* for (const RRNodeId& node : rr_graph.nodes()) {
* // Do something with each node
* }
*
* for (const RREdgeId& edge : rr_graph.edges()) {
* // Do something with each edge
* }
*
* for (const RRSwitchId& switch : rr_graph.switches()) {
* // Do something with each switch
* }
*
* for (const RRSegmentId& segment : rr_graph.segments()) {
* // Do something with each segment
* }
*/
node_range nodes() const;

It will help you when implementing the method

RRGraph::node_range RRGraph::nodes() const {
return vtr::make_range(node_ids_.begin(), node_ids_.end());
}

For other APIs, we may consider to deprecate them. Since current APIs always relay on an id to get the information you want, we no long return a data structure t_rr_node anymore. However, it is safer to double check. I am open to add other APIs if necessary.

For rr_switches(), it is brand new APIs. It is a similar story than merging the rr_segments into RRGraphView. Can you look into the PR #1910 ? After that, if you are still confused, we can talk.

Let me know what you think.

@ethanroj23
Copy link
Contributor

ethanroj23 commented Dec 4, 2021

@tangxifan Thank you for the explanation, this makes more sense now! I will begin implementation of this new API and look for feedback once I have done enough for a WIP PR.

@tangxifan
Copy link
Contributor Author

tangxifan commented Dec 8, 2021 via email

@tangxifan
Copy link
Contributor Author

tangxifan commented Jan 6, 2022

@behzadmehmood-rs @umariqbal-rs
Thank you very much on the good work. We have accomplished all the major tasks in this refactoring effort.
We are approaching the final destination! I have listed the last few steps before we can extract the routing resource graph data structure as library.

Please let me know which step you want to take the ownership.

@behzadmehmood-rs
Copy link
Contributor

@tangxifan Thank you for your support. We are ready to own the first four tasks.

@vaughnbetz
Copy link
Contributor

@tangxifan : I think this can be closed. Agreed?

@vaughnbetz
Copy link
Contributor

Or maybe it's waiting for the last item: unit tests?

@tangxifan
Copy link
Contributor Author

@vaughnbetz The unit tests have been built in #2150 but not yet merged. Feel sorry for the delayed review. I will catch that this summer. I am o.k. to close the PR and create a new one on the unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants