libreda_db/
profile.rs

1// SPDX-FileCopyrightText: 2018-2022 Thomas Kramer
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! Acquire performance metrics of single data-base functions.
6//!
7//! # Example
8//!
9//! ```
10//! use libreda_db::prelude::*;
11//! use libreda_db::profile::{DBPerf, FnName};
12//!
13//! let mut chip = Chip::new();
14//! let mut chip_with_perf = DBPerf::new(&mut chip);
15//!
16//! // Do some operations.
17//! let _cell = chip_with_perf.create_cell("MyCell".into());
18//!
19//! let stats = chip_with_perf.get_stats(FnName::create_cell);
20//!
21//! /// Debug-print the statistics.
22//! dbg!(stats);
23//!
24//! assert_eq!(stats.num_calls, 1, "there was exactly one call to the function");
25//! assert!(stats.total_time.as_nanos() > 0);
26//! ```
27
28use crate::prelude::*;
29
30use num_traits::FromPrimitive;
31use std::sync::atomic::AtomicU64;
32use std::time::Duration;
33
34/// Wrapper around netlist and layout data structures.
35/// Transparently measures time spent in function calls.
36///
37/// # Types
38/// * `T`: Underlying data structure.
39#[derive(Default)]
40pub struct DBPerf<T> {
41    /// Underlying data structure.
42    chip: T,
43    perf_counters: PerfCounters,
44}
45
46struct PerfCounters {
47    perf_counters: Vec<(FnName, PerfCounter)>,
48}
49
50impl Default for PerfCounters {
51    fn default() -> Self {
52        Self::new()
53    }
54}
55
56impl<T> DBPerf<T> {
57    /// Wrap the `chip` structure into a performance counter.
58    pub fn new(chip: T) -> Self {
59        Self {
60            chip,
61            perf_counters: PerfCounters::new(),
62        }
63    }
64
65    /// Get a list of counters associated with the API function names.
66    pub fn get_stats_all(&self) -> Vec<(FnName, PerfCounterResult)> {
67        self.perf_counters
68            .perf_counters
69            .iter()
70            .map(|(fname, counter)| (*fname, counter.atomic_read()))
71            .collect()
72    }
73
74    /// Get the performance counter values for the given function.
75    pub fn get_stats(&self, function_name: FnName) -> PerfCounterResult {
76        self.perf_counters.get(function_name).atomic_read()
77    }
78
79    /// Retreive the inner datastructure.
80    /// This is used mainly when the inner data is owned and not a reference.
81    pub fn into_inner(self) -> T {
82        self.chip
83    }
84}
85
86impl PerfCounters {
87    fn new() -> Self {
88        Self {
89            perf_counters: (0..)
90                .map(FnName::from_usize)
91                .take_while(|fname| fname.is_some())
92                .map(|fname| (fname.unwrap(), Default::default()))
93                .collect(),
94        }
95    }
96
97    /// Get a counter by the function name.
98    fn get(&self, function_name: FnName) -> &PerfCounter {
99        &self.perf_counters[function_name as usize].1
100    }
101}
102
103/// Enum of API names.
104/// This is used as an index into the array of performance counters.
105#[derive(Copy, Clone, PartialEq, Eq, ToPrimitive, FromPrimitive, Debug)]
106#[allow(non_camel_case_types, missing_docs)]
107pub enum FnName {
108    // HierarchyBase
109    cell_by_name = 0,
110    cell_instance_by_name,
111    cell_name,
112    cell_instance_name,
113    parent_cell,
114    template_cell,
115    for_each_cell,
116    each_cell_vec,
117    each_cell,
118    for_each_cell_instance,
119    each_cell_instance_vec,
120    each_cell_instance,
121    for_each_cell_dependency,
122    each_cell_dependency_vec,
123    each_cell_dependency,
124    num_cell_dependencies,
125    for_each_dependent_cell,
126    each_dependent_cell_vec,
127    each_dependent_cell,
128    num_dependent_cells,
129    for_each_cell_reference,
130    each_cell_reference_vec,
131    each_cell_reference,
132    num_cell_references,
133    num_child_instances,
134    num_cells,
135    get_chip_property,
136    get_cell_property,
137    get_cell_instance_property,
138
139    // HierarchyEdit,
140    create_cell,
141    remove_cell,
142    create_cell_instance,
143    remove_cell_instance,
144    rename_cell_instance,
145    rename_cell,
146    set_chip_property,
147    set_cell_property,
148    set_cell_instance_property,
149
150    // LayoutEdit
151    insert_shape,
152    set_dbu,
153    create_layer,
154    create_layer_with_id,
155    set_layer_name,
156    remove_shape,
157    replace_shape,
158    set_transform,
159    set_shape_property,
160
161    // NetlistEdit
162    create_pin,
163    remove_pin,
164    rename_pin,
165    create_net,
166    rename_net,
167    remove_net,
168    connect_pin,
169    connect_pin_instance,
170    disconnect_pin,
171    disconnect_pin_instance,
172
173    // L2NBase
174    shapes_of_net,
175    shapes_of_pin,
176    get_net_of_shape,
177    get_pin_of_shape,
178
179    // L2NEdit
180    set_pin_of_shape,
181    set_net_of_shape,
182}
183
184impl std::fmt::Display for FnName {
185    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        // Redirect to `Debug` trait.
187        write!(f, "{:?}", self)
188    }
189}
190
191/// Atomic counters for recording statistics on calls of a single function.
192#[derive(Debug)]
193pub struct PerfCounter {
194    /// Number of function calls.
195    num_calls: AtomicU64,
196    /// Total time spent in this function.
197    total_time_ns: AtomicU64,
198    /// Shortest measured duration spend in this function.
199    min_time_ns: AtomicU64,
200    /// Longest measured duration spend in this function.
201    max_time_ns: AtomicU64,
202}
203
204/// Statistics on calls of a single function.
205#[derive(Debug, Copy, Clone, PartialEq, Eq)]
206pub struct PerfCounterResult {
207    /// Number of function calls.
208    pub num_calls: u64,
209    /// Total time spent in this function.
210    pub total_time: Duration,
211    /// Shortest measured duration spend in this function.
212    pub min_time: Duration,
213    /// Longest measured duration spend in this function.
214    pub max_time: Duration,
215}
216
217impl PerfCounterResult {
218    /// Compute the average time used by the measured function.
219    /// Returns `None` if the number of function calls is zero.
220    pub fn avg_time(&self) -> Option<Duration> {
221        (self.num_calls > 0).then(|| self.total_time / (self.num_calls as u32))
222    }
223}
224
225impl PerfCounter {
226    /// Atomically read the current state of the counter.
227    pub fn atomic_read(&self) -> PerfCounterResult {
228        use std::sync::atomic::Ordering::Relaxed;
229
230        loop {
231            let read = || PerfCounterResult {
232                num_calls: self.num_calls.load(Relaxed),
233                total_time: Duration::from_nanos(self.total_time_ns.load(Relaxed)),
234                min_time: Duration::from_nanos(self.min_time_ns.load(Relaxed)),
235                max_time: Duration::from_nanos(self.max_time_ns.load(Relaxed)),
236            };
237
238            let r = read();
239            if r == read() {
240                // There was no write to the counters in the meantime.
241                break r;
242            }
243
244            std::hint::spin_loop();
245        }
246    }
247}
248
249impl Default for PerfCounter {
250    fn default() -> Self {
251        Self {
252            num_calls: Default::default(),
253            total_time_ns: Default::default(),
254            min_time_ns: AtomicU64::new(u64::MAX),
255            max_time_ns: Default::default(),
256        }
257    }
258}
259
260/// Context manager for a performance counter.
261/// This is used to track when the measured function exits.
262pub struct PerfCounterManager<'a> {
263    /// Instant then the time measurement was started.
264    start_time: std::time::Instant,
265    counter: &'a PerfCounter,
266}
267
268impl<'a> PerfCounterManager<'a> {
269    /// Stop measuring the time and add the duration to the total spent time.
270    fn stop_measurement(self) {
271        let elapsed = self.start_time.elapsed();
272        let elapsed_ns = elapsed.as_nanos() as u64;
273        use std::sync::atomic::Ordering::*;
274        self.counter.total_time_ns.fetch_add(elapsed_ns, Relaxed);
275        self.counter.min_time_ns.fetch_min(elapsed_ns, Relaxed);
276        self.counter.max_time_ns.fetch_max(elapsed_ns, Relaxed);
277        self.counter.num_calls.fetch_add(1, Relaxed);
278    }
279}
280
281impl PerfCounter {
282    /// Start measuring the spent time.
283    /// Must call `stop()` on the return value.
284    #[must_use]
285    fn start_measurement(&self) -> PerfCounterManager {
286        PerfCounterManager {
287            start_time: std::time::Instant::now(),
288            counter: self,
289        }
290    }
291
292    /// Measure the execution time of `f` and add it to the statistics.
293    fn measure<R>(&self, f: impl FnOnce() -> R) -> R {
294        let m = self.start_measurement();
295        let r = f();
296        m.stop_measurement();
297        r
298    }
299}
300
301#[portrait::fill(portrait::delegate(H))]
302impl<H: HierarchyIds> HierarchyIds for DBPerf<H> {}
303
304#[portrait::fill(portrait::delegate(N))]
305impl<N: NetlistIds> NetlistIds for DBPerf<N> {}
306
307// Inherit everything from HierarchyBase.
308impl<H: HierarchyBase> HierarchyBase for DBPerf<H> {
309    type NameType = H::NameType;
310
311    fn cell_by_name(&self, name: &str) -> Option<H::CellId> {
312        self.perf_counters
313            .get(FnName::cell_by_name)
314            .measure(|| self.chip.cell_by_name(name))
315    }
316
317    fn cell_instance_by_name(&self, parent_cell: &H::CellId, name: &str) -> Option<H::CellInstId> {
318        self.perf_counters
319            .get(FnName::cell_instance_by_name)
320            .measure(|| self.chip.cell_instance_by_name(parent_cell, name))
321    }
322
323    fn cell_name(&self, cell: &H::CellId) -> H::NameType {
324        self.perf_counters
325            .get(FnName::cell_name)
326            .measure(|| self.chip.cell_name(cell))
327    }
328
329    fn cell_instance_name(&self, cell_inst: &H::CellInstId) -> Option<H::NameType> {
330        self.perf_counters
331            .get(FnName::cell_instance_name)
332            .measure(|| self.chip.cell_instance_name(cell_inst))
333    }
334
335    fn parent_cell(&self, cell_instance: &H::CellInstId) -> H::CellId {
336        self.perf_counters
337            .get(FnName::parent_cell)
338            .measure(|| self.chip.parent_cell(cell_instance))
339    }
340
341    fn template_cell(&self, cell_instance: &H::CellInstId) -> H::CellId {
342        self.perf_counters
343            .get(FnName::template_cell)
344            .measure(|| self.chip.template_cell(cell_instance))
345    }
346
347    fn for_each_cell<F>(&self, f: F)
348    where
349        F: FnMut(H::CellId),
350    {
351        self.perf_counters
352            .get(FnName::for_each_cell)
353            .measure(|| self.chip.for_each_cell(f))
354    }
355
356    fn each_cell_vec(&self) -> Vec<H::CellId> {
357        self.perf_counters
358            .get(FnName::each_cell_vec)
359            .measure(|| self.chip.each_cell_vec())
360    }
361
362    fn each_cell(&self) -> Box<dyn Iterator<Item = H::CellId> + '_> {
363        self.perf_counters
364            .get(FnName::each_cell)
365            .measure(|| self.chip.each_cell())
366    }
367
368    fn for_each_cell_instance<F>(&self, cell: &H::CellId, f: F)
369    where
370        F: FnMut(H::CellInstId),
371    {
372        self.perf_counters
373            .get(FnName::each_cell_instance)
374            .measure(|| self.chip.for_each_cell_instance(cell, f))
375    }
376
377    fn each_cell_instance_vec(&self, cell: &H::CellId) -> Vec<H::CellInstId> {
378        self.perf_counters
379            .get(FnName::each_cell_instance_vec)
380            .measure(|| self.chip.each_cell_instance_vec(cell))
381    }
382
383    fn each_cell_instance(&self, cell: &H::CellId) -> Box<dyn Iterator<Item = H::CellInstId> + '_> {
384        self.perf_counters
385            .get(FnName::each_cell_instance)
386            .measure(|| self.chip.each_cell_instance(cell))
387    }
388
389    fn for_each_cell_dependency<F>(&self, cell: &H::CellId, f: F)
390    where
391        F: FnMut(H::CellId),
392    {
393        self.perf_counters
394            .get(FnName::for_each_cell_dependency)
395            .measure(|| self.chip.for_each_cell_dependency(cell, f))
396    }
397
398    fn each_cell_dependency_vec(&self, cell: &H::CellId) -> Vec<H::CellId> {
399        self.perf_counters
400            .get(FnName::each_cell_dependency_vec)
401            .measure(|| self.chip.each_cell_dependency_vec(cell))
402    }
403
404    fn each_cell_dependency(&self, cell: &H::CellId) -> Box<dyn Iterator<Item = H::CellId> + '_> {
405        self.perf_counters
406            .get(FnName::each_cell_dependency)
407            .measure(|| self.chip.each_cell_dependency(cell))
408    }
409
410    fn num_cell_dependencies(&self, cell: &H::CellId) -> usize {
411        self.perf_counters
412            .get(FnName::num_cell_dependencies)
413            .measure(|| self.chip.num_cell_dependencies(cell))
414    }
415
416    fn for_each_dependent_cell<F>(&self, cell: &H::CellId, f: F)
417    where
418        F: FnMut(H::CellId),
419    {
420        self.perf_counters
421            .get(FnName::for_each_dependent_cell)
422            .measure(|| self.chip.for_each_dependent_cell(cell, f))
423    }
424
425    fn each_dependent_cell_vec(&self, cell: &H::CellId) -> Vec<H::CellId> {
426        self.perf_counters
427            .get(FnName::each_dependent_cell_vec)
428            .measure(|| self.chip.each_dependent_cell_vec(cell))
429    }
430
431    fn each_dependent_cell(&self, cell: &H::CellId) -> Box<dyn Iterator<Item = H::CellId> + '_> {
432        self.perf_counters
433            .get(FnName::each_dependent_cell)
434            .measure(|| self.chip.each_dependent_cell(cell))
435    }
436
437    fn num_dependent_cells(&self, cell: &H::CellId) -> usize {
438        self.perf_counters
439            .get(FnName::num_dependent_cells)
440            .measure(|| self.chip.num_dependent_cells(cell))
441    }
442
443    fn for_each_cell_reference<F>(&self, cell: &H::CellId, f: F)
444    where
445        F: FnMut(H::CellInstId),
446    {
447        self.perf_counters
448            .get(FnName::for_each_cell_reference)
449            .measure(|| self.chip.for_each_cell_reference(cell, f))
450    }
451
452    fn each_cell_reference_vec(&self, cell: &H::CellId) -> Vec<H::CellInstId> {
453        self.perf_counters
454            .get(FnName::each_cell_reference_vec)
455            .measure(|| self.chip.each_cell_reference_vec(cell))
456    }
457
458    fn each_cell_reference(
459        &self,
460        cell: &H::CellId,
461    ) -> Box<dyn Iterator<Item = H::CellInstId> + '_> {
462        self.perf_counters
463            .get(FnName::each_cell_reference)
464            .measure(|| self.chip.each_cell_reference(cell))
465    }
466
467    fn num_cell_references(&self, cell: &H::CellId) -> usize {
468        self.perf_counters
469            .get(FnName::num_cell_references)
470            .measure(|| self.chip.num_cell_references(cell))
471    }
472
473    fn num_child_instances(&self, cell: &H::CellId) -> usize {
474        self.perf_counters
475            .get(FnName::num_child_instances)
476            .measure(|| self.chip.num_child_instances(cell))
477    }
478
479    fn num_cells(&self) -> usize {
480        self.perf_counters
481            .get(FnName::num_cells)
482            .measure(|| self.chip.num_cells())
483    }
484
485    fn get_chip_property(&self, key: &H::NameType) -> Option<PropertyValue> {
486        self.perf_counters
487            .get(FnName::get_chip_property)
488            .measure(|| self.chip.get_chip_property(key))
489    }
490
491    fn get_cell_property(&self, cell: &H::CellId, key: &H::NameType) -> Option<PropertyValue> {
492        self.perf_counters
493            .get(FnName::get_cell_property)
494            .measure(|| self.chip.get_cell_property(cell, key))
495    }
496
497    fn get_cell_instance_property(
498        &self,
499        inst: &H::CellInstId,
500        key: &H::NameType,
501    ) -> Option<PropertyValue> {
502        self.perf_counters
503            .get(FnName::get_cell_instance_property)
504            .measure(|| self.chip.get_cell_instance_property(inst, key))
505    }
506}
507
508// Inherit everything from LayoutBase.
509#[portrait::fill(portrait::delegate(L))]
510impl<L: LayoutIds> LayoutIds for DBPerf<L> {}
511
512// Inherit everything from LayoutBase.
513#[portrait::fill(portrait::delegate(L; self.chip))]
514impl<L: LayoutBase> LayoutBase for DBPerf<L> {}
515
516// Inherit everything from NetlistBase.
517#[portrait::fill(portrait::delegate(N; self.chip))]
518impl<N: NetlistBase> NetlistBase for DBPerf<N> {}
519
520// Inherit everything from HierarchyEdit.
521impl<H: HierarchyEdit> HierarchyEdit for DBPerf<H> {
522    fn create_cell(&mut self, name: H::NameType) -> H::CellId {
523        self.perf_counters
524            .get(FnName::create_cell)
525            .measure(|| self.chip.create_cell(name))
526    }
527
528    fn remove_cell(&mut self, cell_id: &H::CellId) {
529        self.perf_counters
530            .get(FnName::remove_cell)
531            .measure(|| self.chip.remove_cell(cell_id))
532    }
533
534    fn create_cell_instance(
535        &mut self,
536        parent_cell: &H::CellId,
537        template_cell: &H::CellId,
538        name: Option<H::NameType>,
539    ) -> H::CellInstId {
540        self.perf_counters
541            .get(FnName::create_cell_instance)
542            .measure(|| {
543                self.chip
544                    .create_cell_instance(parent_cell, template_cell, name)
545            })
546    }
547
548    fn remove_cell_instance(&mut self, inst: &H::CellInstId) {
549        self.perf_counters
550            .get(FnName::remove_cell_instance)
551            .measure(|| self.chip.remove_cell_instance(inst))
552    }
553
554    fn rename_cell_instance(&mut self, inst: &H::CellInstId, new_name: Option<H::NameType>) {
555        self.perf_counters
556            .get(FnName::rename_cell_instance)
557            .measure(|| self.chip.rename_cell_instance(inst, new_name))
558    }
559
560    fn rename_cell(&mut self, cell: &H::CellId, new_name: H::NameType) {
561        self.perf_counters
562            .get(FnName::rename_cell)
563            .measure(|| self.chip.rename_cell(cell, new_name))
564    }
565
566    fn set_chip_property(&mut self, key: H::NameType, value: PropertyValue) {
567        self.perf_counters
568            .get(FnName::set_chip_property)
569            .measure(|| self.chip.set_chip_property(key, value))
570    }
571
572    fn set_cell_property(&mut self, cell: &H::CellId, key: H::NameType, value: PropertyValue) {
573        self.perf_counters
574            .get(FnName::set_cell_property)
575            .measure(|| self.chip.set_cell_property(cell, key, value))
576    }
577
578    fn set_cell_instance_property(
579        &mut self,
580        inst: &H::CellInstId,
581        key: H::NameType,
582        value: PropertyValue,
583    ) {
584        self.perf_counters
585            .get(FnName::set_cell_instance_property)
586            .measure(|| self.chip.set_cell_instance_property(inst, key, value))
587    }
588}
589
590// Inherit everything from LayoutEdit.
591impl<L: LayoutEdit> LayoutEdit for DBPerf<L> {
592    fn insert_shape(
593        &mut self,
594        parent_cell: &L::CellId,
595        layer: &L::LayerId,
596        geometry: Geometry<L::Coord>,
597    ) -> L::ShapeId {
598        self.perf_counters
599            .get(FnName::insert_shape)
600            .measure(|| self.chip.insert_shape(parent_cell, layer, geometry))
601    }
602
603    fn set_dbu(&mut self, dbu: L::Coord) {
604        self.perf_counters
605            .get(FnName::set_dbu)
606            .measure(|| self.chip.set_dbu(dbu))
607    }
608
609    fn create_layer(&mut self, index: UInt, datatype: UInt) -> L::LayerId {
610        self.perf_counters
611            .get(FnName::create_layer)
612            .measure(|| self.chip.create_layer(index, datatype))
613    }
614
615    fn create_layer_with_id(
616        &mut self,
617        layer_id: L::LayerId,
618        index: UInt,
619        datatype: UInt,
620    ) -> Result<(), ()> {
621        self.perf_counters
622            .get(FnName::create_layer_with_id)
623            .measure(|| self.chip.create_layer_with_id(layer_id, index, datatype))
624    }
625
626    fn set_layer_name(
627        &mut self,
628        layer: &L::LayerId,
629        name: Option<L::NameType>,
630    ) -> Option<L::NameType> {
631        self.perf_counters
632            .get(FnName::set_layer_name)
633            .measure(|| self.chip.set_layer_name(layer, name))
634    }
635
636    fn remove_shape(&mut self, shape_id: &L::ShapeId) -> Option<Geometry<L::Coord>> {
637        self.perf_counters
638            .get(FnName::remove_shape)
639            .measure(|| self.chip.remove_shape(shape_id))
640    }
641
642    fn replace_shape(
643        &mut self,
644        shape_id: &L::ShapeId,
645        geometry: Geometry<L::Coord>,
646    ) -> Geometry<L::Coord> {
647        self.perf_counters
648            .get(FnName::replace_shape)
649            .measure(|| self.chip.replace_shape(shape_id, geometry))
650    }
651
652    fn set_transform(&mut self, cell_inst: &L::CellInstId, tf: SimpleTransform<L::Coord>) {
653        self.perf_counters
654            .get(FnName::set_transform)
655            .measure(|| self.chip.set_transform(cell_inst, tf))
656    }
657
658    fn set_shape_property(&mut self, shape: &L::ShapeId, key: L::NameType, value: PropertyValue) {
659        self.perf_counters
660            .get(FnName::set_shape_property)
661            .measure(|| self.chip.set_shape_property(shape, key, value))
662    }
663}
664
665impl<N: NetlistEdit> NetlistEdit for DBPerf<N> {
666    fn create_pin(
667        &mut self,
668        cell: &Self::CellId,
669        name: Self::NameType,
670        direction: Direction,
671    ) -> Self::PinId {
672        self.perf_counters
673            .get(FnName::create_pin)
674            .measure(|| self.chip.create_pin(cell, name, direction))
675    }
676
677    fn remove_pin(&mut self, id: &Self::PinId) {
678        self.perf_counters
679            .get(FnName::remove_pin)
680            .measure(|| self.chip.remove_pin(id))
681    }
682
683    fn rename_pin(&mut self, pin: &Self::PinId, new_name: Self::NameType) -> Self::NameType {
684        self.perf_counters
685            .get(FnName::rename_pin)
686            .measure(|| self.chip.rename_pin(pin, new_name))
687    }
688
689    fn create_net(&mut self, parent: &Self::CellId, name: Option<Self::NameType>) -> Self::NetId {
690        self.perf_counters
691            .get(FnName::create_net)
692            .measure(|| self.chip.create_net(parent, name))
693    }
694
695    fn rename_net(
696        &mut self,
697        net_id: &Self::NetId,
698        new_name: Option<Self::NameType>,
699    ) -> Option<Self::NameType> {
700        self.perf_counters
701            .get(FnName::rename_net)
702            .measure(|| self.chip.rename_net(net_id, new_name))
703    }
704
705    fn remove_net(&mut self, net: &Self::NetId) {
706        self.perf_counters
707            .get(FnName::remove_net)
708            .measure(|| self.chip.remove_net(net))
709    }
710
711    fn connect_pin(&mut self, pin: &Self::PinId, net: Option<Self::NetId>) -> Option<Self::NetId> {
712        self.perf_counters
713            .get(FnName::connect_pin)
714            .measure(|| self.chip.connect_pin(pin, net))
715    }
716
717    fn connect_pin_instance(
718        &mut self,
719        pin: &Self::PinInstId,
720        net: Option<Self::NetId>,
721    ) -> Option<Self::NetId> {
722        self.perf_counters
723            .get(FnName::connect_pin_instance)
724            .measure(|| self.chip.connect_pin_instance(pin, net))
725    }
726
727    fn disconnect_pin(&mut self, pin: &Self::PinId) -> Option<Self::NetId> {
728        self.perf_counters
729            .get(FnName::disconnect_pin)
730            .measure(|| self.chip.disconnect_pin(pin))
731    }
732
733    fn disconnect_pin_instance(&mut self, pin_instance: &Self::PinInstId) -> Option<Self::NetId> {
734        self.perf_counters
735            .get(FnName::disconnect_pin_instance)
736            .measure(|| self.chip.disconnect_pin_instance(pin_instance))
737    }
738}
739
740impl<L: L2NBase> L2NBase for DBPerf<L> {
741    fn shapes_of_net(&self, net_id: &Self::NetId) -> Box<dyn Iterator<Item = Self::ShapeId> + '_> {
742        self.perf_counters
743            .get(FnName::shapes_of_net)
744            .measure(|| self.chip.shapes_of_net(net_id))
745    }
746
747    fn shapes_of_pin(&self, pin_id: &Self::PinId) -> Box<dyn Iterator<Item = Self::ShapeId> + '_> {
748        self.perf_counters
749            .get(FnName::shapes_of_pin)
750            .measure(|| self.chip.shapes_of_pin(pin_id))
751    }
752
753    fn get_net_of_shape(&self, shape_id: &Self::ShapeId) -> Option<Self::NetId> {
754        self.perf_counters
755            .get(FnName::get_net_of_shape)
756            .measure(|| self.chip.get_net_of_shape(shape_id))
757    }
758
759    fn get_pin_of_shape(&self, shape_id: &Self::ShapeId) -> Option<Self::PinId> {
760        self.perf_counters
761            .get(FnName::get_pin_of_shape)
762            .measure(|| self.chip.get_pin_of_shape(shape_id))
763    }
764}
765
766impl<L: L2NEdit> L2NEdit for DBPerf<L> {
767    fn set_pin_of_shape(
768        &mut self,
769        shape_id: &Self::ShapeId,
770        pin: Option<Self::PinId>,
771    ) -> Option<Self::PinId> {
772        self.perf_counters
773            .get(FnName::set_pin_of_shape)
774            .measure(|| self.chip.set_pin_of_shape(shape_id, pin))
775    }
776
777    fn set_net_of_shape(
778        &mut self,
779        shape_id: &Self::ShapeId,
780        net: Option<Self::NetId>,
781    ) -> Option<Self::NetId> {
782        self.perf_counters
783            .get(FnName::set_net_of_shape)
784            .measure(|| self.chip.set_net_of_shape(shape_id, net))
785    }
786}
787
788#[test]
789fn test_dbperf() {
790    use crate::chip::Chip;
791    let mut chip = Chip::new();
792    let mut chip_perf = DBPerf::new(&mut chip);
793
794    let _cell = chip_perf.create_cell("A".into());
795    let _cell = chip_perf.create_cell("B".into());
796    let _cell = chip_perf.create_cell("C".into());
797
798    // Read performance stats of the 'create_cell' function.
799    let create_cell_perf = chip_perf.get_stats(FnName::create_cell);
800    dbg!(create_cell_perf);
801
802    assert_eq!(create_cell_perf.num_calls, 3);
803    assert!(!create_cell_perf.total_time.is_zero());
804    assert!(create_cell_perf.min_time <= create_cell_perf.max_time);
805    assert!(create_cell_perf.min_time <= create_cell_perf.avg_time().unwrap());
806    assert!(create_cell_perf.avg_time().unwrap() <= create_cell_perf.max_time);
807}