From 68fe668567764d3466ac49042f9f117010aed943 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 22 Jan 2019 07:42:44 +0100 Subject: [PATCH] WIP: performance improvement. --- src/db/db/dbDeepShapeStore.cc | 2 +- src/db/db/dbNetlistDeviceExtractor.cc | 116 +++++++++-- src/db/db/dbNetlistDeviceExtractor.h | 3 +- src/db/unit_tests/dbNetlistExtractorTests.cc | 207 +++++++++++++++++++ 4 files changed, 311 insertions(+), 17 deletions(-) diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index b7bf576d3..cf7c48bcf 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -433,7 +433,7 @@ DeepShapeStore::cell_mapping_to_original (size_t layout_index, db::Layout *into_ } if (! skip) { - cm->second.map (m->first.first, m->second); + cm->second.map (m->second, m->first.first); } } diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 821944950..e45cedf92 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -25,6 +25,9 @@ #include "dbHierNetworkProcessor.h" #include "dbDeepRegion.h" +#include "tlProgress.h" +#include "tlTimer.h" + namespace db { @@ -156,23 +159,53 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: } // collect the cells below the top cell + std::set all_called_cells; + all_called_cells.insert (cell.cell_index ()); + cell.collect_called_cells (all_called_cells); + + // ignore device cells from previous extractions std::set called_cells; - called_cells.insert (cell.cell_index ()); - cell.collect_called_cells (called_cells); + for (std::set::const_iterator ci = all_called_cells.begin (); ci != all_called_cells.end (); ++ci) { + if (! m_netlist->device_abstract_by_cell_index (*ci)) { + called_cells.insert (*ci); + } + } + all_called_cells.clear (); // build the device clusters db::Connectivity device_conn = get_connectivity (layout, layers); db::hier_clusters device_clusters; device_clusters.build (layout, cell, shape_iter_flags, device_conn); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Extracting devices"))); + + // count effort and make a progress reporter + + size_t n = 0; + for (std::set::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) { + db::connected_clusters cc = device_clusters.clusters_per_cell (*ci); + for (db::connected_clusters::all_iterator c = cc.begin_all (); !c.at_end(); ++c) { + if (cc.is_root (*c)) { + ++n; + } + } + } + + tl::RelativeProgress progress (tl::to_string (tr ("Extracting devices")), n, 1); + + struct ExtractorCacheValueType { + ExtractorCacheValueType () : circuit (0) { } + db::Circuit *circuit; + db::Vector disp; + std::map geometry; + }; + + typedef std::map, ExtractorCacheValueType> extractor_cache_type; + extractor_cache_type extractor_cache; + // for each cell investigate the clusters for (std::set::const_iterator ci = called_cells.begin (); ci != called_cells.end (); ++ci) { - // skip device cells from previous extractions - if (m_netlist->device_abstract_by_cell_index (*ci)) { - continue; - } - m_cell_index = *ci; std::map::const_iterator c2c = circuits_by_cell.find (*ci); @@ -200,6 +233,8 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: continue; } + ++progress; + // build layer geometry from the cluster found std::vector layer_geometry; @@ -210,28 +245,55 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: for (db::recursive_cluster_shape_iterator si (device_clusters, *l, *ci, *c); ! si.at_end(); ++si) { insert_into_region (*si, si.trans (), r); } + // r.merge ()??? } - // do the actual device extraction - extract_devices (layer_geometry); + db::Box box; + for (std::vector::const_iterator g = layer_geometry.begin (); g != layer_geometry.end (); ++g) { + box += g->bbox (); + } - // push the new devices to the layout - push_new_devices (); + db::Vector disp = box.p1 () - db::Point (); + for (std::vector::iterator g = layer_geometry.begin (); g != layer_geometry.end (); ++g) { + g->transform (db::Disp (-disp)); + } + + extractor_cache_type::const_iterator ec = extractor_cache.find (layer_geometry); + if (ec == extractor_cache.end ()) { + + // do the actual device extraction + extract_devices (layer_geometry); + + // push the new devices to the layout + push_new_devices (disp); + + ExtractorCacheValueType &ecv = extractor_cache [layer_geometry]; + ecv.disp = disp; + ecv.circuit = mp_circuit; + ecv.geometry.swap (m_new_devices); + + } else { + + push_cached_devices (ec->second.circuit, ec->second.geometry, ec->second.disp, disp); + + } } } } -void NetlistDeviceExtractor::push_new_devices () +void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache) { - db::VCplxTrans dbu_inv = db::CplxTrans (mp_layout->dbu ()).inverted (); + db::CplxTrans dbu = db::CplxTrans (mp_layout->dbu ()); + db::VCplxTrans dbu_inv = dbu.inverted (); for (std::map::const_iterator d = m_new_devices.begin (); d != m_new_devices.end (); ++d) { db::Device *device = mp_circuit->device_by_id (d->first); db::Vector disp = dbu_inv * device->position () - db::Point (); + device->set_position (device->position () + dbu * disp_cache); DeviceCellKey key; @@ -302,12 +364,36 @@ void NetlistDeviceExtractor::push_new_devices () ps.insert (std::make_pair (m_device_id_propname_id, tl::Variant (d->first))); db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps); - db::CellInstArrayWithProperties inst (db::CellInstArray (db::CellInst (c->second.first), db::Trans (disp)), pi); + db::CellInstArrayWithProperties inst (db::CellInstArray (db::CellInst (c->second.first), db::Trans (disp_cache + disp)), pi); mp_layout->cell (m_cell_index).insert (inst); } +} - m_new_devices.clear (); +void NetlistDeviceExtractor::push_cached_devices (db::Circuit *circuit, const std::map &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp) +{ + db::CplxTrans dbu = db::CplxTrans (mp_layout->dbu ()); + db::VCplxTrans dbu_inv = dbu.inverted (); + db::PropertiesRepository::properties_set ps; + + for (std::map::const_iterator d = cached_devices.begin (); d != cached_devices.end (); ++d) { + + db::Device *cached_device = circuit->device_by_id (d->first); + db::Vector disp = dbu_inv * cached_device->position () - disp_cache - db::Point (); + + db::Device *device = new db::Device (*cached_device); + mp_circuit->add_device (device); + device->set_position (device->position () + dbu * (new_disp - disp_cache)); + + // Build a property set for the device ID + ps.clear (); + ps.insert (std::make_pair (m_device_id_propname_id, tl::Variant (device->id ()))); + db::properties_id_type pi = mp_layout->properties_repository ().properties_id (ps); + + db::CellInstArrayWithProperties inst (db::CellInstArray (db::CellInst (device->device_abstract ()->cell_index ()), db::Trans (new_disp + disp)), pi); + mp_layout->cell (m_cell_index).insert (inst); + + } } void NetlistDeviceExtractor::setup () diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index 0be8e5f7f..e2b97280d 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -521,7 +521,8 @@ private: void initialize (db::Netlist *nl); void extract_without_initialize (db::Layout &layout, db::Cell &cell, hier_clusters_type &clusters, const std::vector &layers); - void push_new_devices (); + void push_new_devices (const Vector &disp_cache); + void push_cached_devices (db::Circuit *circuit, const std::map &cached_devices, const db::Vector &disp_cache, const db::Vector &new_disp); }; } diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 1ac2bbdf9..add58495f 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -340,3 +340,210 @@ TEST(1_DeviceAndNetExtraction) db::compare_layouts (_this, ly, au); } + +TEST(2_DeviceAndNetExtractionFlat) +{ + db::Layout ly (true); + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int poly = define_layer (ly, lmap, 3); + unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); + unsigned int diff_cont = define_layer (ly, lmap, 4); + unsigned int poly_cont = define_layer (ly, lmap, 5); + unsigned int metal1 = define_layer (ly, lmap, 6); + unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); + unsigned int via1 = define_layer (ly, lmap, 7); + unsigned int metal2 = define_layer (ly, lmap, 8); + unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l1.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + ly.flatten (ly.cell (*ly.begin_top_down ()), -1, true); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Region rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Region rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Region rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> Gate + unsigned int lsd = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> Source/Drain + unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion + unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion + + rpgate.insert_into (&ly, tc.cell_index (), lgate); + rngate.insert_into (&ly, tc.cell_index (), lgate); + rpsd.insert_into (&ly, tc.cell_index (), lsd); + rnsd.insert_into (&ly, tc.cell_index (), lsd); + rpsd.insert_into (&ly, tc.cell_index (), lpdiff); + rnsd.insert_into (&ly, tc.cell_index (), lndiff); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, dl, nl, cl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, dl, nl, cl); + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rpsd); + conn.connect (rnsd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rpsd, rdiff_cont); + conn.connect (rnsd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + net_ex.extract_nets (dss, conn, nl, cl); + + // debug layers produced for nets + // 202/0 -> Active + // 203/0 -> Poly + // 204/0 -> Diffusion contacts + // 205/0 -> Poly contacts + // 206/0 -> Metal1 + // 207/0 -> Via1 + // 208/0 -> Metal2 + // 210/0 -> N source/drain + // 211/0 -> P source/drain + std::map dump_map; + dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + + // write nets to layout + db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); + dump_nets_to_layout (nl, cl, ly, dump_map, cm); + + // compare netlist as string + // NOTE: some of the nets are called IN,OUT but are different ones. They + // happen to be the same because they share the same label. + EXPECT_EQ (nl.to_string (), + "Circuit RINGO ():\n" + " DPMOS $1 (S='IN,FB',G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $2 (S=VDD,G='IN,FB',D='OUT,OSC') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $3 (S=$18,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $4 (S=VDD,G=$18,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $5 (S=$16,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $6 (S=VDD,G=$16,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $7 (S=$14,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $8 (S=VDD,G=$14,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $9 (S=$12,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $10 (S=VDD,G=$12,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $11 (S=$4,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $12 (S=VDD,G=$4,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $13 (S=$8,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $14 (S=VDD,G=$8,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $15 (S=$6,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $16 (S=VDD,G=$6,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $17 (S=$2,G='IN,FB',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $18 (S=VDD,G=$2,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DPMOS $19 (S=$10,G='IN,OUT',D=VDD) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DPMOS $20 (S=VDD,G=$10,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $21 (S='IN,FB',G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $22 (S=VSS,G='IN,FB',D='OUT,OSC') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $23 (S=$16,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $24 (S=VSS,G=$16,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $25 (S=$14,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $26 (S=VSS,G=$14,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $27 (S=$12,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $28 (S=VSS,G=$12,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $29 (S=$4,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $30 (S=VSS,G=$4,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $31 (S=$18,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $32 (S=VSS,G=$18,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $33 (S=$2,G='IN,FB',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $34 (S=VSS,G=$2,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $35 (S=$10,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $36 (S=VSS,G=$10,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $37 (S=$6,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $38 (S=VSS,G=$6,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + " DNMOS $39 (S=$8,G='IN,OUT',D=VSS) [L=0.25,W=0.95,AS=0.49875,AD=0.26125]\n" + " DNMOS $40 (S=VSS,G=$8,D='IN,OUT') [L=0.25,W=0.95,AS=0.26125,AD=0.49875]\n" + ); + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1_flat.gds"); + + db::compare_layouts (_this, ly, au); +}