Skip to content

Instantly share code, notes, and snippets.

@duck2
Last active March 24, 2019 21:23
Show Gist options
  • Save duck2/02d001727a252de4a118ae63b680a11c to your computer and use it in GitHub Desktop.
Save duck2/02d001727a252de4a118ae63b680a11c to your computer and use it in GitHub Desktop.
draft for rr_graph.xml reader with SAX
#include <cstring>
#include <fstream>
#include <iostream>
#include <unordered_map>
#include <stack>
#include <vector>
#include <libxml/parser.h>
#pragma pack(1)
typedef std::unordered_map<std::string, std::string> AttributeMap;
struct ChannelList {
int index;
int info;
};
struct Channels {
int chan_width_max;
int x_min;
int y_min;
int x_max;
int y_max;
std::vector<ChannelList> x_list;
std::vector<ChannelList> y_list;
};
enum SwitchType : char {
INVALID_SWITCH_TYPE,
MUX,
TRISTATE,
PASS_GATE,
SHORT,
BUFFER
};
struct SwitchTiming {
float r;
float c_in;
float c_out;
float t_del;
};
struct SwitchSizing {
float mux_trans_size;
float buf_size;
};
struct Switch {
int id;
std::string name;
SwitchType type;
SwitchTiming timing;
SwitchSizing sizing;
};
struct SegmentTiming {
float r_per_meter;
float c_per_meter;
};
struct Segment {
int id;
std::string name;
SegmentTiming timing;
};
enum PinType : char {
NONE,
OPEN,
OUTPUT,
INPUT
};
struct Pin {
int ptc;
std::string name;
};
struct PinClass {
PinType type;
std::vector<Pin> pins;
};
struct BlockType {
int id;
std::string name;
int width;
int height;
std::vector<PinClass> pin_classes;
};
struct GridLoc {
int x;
int y;
int block_type_id;
int width_offset;
int height_offset;
};
enum NodeType : char {
INVALID_NODE_TYPE,
CHANX,
CHANY,
SOURCE,
SINK,
OPIN,
IPIN
};
enum NodeDirection : char {
NO_DIR,
INC_DIR,
DEC_DIR,
BI_DIR
};
enum NodeSide : char {
NO_SIDE,
LEFT,
RIGHT,
TOP,
BOTTOM
};
struct NodeTiming {
float r;
float c;
};
struct NodeLoc {
short x_low;
short y_low;
short x_high;
short y_high;
NodeSide side;
int ptc;
};
struct NodeMetadata {
char *name = NULL;
char *value = NULL;
int x_offset;
int y_offset;
int z_offset;
void set_name(const std::string& n){
name = (char *)malloc(n.length()+1);
strcpy(name, n.c_str());
}
void set_value(const std::string& v){
value = (char *)malloc(v.length()+1);
strcpy(value, v.c_str());
}
};
struct NodeSegment {
int segment_id = -1;
};
struct RrNode {
NodeType type;
NodeDirection direction;
int id;
int capacity;
NodeSegment segment;
NodeTiming timing;
NodeLoc loc;
std::vector<NodeMetadata> *metadata = NULL;
void alloc_metadata(){
metadata = new std::vector<NodeMetadata>;
metadata->reserve(1);
}
};
struct RrEdge {
int src_node;
int sink_node;
int switch_id;
std::vector<NodeMetadata> *metadata = NULL;
void alloc_metadata(){
metadata = new std::vector<NodeMetadata>;
metadata->reserve(1);
}
};
struct RrGraph {
std::string tool_version;
std::string tool_comment;
Channels channels;
std::vector<Switch> switches;
std::vector<Segment> segments;
std::vector<BlockType> block_types;
std::vector<GridLoc> grid;
std::vector<RrNode> rr_nodes;
std::vector<RrEdge> rr_edges;
~RrGraph(){
for(auto n : rr_nodes){
if(n.metadata){
for(auto m : *n.metadata){
free(m.name);
free(m.value);
}
delete n.metadata;
}
}
for(auto e: rr_edges){
if(e.metadata){
for(auto m : *e.metadata){
free(m.name);
free(m.value);
}
delete e.metadata;
}
}
}
};
class RRSaxReader {
public:
RRSaxReader();
~RRSaxReader();
std::stack <const char *> parser_stack;
RrGraph rr_graph = {};
/* <meta> tags are found in both nodes and edges, and they are deeply nested.
* We hold pointers to know where to push new <meta> tags and which MetaData
* struct to fill when a text node arrives.
* Note that these pointers can be invalidated when the vectors holding them do
* a reallocation, but text nodes we are interested in come right after their associated
* elements, and nothing should be push_back'ed between the tag and the text. */
std::vector<NodeMetadata> *current_metadata;
NodeMetadata *current_meta;
/* <pin> tags also carry a text node */
Pin *current_pin;
xmlSAXHandler sax_handler = {};
void load_rr_file(const char *name);
void on_start_element(const char *name, const char **attrs);
void on_end_element(const char *name);
void on_characters(const char *text, int ch);
void consume_channels(AttributeMap& attrs);
void consume_switches(AttributeMap& attrs);
void consume_segments(AttributeMap& attrs);
void consume_block_types(AttributeMap& attrs);
void consume_grid(AttributeMap& attrs);
void consume_rr_nodes(AttributeMap& attrs);
void consume_rr_edges(AttributeMap& attrs);
void consume_channel(AttributeMap& attrs);
void consume_x_list(AttributeMap& attrs);
void consume_y_list(AttributeMap& attrs);
void consume_switch(AttributeMap& attrs);
void consume_switch_timing(AttributeMap& attrs);
void consume_switch_sizing(AttributeMap& attrs);
void consume_segment(AttributeMap& attrs);
void consume_segment_timing(AttributeMap& attrs);
void consume_block_type(AttributeMap& attrs);
void consume_pin_class(AttributeMap& attrs);
void consume_pin(AttributeMap& attrs);
void consume_grid_loc(AttributeMap& attrs);
void consume_node(AttributeMap& attrs);
void consume_node_loc(AttributeMap& attrs);
void consume_node_timing(AttributeMap& attrs);
void consume_node_segment(AttributeMap& attrs);
void consume_node_metadata(AttributeMap& attrs);
void consume_meta(AttributeMap& attrs);
void consume_edge(AttributeMap& attrs);
void consume_edge_metadata(AttributeMap& attrs);
friend struct RRSaxCallback;
};
/* The callback functions have to be static. If we make them static in the
* class, they don't know which object to access. So we hide the pointer to the RRSaxReader object
* in the parser context, unpack it in the static function and call the object's callback.
* While we are at it, we can also cast xmlChars to chars because they create a bit of trouble. */
struct RRSaxCallback {
static void on_start_element(void *ctx, const xmlChar *name, const xmlChar **attrs){
auto _ctx = (_xmlParserCtxt *) ctx;
auto parser = (RRSaxReader *)_ctx->_private;
parser->on_start_element((const char *)name, (const char **)attrs);
}
static void on_end_element(void *ctx, const xmlChar *name){
auto _ctx = (_xmlParserCtxt *) ctx;
auto parser = (RRSaxReader *)_ctx->_private;
parser->on_end_element((const char *)name);
}
static void on_characters(void *ctx, const xmlChar *ch, int len){
auto _ctx = (_xmlParserCtxt *) ctx;
auto parser = (RRSaxReader *)_ctx->_private;
parser->on_characters((const char *)ch, len);
}
};
RRSaxReader::RRSaxReader(){
sax_handler.startElement = RRSaxCallback::on_start_element;
sax_handler.endElement = RRSaxCallback::on_end_element;
sax_handler.characters = RRSaxCallback::on_characters;
}
RRSaxReader::~RRSaxReader(){}
void RRSaxReader::load_rr_file(const char* read_rr_graph_name) {
/* parse the file */
std::ifstream F(read_rr_graph_name);
char buffer[1048576];
RRSaxReader parser;
auto ctx = xmlCreatePushParserCtxt(&sax_handler, NULL, NULL, 0, read_rr_graph_name);
/* Store the pointer to this in the parser context,
* so that the static callbacks find their way to this object. */
ctx->_private = (void *) this;
do {
F.read(buffer, 1048575);
xmlParseChunk(ctx, buffer, F.gcount(), 0);
} while(F);
xmlParseChunk(ctx, buffer, 0, 1);
xmlFreeParserCtxt(ctx);
}
static std::unordered_map<std::string, std::unordered_map<std::string, void(RRSaxReader::*)(AttributeMap&)>> parse_table = {
{"rr_graph", {
{"channels", &RRSaxReader::consume_channels},
{"switches", &RRSaxReader::consume_switches},
{"segments", &RRSaxReader::consume_segments},
{"block_types", &RRSaxReader::consume_block_types},
{"grid", &RRSaxReader::consume_grid},
{"rr_nodes", &RRSaxReader::consume_rr_nodes},
{"rr_edges", &RRSaxReader::consume_rr_edges}
}},
{"channels", {
{"channel", &RRSaxReader::consume_channel},
{"x_list", &RRSaxReader::consume_x_list},
{"y_list", &RRSaxReader::consume_y_list},
}},
{"switches", {
{"switch", &RRSaxReader::consume_switch},
}},
{"switch", {
{"timing", &RRSaxReader::consume_switch_timing},
{"sizing", &RRSaxReader::consume_switch_sizing},
}},
{"segments", {
{"segment", &RRSaxReader::consume_segment},
}},
{"segment", {
{"timing", &RRSaxReader::consume_segment_timing},
}},
{"block_types", {
{"block_type", &RRSaxReader::consume_block_type},
}},
{"block_type", {
{"pin_class", &RRSaxReader::consume_pin_class},
}},
{"pin_class", {
{"pin", &RRSaxReader::consume_pin},
}},
{"grid", {
{"grid_loc", &RRSaxReader::consume_grid_loc},
}},
{"rr_nodes", {
{"node", &RRSaxReader::consume_node},
}},
{"rr_edges", {
{"edge", &RRSaxReader::consume_edge},
}},
{"node", {
{"loc", &RRSaxReader::consume_node_loc},
{"timing", &RRSaxReader::consume_node_timing},
{"segment", &RRSaxReader::consume_node_segment},
{"metadata", &RRSaxReader::consume_node_metadata},
}},
{"edge", {
{"metadata", &RRSaxReader::consume_edge_metadata},
}},
{"metadata", {
{"meta", &RRSaxReader::consume_meta},
}},
};
void RRSaxReader::on_start_element(const char *name, const char **attrs){
if(parser_stack.empty()){
if(strcmp(name, "rr_graph") == 0){
parser_stack.push("rr_graph");
} else throw std::runtime_error("no <rr_graph> tag found");
return;
}
auto top = parser_stack.top();
parser_stack.push(name);
/* Convert attributes to hashtable first. */
AttributeMap map;
for(const char **c = attrs; c && *c; c += 2){
map[*c] = *(c+1);
}
/* Look up callback function from current and previous tags. */
auto fn = parse_table[top][name];
if(fn != NULL){
(this->*fn)(map);
return;
}
std::cout << "Unexpected " << name << " after " << top << std::endl;
return;
}
void RRSaxReader::on_end_element(const char *name){
parser_stack.pop();
}
/* A text node should only occur inside a <meta> or a <pin> tag. */
void RRSaxReader::on_characters(const char *ch, int len){
auto top = parser_stack.top();
if(top == "meta"){
//std::cout << "filling in meta " << text << " addr = " << current_meta << std::endl;
current_meta->set_value(ch);
} else if(top == "pin"){
//std::cout << "filling in pin " << text << " addr=" << current_pin << std::endl;
current_pin->name = ch;
}
}
void RRSaxReader::consume_channels(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_switches(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_segments(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_block_types(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_grid(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_rr_nodes(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_rr_edges(AttributeMap& attrs){
return;
}
void RRSaxReader::consume_channel(AttributeMap& attrs){
rr_graph.channels.chan_width_max = std::stoi(attrs["chan_width_max"]);
rr_graph.channels.x_min = std::stoi(attrs["x_min"]);
rr_graph.channels.y_min = std::stoi(attrs["y_min"]);
rr_graph.channels.x_max = std::stoi(attrs["x_max"]);
rr_graph.channels.y_max = std::stoi(attrs["y_max"]);
}
void RRSaxReader::consume_x_list(AttributeMap& attrs){
ChannelList list;
list.index = std::stoi(attrs["index"]);
list.info = std::stoi(attrs["info"]);
rr_graph.channels.x_list.push_back(list);
}
void RRSaxReader::consume_y_list(AttributeMap& attrs){
ChannelList list;
list.index = std::stoi(attrs["index"]);
list.info = std::stoi(attrs["info"]);
rr_graph.channels.y_list.push_back(list);
}
void RRSaxReader::consume_switch(AttributeMap& attrs){
Switch sw;
sw.id = std::stoi(attrs["id"]);
sw.name = attrs["name"];
if(attrs["type"] == "mux") sw.type = MUX;
else if(attrs["type"] == "tristate") sw.type = TRISTATE;
else if(attrs["type"] == "pass_gate") sw.type = PASS_GATE;
else if(attrs["type"] == "short") sw.type = SHORT;
else if(attrs["type"] == "buffer") sw.type = BUFFER;
else sw.type = INVALID_SWITCH_TYPE;
rr_graph.switches.push_back(sw);
}
/* map's operator[] gives default value for nonexistent keys:
* http://www.cplusplus.com/reference/map/map/operator%5B%5D/ */
void RRSaxReader::consume_switch_timing(AttributeMap& attrs){
Switch& sw = rr_graph.switches.back();
if(attrs["R"] != "") sw.timing.r = std::stof(attrs["R"]);
if(attrs["Cin"] != "") sw.timing.c_in = std::stof(attrs["Cin"]);
if(attrs["Cout"] != "") sw.timing.c_out = std::stof(attrs["Cout"]);
if(attrs["Tdel"] != "") sw.timing.t_del = std::stof(attrs["Tdel"]);
}
void RRSaxReader::consume_switch_sizing(AttributeMap& attrs){
Switch& sw = rr_graph.switches.back();
sw.sizing.mux_trans_size = std::stof(attrs["mux_trans_size"]);
sw.sizing.buf_size = std::stof(attrs["buf_size"]);
}
void RRSaxReader::consume_segment(AttributeMap& attrs){
Segment seg;
seg.id = std::stoi(attrs["id"]);
seg.name = attrs["name"];
rr_graph.segments.push_back(seg);
}
void RRSaxReader::consume_segment_timing(AttributeMap& attrs){
Segment& seg = rr_graph.segments.back();
if(attrs["R_per_meter"] != "") seg.timing.r_per_meter = std::stof(attrs["R_per_meter"]);
if(attrs["C_per_meter"] != "") seg.timing.c_per_meter = std::stof(attrs["C_per_meter"]);
}
void RRSaxReader::consume_block_type(AttributeMap& attrs){
BlockType bt;
bt.id = std::stoi(attrs["id"]);
bt.name = attrs["name"];
bt.width = std::stoi(attrs["width"]);
bt.height = std::stoi(attrs["height"]);
rr_graph.block_types.push_back(bt);
}
void RRSaxReader::consume_pin_class(AttributeMap& attrs){
BlockType& bt = rr_graph.block_types.back();
PinClass pc;
if(attrs["type"] == "open") pc.type = OPEN;
else if(attrs["type"] == "output") pc.type = OUTPUT;
else if(attrs["type"] == "input") pc.type = INPUT;
else pc.type = NONE;
bt.pin_classes.push_back(pc);
}
void RRSaxReader::consume_pin(AttributeMap& attrs){
BlockType& bt = rr_graph.block_types.back();
PinClass& pc = bt.pin_classes.back();
Pin pin;
pin.ptc = std::stoi(attrs["ptc"]);
pc.pins.push_back(pin);
current_pin = &(pc.pins.back());
}
void RRSaxReader::consume_grid_loc(AttributeMap& attrs){
GridLoc gl;
gl.x = std::stoi(attrs["x"]);
gl.y = std::stoi(attrs["y"]);
gl.block_type_id = std::stoi(attrs["block_type_id"]);
gl.width_offset = std::stoi(attrs["width_offset"]);
gl.height_offset = std::stoi(attrs["height_offset"]);
rr_graph.grid.push_back(gl);
}
void RRSaxReader::consume_node(AttributeMap& attrs){
RrNode node;
node.id = std::stoi(attrs["id"]);
if(attrs["type"] == "CHANX") node.type = CHANX;
else if(attrs["type"] == "CHANY") node.type = CHANY;
else if(attrs["type"] == "SOURCE") node.type = SOURCE;
else if(attrs["type"] == "SINK") node.type = SINK;
else if(attrs["type"] == "OPIN") node.type = OPIN;
else if(attrs["type"] == "IPIN") node.type = IPIN;
else node.type = INVALID_NODE_TYPE;
rr_graph.rr_nodes.push_back(node);
}
void RRSaxReader::consume_node_loc(AttributeMap& attrs){
RrNode& node = rr_graph.rr_nodes.back();
node.loc.x_low = std::stoi(attrs["xlow"]);
node.loc.y_low = std::stoi(attrs["ylow"]);
node.loc.x_high = std::stoi(attrs["xhigh"]);
node.loc.y_high = std::stoi(attrs["yhigh"]);
node.loc.ptc = std::stoi(attrs["ptc"]);
if(attrs["side"] == "LEFT") node.loc.side = LEFT;
else if(attrs["side"] == "RIGHT") node.loc.side = RIGHT;
else if(attrs["side"] == "TOP") node.loc.side = TOP;
else if(attrs["side"] == "BOTTOM") node.loc.side = BOTTOM;
else node.loc.side = NO_SIDE;
}
void RRSaxReader::consume_node_timing(AttributeMap& attrs){
RrNode& node = rr_graph.rr_nodes.back();
if(attrs["R"] != "") node.timing.r = std::stof(attrs["R"]);
if(attrs["C"] != "") node.timing.c = std::stof(attrs["C"]);
}
void RRSaxReader::consume_node_segment(AttributeMap& attrs){
RrNode& node = rr_graph.rr_nodes.back();
if(attrs["segment_id"] != "") node.segment.segment_id = std::stof(attrs["segment_id"]);
}
void RRSaxReader::consume_node_metadata(AttributeMap& attrs){
RrNode& node = rr_graph.rr_nodes.back();
node.alloc_metadata();
current_metadata = node.metadata;
}
void RRSaxReader::consume_meta(AttributeMap& attrs){
NodeMetadata md;
md.set_name(attrs["name"]);
if(attrs["x_offset"] != "") md.x_offset = std::stoi(attrs["x_offset"]);
if(attrs["y_offset"] != "") md.y_offset = std::stoi(attrs["y_offset"]);
if(attrs["z_offset"] != "") md.z_offset = std::stoi(attrs["z_offset"]);
(*current_metadata).push_back(md);
/* needed to read value */
current_meta = &((*current_metadata).back());
}
void RRSaxReader::consume_edge(AttributeMap& attrs){
RrEdge edge;
edge.src_node = std::stoi(attrs["src_node"]);
edge.sink_node = std::stoi(attrs["sink_node"]);
edge.switch_id = std::stoi(attrs["switch_id"]);
rr_graph.rr_edges.push_back(edge);
}
void RRSaxReader::consume_edge_metadata(AttributeMap& attrs){
RrEdge& edge = rr_graph.rr_edges.back();
edge.alloc_metadata();
current_metadata = edge.metadata;
}
int main(){
RRSaxReader reader;
reader.load_rr_file("rr_graph_big.xml");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment