202 research outputs found

    A model-based design flow for embedded vision applications on heterogeneous architectures

    Get PDF
    The ability to gather information from images is straightforward to human, and one of the principal input to understand external world. Computer vision (CV) is the process to extract such knowledge from the visual domain in an algorithmic fashion. The requested computational power to process these information is very high. Until recently, the only feasible way to meet non-functional requirements like performance was to develop custom hardware, which is costly, time-consuming and can not be reused in a general purpose. The recent introduction of low-power and low-cost heterogeneous embedded boards, in which CPUs are combine with heterogeneous accelerators like GPUs, DSPs and FPGAs, can combine the hardware efficiency needed for non-functional requirements with the flexibility of software development. Embedded vision is the term used to identify the application of the aforementioned CV algorithms applied in the embedded field, which usually requires to satisfy, other than functional requirements, also non-functional requirements such as real-time performance, power, and energy efficiency. Rapid prototyping, early algorithm parametrization, testing, and validation of complex embedded video applications for such heterogeneous architectures is a very challenging task. This thesis presents a comprehensive framework that: 1) Is based on a model-based paradigm. Differently from the standard approaches at the state of the art that require designers to manually model the algorithm in any programming language, the proposed approach allows for a rapid prototyping, algorithm validation and parametrization in a model-based design environment (i.e., Matlab/Simulink). The framework relies on a multi-level design and verification flow by which the high-level model is then semi-automatically refined towards the final automatic synthesis into the target hardware device. 2) Relies on a polyglot parallel programming model. The proposed model combines different programming languages and environments such as C/C++, OpenMP, PThreads, OpenVX, OpenCV, and CUDA to best exploit different levels of parallelism while guaranteeing a semi-automatic customization. 3) Optimizes the application performance and energy efficiency through a novel algorithm for the mapping and scheduling of the application 3 tasks on the heterogeneous computing elements of the device. Such an algorithm, called exclusive earliest finish time (XEFT), takes into consideration the possible multiple implementation of tasks for different computing elements (e.g., a task primitive for CPU and an equivalent parallel implementation for GPU). It introduces and takes advantage of the notion of exclusive overlap between primitives to improve the load balancing. This thesis is the result of three years of research activity, during which all the incremental steps made to compose the framework have been tested on real case studie

    On the Task Mapping and Scheduling for DAG-based Embedded Vision Applications on Heterogeneous Multi/Many-core Architectures

    Get PDF
    Embedded vision applications have stringent performance constraints that must be satisfied when they are run on low-power embedded systems. OpenVX has emerged as the de-facto reference standard to develop such applications. Starting with a DAG representation of the application and by relying on a primitive-based programming model, it allows for automatic system-level optimizations and synthesis of an implementation onto the target heterogeneous multi-core architecture. However, the state-of-the-art algorithm for task mapping and scheduling in OpenVX does not provide the performance necessary for such applications when deployed on embedded multi-/many-core architectures. %does not implement an efficient algorithm task mapping and scheduling onto embedded multi/many-core architectures. Our work addresses this challenge by making the following three contributions. First, we implemented a static task scheduling and mapping approach for OpenVX using the heterogeneous earliest finish time (HEFT) heuristic. We show that HEFT allows us to improve the system performance up to 70% on one of the most widespread embedded vision systems (i.e., NVIDIA VisionWorks on NVIDIA Jetson TX2). Second, we show that HEFT, in the context of an embedded vision application where some primitives may have multiple implementations (e.g., for CPU and for GPU), can lead to an imbalance in load amongst heterogeneous computing elements (CEs); thereby, suffering from degraded performance. Third, we propose an algorithm called exclusive earliest finish time (XEFT) that introduces the notion of exclusive overlap between single implementation primitives to improve the load balancing. We show that XEFT can further improve the system performance up to 33% over HEFT, and 82% over OpenVX. We present the results on different benchmarks, including a real-world localization and mapping application (ORB-SLAM) combined with the NVIDIA image recognition application based on deep-learning

    Geometry-Oblivious FMM for Compressing Dense SPD Matrices

    Full text link
    We present GOFMM (geometry-oblivious FMM), a novel method that creates a hierarchical low-rank approximation, "compression," of an arbitrary dense symmetric positive definite (SPD) matrix. For many applications, GOFMM enables an approximate matrix-vector multiplication in Nlog⁥NN \log N or even NN time, where NN is the matrix size. Compression requires Nlog⁥NN \log N storage and work. In general, our scheme belongs to the family of hierarchical matrix approximation methods. In particular, it generalizes the fast multipole method (FMM) to a purely algebraic setting by only requiring the ability to sample matrix entries. Neither geometric information (i.e., point coordinates) nor knowledge of how the matrix entries have been generated is required, thus the term "geometry-oblivious." Also, we introduce a shared-memory parallel scheme for hierarchical matrix computations that reduces synchronization barriers. We present results on the Intel Knights Landing and Haswell architectures, and on the NVIDIA Pascal architecture for a variety of matrices.Comment: 13 pages, accepted by SC'1

    A (ir)regularity-aware task scheduler for heterogeneous platforms

    Get PDF
    This paper addresses the design, implementation and validation of an e ective scheduling scheme for both regular and irregular applications on heterogeneous platforms. The scheduler uses an empirical performance model to dynamically schedule the workload, organized into a given number of chunks, and follows the Heterogeneous Earliest Finish Time (HEFT) scheduling algorithm, which ranks the tasks based on both their computation and communication costs. The evaluation of the proposed approach is based on three case studies { the SAXPY, the FFT and the Barnes-Hut algorithms { two regular and one irregular application. The scheduler was evaluated on a heterogeneous platform with one quad-core CPU-chip accelerated by one or two GPU devices, embedded in the GAMA framework. The evaluation runs measured the e ectiveness, the e ciency and the scalability of the proposed method. Results show that the proposed model was e active in addressing both regular and irregular applications, on heterogeneous platforms, while achieving ideal ( 100%) levels of e ciency in the irregular Barnes-Hut algorithm.Fundação para a CiĂȘncia e Tecnologi

    Proactive Adaptation in Self-Organizing Task-based Runtime Systems for Different Computing Classes

    Get PDF
    Moderne Computersysteme bieten Anwendern und Anwendungsentwicklern ein hohes Maß an ParallelitĂ€t und HeterogenitĂ€t. Die effiziente Nutzung dieser Systeme erfordert jedoch tiefgreifende Kenntnisse, z.B. der darunterliegenden Hardware-Plattform und den notwendigen Programmiermodellen, und umfangreiche Arbeit des Entwicklers. In dieser Thesis bezieht sich die effiziente Nutzung auf die GesamtausfĂŒhrungszeit der Anwendungen, den Energieverbrauch des Systems, die maximale Temperatur der Verarbeitungseinheiten und die ZuverlĂ€ssigkeit des Systems. Neben den verschiedenen Optimierungszielen muss ein Anwendungsentwickler auch die spezifischen EinschrĂ€nkungen und Randbedingungen des Systems berĂŒcksichtigen, wie z. B. Deadlines oder Sicherheitsgarantien, die mit bestimmten Anwendungsbereichen einhergehen. Diese KomplexitĂ€t heterogener Systeme macht es unmöglich, alle potenziellen SystemzustĂ€nde und UmwelteinflĂŒsse, die zur Laufzeit auftreten können, vorherzusagen. Die System- und Anwendungsentwickler sind somit nicht in der Lage, zur Entwurfszeit festzulegen, wie das System und die Anwendungen in allen möglichen Situationen reagieren sollen. Daher ist es notwendig, die Systeme zur Laufzeit der aktuellen Situation anzupassen, um ihr Verhalten entsprechend zu optimieren. In eingebetteten Systemen mit begrenzten KĂŒhlkapazitĂ€ten muss z.B. bei Erreichen einer bestimmten Temperaturschwelle eine Lastverteilung vorgenommen, die Frequenz verringert oder Verarbeitungseinheiten abgeschaltet werden, um die WĂ€rmeentwicklung zu reduzieren. Normalerweise reicht es aber nicht aus, einfach nur auf einen ungĂŒnstigen Systemzustand zu reagieren. Das Ziel sollte darin bestehen, ungĂŒnstige oder fehlerhafte SystemzustĂ€nde vor dem Auftreten zu vermeiden, um die Notwendigkeit des Aufrufs von Notfallfunktionen zu verringern und die Benutzerfreundlichkeit zu verbessern. Anstatt beispielsweise die WĂ€rmeentwicklung durch eine Neuverteilung der Anwendungen zu reduzieren, könnten proaktive Mechanismen kritische Temperaturen bereits im Vorfeld vermeiden, indem sie bestimmte unkritische Aufgaben verzögern oder deren Genauigkeit oder QoS verringern. Auf diese Weise wird die Systemlast reduziert, bevor ein kritischer Punkt erreicht wird. Lösungen des aktuellen Stands der Technik wie einheitliche Programmiersprachen oder Laufzeitsysteme adressieren einige der oben genannten Herausforderungen, jedoch existiert kein Ansatz, der in der Lage ist, eine Optimierung mehrerer sich widersprechender Zielfunktionen dynamisch und vor allem proaktiv durchzufĂŒhren. Ein Konzept, das diese komplexe Aufgabe fĂŒr den Entwickler ĂŒbernimmt und eine Möglichkeit zur dynamischen und proaktiven Anpassung an VerĂ€nderungen bietet, ist die Selbstorganisation. Selbstorganisation ist jedoch definiert als ein Prozess ohne externe Kontrolle oder Steuerung. Im Kontext der Systemoptimierung kann dies leicht zu unerwĂŒnschten Ergebnissen fĂŒhren. Ein Ansatz, der Selbstorganisation mit einem Kontrollmechanismus kombiniert, welcher auf Robustheit und WiderstandsfĂ€higkeit gegenĂŒber Ă€ußeren Störungen abzielt, ist Organic Computing. Das bestimmende Merkmal von Organic Computing ist eine Observer/Controller-Architektur. Das Konzept dieser Architektur besteht darin, den aktuellen Zustand des Systems und der Umgebung zu ĂŒberwachen, diese Daten zu analysieren und auf der Grundlage dieser Analyse Entscheidungen ĂŒber das zukĂŒnftige Systemverhalten zu treffen. Organic Computing ermöglicht es also auf der Grundlage der vergangenen und des aktuellen Zustands proaktiv Mechanismen auszuwĂ€hlen und auszulösen, die das System optimieren und unerwĂŒnschte ZustĂ€nde vermeiden. Um die Vorteile des Organic Computings auf moderne heterogene Systeme zu ĂŒbertragen, kombiniere ich den Organic Computing-Ansatz mit einem Laufzeitsystem. Laufzeitsysteme sind ein vielversprechender Kandidat fĂŒr die Umsetzung des Organic Computing-Ansatzes, da sie bereits die AusfĂŒhrung von Anwendungen ĂŒberwachen und steuern. Insbesondere betrachte und bearbeite ich in dieser Dissertation die folgenden Forschungsthemen, indem ich die Konzepte des Organic Computings und der Laufzeitsysteme kombiniere: ‱ Erfassen des aktuellen Systemzustands durch Überwachung von Sensoren und Performance Countern ‱ Vorhersage zukĂŒnftiger SystemzustĂ€nde durch Analyse des vergangenen Verhaltens ‱ Nutzung von Zustandsinformationen zur proaktiven Anpassung des Systems Ich erweitere das Thema der Erfassung von SystemzustĂ€nden auf zwei Arten. ZunĂ€chst fĂŒhre ich eine neuartige heuristische Metrik zur Berechnung der ZuverlĂ€ssigkeit einer Verarbeitungseinheit ein, die auf symptombasierter Fehlererkennung basiert. Symptombasierte Fehlererkennung ist eine leichtgewichtige Methode zur dynamischen Erkennung von soften Hardware-Fehlern durch Überwachung des AusfĂŒhrungsverhaltens mit Performance Countern. Die dynamische Erkennung von Fehlern ermöglicht dann die Berechnung einer heuristischen Fehlerrate einer Verarbeitungseinheit in einem bestimmten Zeitfenster. Die Fehlerrate wird verwendet, um die Anzahl der erforderlichen AusfĂŒhrungen einer Anwendung zu berechnen, um eine bestimmte ErgebniszuverlĂ€ssigkeit, also eine Mindestwahrscheinlichkeit fĂŒr ein korrektes Ergebnis, zu gewĂ€hrleisten. Ein wichtiger Aspekt der Zustandserfassung ist die Minimierung des entstehenden Overheads. Ich verringere die Anzahl der fĂŒr OpenMP-Tasks notwendigen Profiling-DurchlĂ€ufe durch Thread-Interpolation und ÜberprĂŒfungen des Skalierungsverhaltens. ZusĂ€tzlich untersuche ich die Vorhersage von OpenCL Task-AusfĂŒhrungszeiten. Die PrĂ€diktoren der AusfĂŒhrungszeiten werden mit verschiedenen maschinellen Lernalgorithmen trainiert. Als Input werden Profile der Kernel verwendet, die durch statische Codeanalyse erstellt wurden. Um in dieser Dissertation zukĂŒnftige SystemzustĂ€nde vorherzusagen, sollen Anwendungen vorausgesagt werden, die in naher Zukunft im System vorkommen werden. In Kombination mit der AusfĂŒhrungsdatenbank ermöglicht dies die SchĂ€tzung der anstehenden Kosten, die das System zu bewĂ€ltigen hat. In dieser Arbeit werden zwei Mechanismen zur Vorhersage von Anwendungen/Tasks entwickelt. Der erste PrĂ€diktor zielt darauf ab, neue Instanzen unabhĂ€ngiger Tasks vorherzusagen. Der zweite Mechanismus betrachtet AusfĂŒhrungsmuster abhĂ€ngiger Anwendungen und sagt auf dieser Grundlage zukĂŒnftig auftretende Anwendungen vorher. Beide Mechanismen verwenden eine Vorhersagetabelle, die auf Markov-PrĂ€diktoren und dem Abgleich von Mustern basiert. In dieser Arbeit wird das Wissen, das durch die SystemĂŒberwachung und die Vorhersage zukĂŒnftiger Anwendungen gewonnen wird, verwendet, um die Optimierungsziele des Systems proaktiv in Einklang zu bringen und zu gewichten. Dies geschieht durch eine Reihe von Regeln, die eine Systemzustandsbeschreibung, bestehend aus dem aktuellen Zustand, Vorhersagen und Randbedingungen bzw. BeschrĂ€nkungen, auf einen Vektor aus Gewichten abbilden. Zum Erlernen der Regelmenge wird ein Extended Classifer System (XCS) eingesetzt. Das XCS ist in eine hierarchische Architektur eingebettet, die nach den Prinzipien des Organic Computing entworfen wurde. Eine wichtige Designentscheidung ist dabei die Auslagerung der Erstellung neuer Regeln an einen Offline-Algorithmus, der einen Simulator nutzt und parallel zum normalen Systemablauf ausgefĂŒhrt wird. Dadurch wird sichergestellt, dass keine ungetesteten Regeln, deren Auswirkungen noch nicht bekannt sind, dem laufenden System hinzugefĂŒgt werden. Die sich daraus ergebenden Gewichte werden schließlich verwendet, um eine Bewertungsfunktion fĂŒr List Scheduling-Algorithmen zu erstellen. Diese Dissertation erweitert das Forschungsgebiet der Scheduling-Algorithmen durch zwei Mechanismen fĂŒr dynamisches Scheduling. Die erste Erweiterung konzentriert sich auf nicht sicherheitskritische Systeme, die PrioritĂ€ten verwenden, um die unterschiedliche Wichtigkeit von Tasks auszudrĂŒcken. Da statische PrioritĂ€ten in stark ausgelasteten Systemen zu Starvation fĂŒhren können, habe ich einen dynamischen Ageing-Mechanismus entwickelt, der dazu in der Lage ist, die PrioritĂ€ten der Tasks entsprechend der aktuellen Auslastung und ihrer Wartezeiten anzupassen. Dadurch reduziert der Mechanismus die Gesamtlaufzeit ĂŒber alle Tasks und die Wartezeit fĂŒr Tasks mit niedrigerer PrioritĂ€t. Noch ist eine große Anzahl von Anwendungen nicht dazu bereit, den hohen Grad an ParallelitĂ€t zu nutzen, den moderne Computersysteme bieten. Ein Konzept, das versucht dieses Problem zu lösen, indem es mehrere verschiedene Prozesse auf demselben Rechenknoten zur AusfĂŒhrung bringt, ist das Co-Scheduling. In dieser Dissertation stelle ich einen neuartigen Co-Scheduling-Mechanismus vor, welcher die Task-Schedules mehrerer Laufzeitsysteminstanzen optimiert, die auf demselben Rechenknoten ausgefĂŒhrt werden. Um die notwendigen Informationen zwischen den Laufzeitsysteminstanzen zu teilen, speichert der Mechanismus die Daten in Shared Memory. Sobald ein Laufzeitsystem neue Tasks in das System einfĂŒgt, prĂŒft der Mechanismus, ob die Berechnung eines neuen Schedules sinnvoll ist. Wird die Entscheidung getroffen, einen neuen Schedule zu berechnen, setzt der Mechanismus Simulated Annealing ein, um alle Tasks, die bisher noch nicht mit ihrer AusfĂŒhrung begonnen haben, neu auf AusfĂŒhrungseinheiten abzubilden. Zusammenfassend lĂ€sst sich sagen, dass diese Arbeit neuartige Mechanismen und Algorithmen sowie Erweiterungen zu verschiedenen Forschungsgebieten anbietet, um ein proaktives selbst-organisierendes System zu implementieren, das sich an neue und unbekannte Situationen anpassen kann. Dabei wird die KomplexitĂ€t fĂŒr Benutzer und Anwendungsentwickler reduziert, indem die Entscheidungsfindung in das System selbst ausgelagert wird. Gleichzeitig sorgt dieser Ansatz fĂŒr eine effiziente Nutzung der Ressourcen des Systems. Insgesamt leistet diese Arbeit die folgenden BeitrĂ€ge zur Erweiterung des Stands der Forschung: ‱ EinfĂŒhrung einer neuartigen heuristischen Metrik zur Messung der ZuverlĂ€ssigkeit von Verarbeitungseinheiten. Die Metrik basiert auf einer leichtgewichtigen Methode zur Fehlererkennung, genannt symptombasierte Fehlererkennung. Mit der symptombasierten Fehlererkennung ist es möglich, mehrere injizierte Fehlerklassen und Interferenzen, die Soft-Hardware-Fehler simulieren, sowohl auf einer CPU als auch auf einer GPU zuverlĂ€ssig zu erkennen. DarĂŒber hinaus werden diese Ergebnisse durch Welch\u27s t-Test statistisch bestĂ€tigt. ‱ Vorschlag eines Vorhersagemodells fĂŒr die AusfĂŒhrungszeit von OpenCL Kerneln, das auf statischer Code-Analyse basiert. Das Modell ist in der Lage, die schnellste Verarbeitungseinheit aus einer Menge von Verarbeitungseinheiten mit einer Genauigkeit von im schlechtesten Fall 69 %69\,\% auszuwĂ€hlen. Zum Vergleich: eine Referenzvariante, welche immer den Prozessor vorhersagt, der die meisten Kernel am schnellsten ausfĂŒhrt, erzielt eine Genauigkeit von 25 %25\,\%. Im besten Fall erreicht das Modell eine Genauigkeit von bis zu 83 %83\,\%. ‱ Bereitstellung von zwei PrĂ€diktoren fĂŒr kommende Tasks/Anwendungen. Der erste Mechanismus betrachtet unabhĂ€ngige Tasks, die stĂ€ndig neue Task-Instanzen erstellen, der zweite abhĂ€ngige Anwendungen, die AusfĂŒhrungsmuster bilden. Dabei erzielt der erste Mechanismus bei der Vorhersage der Zeitspanne zwischen zwei aufeinanderfolgenden Task-Instanzen einen maximalen\\ sMAPEsMAPE-Wert von 4,33 %4,33\,\% fĂŒr sporadische und 0,002 %0,002 \,\% fĂŒr periodische Tasks. DarĂŒber hinaus werden Tasks mit einem aperiodischen AusfĂŒhrungsschema zuverlĂ€ssig erkannt. Der zweite Mechanismus erreicht eine Genauigkeit von 77,6 %77,6 \,\% fĂŒr die Vorhersage der nĂ€chsten anstehenden Anwendung und deren Startzeit. ‱ EinfĂŒhrung einer Umsetzung eines hierarchischen Organic Computing Frameworks mit dem Anwendungsgebiet Task-Scheduling. Dieses Framework enthĂ€lt u.a. ein modifiziertes XCS, fĂŒr dessen Design und Implementierung ein neuartiger Reward-Mechanismus entwickelt wird. Der Mechanismus bedient sich dabei eines speziell fĂŒr diesen Zweck entwickelten Simulators zur Berechnung von Task-AusfĂŒhrungskosten. Das XCS bildet Beschreibungen des Systemzustands auf Gewichte zur Balancierung der Optimierungsziele des Systems ab. Diese Gewichte werden in einer Bewertungsfunktion fĂŒr List Scheduling-Algorithmen verwendet. Damit wird in einem Evaluationsszenario, welches aus einem fĂŒnfmal wiederholten Muster aus Anwendungen besteht, eine Reduzierung der Gesamtlaufzeit um 10,4 %10,4\,\% bzw. 26,7 s26,7\,s, des Energieverbrauchs um 4,7 %4,7\,\% bzw. 2061,1 J2061,1\,J und der maximalen Temperatur der GPU um 3,6 %3,6\,\% bzw. 2,7K2,7 K erzielt. Lediglich die maximale Temperatur ĂŒber alle CPU-Kerne erhöht sich um 6 %6\,\% bzw. 2,3 K2,3\,K. ‱ Entwicklung von zwei Erweiterungen zur Verbesserung des dynamischen Task-Schedulings fĂŒr einzelne und mehrere Prozesse, z.B. mehrere Laufzeitsysteminstanzen. Der erste Mechanismus, ein Ageing-Algorithmus, betrachtet nicht sicherheitskritische Systeme, welche Task-PrioritĂ€ten verwenden, um die unterschiedliche Bedeutung von Anwendungen darzustellen. Da es in solchen Anwendungsszenarien in Kombination mit hoher Systemauslastung zu Starvation kommen kann, passt der Mechanismus die Task-PrioritĂ€ten dynamisch an die aktuelle Auslastung und die Task-Wartezeiten an. Insgesamt erreicht dieser Mechanismus in zwei Bewertungsszenarien eine durchschnittliche Laufzeitverbesserung von 3,75 %3,75\,\% und 3,16 %3,16\,\% bei gleichzeitiger Reduzierung der Durchlaufzeit von Tasks mit niedrigerer PrioritĂ€t um bis zu 25,67 %25,67\,\%. Der zweite Mechanismus ermöglicht die Optimierung von Schedules mehrerer Laufzeitsysteminstanzen, die parallel auf demselben Rechenknoten ausgefĂŒhrt werden. Dieser Co-Scheduling-Ansatz verwendet Shared Memory zum Austausch von Informationen zwischen den Prozessen und Simulated Annealing zur Berechnung neuer Task-Schedules. In zwei Evaluierungsszenarien erzielt der Mechanismus durchschnittliche Laufzeitverbesserungen von 19,74 %19,74\,\% und 20,91 %20,91\,\% bzw. etwa 2,7 s2,7\,s und 3 s3\,s

    DiviML: A Module-based Heuristic for Mapping Neural Networks onto Heterogeneous Platforms

    Full text link
    Datacenters are increasingly becoming heterogeneous, and are starting to include specialized hardware for networking, video processing, and especially deep learning. To leverage the heterogeneous compute capability of modern datacenters, we develop an approach for compiler-level partitioning of deep neural networks (DNNs) onto multiple interconnected hardware devices. We present a general framework for heterogeneous DNN compilation, offering automatic partitioning and device mapping. Our scheduler integrates both an exact solver, through a mixed integer linear programming (MILP) formulation, and a modularity-based heuristic for scalability. Furthermore, we propose a theoretical lower bound formula for the optimal solution, which enables the assessment of the heuristic solutions' quality. We evaluate our scheduler in optimizing both conventional DNNs and randomly-wired neural networks, subject to latency and throughput constraints, on a heterogeneous system comprised of a CPU and two distinct GPUs. Compared to na\"ively running DNNs on the fastest GPU, he proposed framework can achieve more than 3×\times times lower latency and up to 2.9×\times higher throughput by automatically leveraging both data and model parallelism to deploy DNNs on our sample heterogeneous server node. Moreover, our modularity-based "splitting" heuristic improves the solution runtime up to 395×\times without noticeably sacrificing solution quality compared to an exact MILP solution, and outperforms all other heuristics by 30-60% solution quality. Finally, our case study shows how we can extend our framework to schedule large language models across multiple heterogeneous servers by exploiting symmetry in the hardware setup. Our code can be easily plugged in to existing frameworks, and is available at https://github.com/abdelfattah-lab/diviml.Comment: accepted at ICCAD'2
    • 

    corecore