Chain-Load: integrate topology visualisation (DOT)

- provide as ''operator'' on the TestChainLink instance
- show shortened Node-Hash as label on each Node
This commit is contained in:
Fischlurch 2023-11-16 18:42:36 +01:00
parent 76f250a5cf
commit cc56117574
6 changed files with 200 additions and 125 deletions

View file

@ -109,6 +109,79 @@ namespace dot_gen { ///< Collection of builder DSL functions to generate Graphvi
};
/** generate a Node name or a node_statement
* defining attributes of that node. All variables
* use the format `N<number>`. */
struct Node : Code
{
Node (size_t id)
: Code{"N"+toString(id)}
{ }
Node&&
addAttrib (string def)
{
if (back() != ']')
append ("[");
else
{
resize (length()-2);
append (", ");
}
append (def+" ]");
return move(*this);
}
Node&&
label (string text)
{
return addAttrib ("label=\""+text+"\"");
}
Node&&
style (Code const& code)
{
if (not isnil(code))
addAttrib (code);
return move(*this);
}
};
/** accumulator to collect nodes grouped into a scope */
struct Scope : Code
{
Scope (size_t id)
: Code{"{ /*"+toString(id)+"*/ }"}
{ }
Scope&&
add (Code const& code)
{
resize(length()-1);
append (code+" }");
return move(*this);
}
Scope&&
rank (string rankSetting)
{
return add(Code{"rank="+rankSetting});
}
};
inline Node node (size_t id) { return Node(id); }
inline Scope scope (size_t id) { return Scope(id); }
/** generate a directed node connectivity clause */
inline Code
connect (size_t src, size_t dest)
{
return Code{Node(src) +" -> "+ Node(dest)};
}
/** Helper to collect DOT-Graphviz code for output */
class DotOut
{
@ -154,76 +227,6 @@ namespace dot_gen { ///< Collection of builder DSL functions to generate Graphvi
}
};
/** generate a Node name or a node_statement
* defining attributes of that node. All variables
* use the format `N<number>`. */
struct Node : Code
{
Node (size_t id)
: Code{"N"+toString(id)}
{ }
Node&&
addAttrib (string def)
{
if (back() != ']')
append ("[");
else
{
resize (length()-2);
append (", ");
}
append (def+" ]");
return move(*this);
}
Node&&
label (size_t i)
{
return addAttrib ("label="+toString(i));
}
Node&&
style (Code const& code)
{
if (not isnil(code))
addAttrib (code);
return move(*this);
}
};
/** accumulator to collect nodes grouped into a scope */
struct Scope : Code
{
Scope (size_t id)
: Code{"{ /*"+toString(id)+"*/ }"}
{ }
Scope&&
add (Code const& code)
{
resize(length()-1);
append (code+" }");
return move(*this);
}
Scope&&
rank (string rankSetting)
{
return add(Code{"rank="+rankSetting});
}
};
/** generate a directed node connectivity clause */
inline Code
connect (size_t src, size_t dest)
{
return Code{Node(src) +" -> "+ Node(dest)};
}
/**
* Entrance-point: generate a graph spec in DOT-Language.
* @param parts a sequence of Section or Code objects to be combined and rendered

View file

@ -325,6 +325,7 @@ namespace util {
using std::setw;
using std::right;
using std::setfill;
using std::uppercase;
using std::noshowbase;
using std::ostringstream;
using std::ostream;
@ -399,5 +400,24 @@ namespace util {
{ return FAILURE_INDICATOR; }
string
showHash (size_t hash, uint showBytes) noexcept
try {
showBytes = util::limited (1u, showBytes, 8u);
size_t suffix_modulus = size_t(1) << showBytes * 8;
ostringstream buffer;
buffer << hex
<< uppercase
<< noshowbase
<< setw (showBytes * 2) // need 2 hex digits per byte
<< setfill('0')
<< right
<< (showBytes==8? hash : hash % suffix_modulus);
return buffer.str();
}
catch(...)
{ return FAILURE_INDICATOR; }
} // namespace util

View file

@ -91,6 +91,16 @@ namespace util {
/** preconfigured format for pretty-printing of addresses */
std::ostream& showAddr (std::ostream&, void const* addr);
/** renders the size_t in hex, optionally only trailing bytes */
std::string showHash (size_t hash, uint showBytes=8) noexcept;
inline std::string
showHashLSB (size_t hash) noexcept
{
return showHash(hash,1);
}
namespace {
/** toggle to prefer specialisation with direct lexical conversion */

View file

@ -170,50 +170,12 @@ namespace test {
verify_Topology()
{
auto graph = TestChainLoad<32>{}
.buildToplolgy();
.buildToplolgy()
.printTopologyDOT();
CHECK (31 == graph.topLevel());
CHECK (0 == graph.getSeed());
CHECK (0 == graph.getHash());
///////////////////////////////////////////////////////////////////////TODO : what follows is WIP to test the DOT graph generator....
using N = const TestChainLoad<32>::Node;
using namespace dot;
Section nodes("Nodes");
Section layers("Layers");
Section topology("Topology");
Code BOTTOM{"shape=doublecircle"};
Code SEED {"shape=circle"};
Code TOP {"shape=box, style=rounded"};
Code DEFAULT{};
N& n0n = *graph.allNodes();
auto nNr = [&](N& nn){ return size_t(&nn - &n0n); };
size_t level(0);
Scope timeLevel{level};
layers += timeLevel.rank("min ");
for (N& nn : graph.allNodes())
{
size_t i = nNr(nn);
nodes += Node(i).label(i+1).style(i==0 ? BOTTOM
:isnil(nn.pred)? SEED
:isnil(nn.succ)? TOP
: DEFAULT);
for (N* suc : nn.succ)
topology += connect(i, nNr(*suc));
if (level != nn.level)
{
++level;
ENSURE (level == nn.level);
timeLevel = Scope(level).rank("same");
layers += timeLevel;
}
timeLevel.add(Node(i));
}
cout << digraph(nodes,layers,topology) <<endl;
}

View file

@ -86,6 +86,7 @@
//#include "lib/meta/function.hpp"
//#include "lib/wrapper.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/format-cout.hpp"
#include "lib/dot-gen.hpp"
#include <boost/functional/hash.hpp>
@ -111,6 +112,8 @@ namespace test {
// using lib::meta::RebindVariadic;
using util::max;
using util::unConst;
using util::toString;
using util::showHashLSB;
// using std::forward;
// using std::string;
using std::swap;
@ -256,7 +259,7 @@ namespace test {
/**
* Use current configuration and seed to (re)build Node connectivity.
*/
TestChainLoad
TestChainLoad&&
buildToplolgy()
{
NodeTab a,b, // working data for generation
@ -331,6 +334,66 @@ namespace test {
return move(*this);
}
/* ===== Operators ===== */
std::string
generateTopologyDOT()
{
using namespace dot;
Section nodes("Nodes");
Section layers("Layers");
Section topology("Topology");
// Styles to distinguish the computation nodes
Code BOTTOM{"shape=doublecircle"};
Code SEED {"shape=circle"};
Code TOP {"shape=box, style=rounded"};
Code DEFAULT{};
auto nodeID = [&](Node& nn){ return size_t(&nn - &nodes_->front()); };
// prepare time-level zero
size_t level(0);
auto timeLevel = scope(level);
layers += timeLevel.rank("min ");
for (Node& n : allNodes())
{
size_t i = nodeID(n);
nodes += node(i).label(toString(i)+": "+showHashLSB(n.hash))
.style(i==0 ? BOTTOM
:isnil(n.pred)? SEED
:isnil(n.succ)? TOP
: DEFAULT);
for (Node* suc : n.succ)
topology += connect (i, nodeID(*suc));
if (level != n.level)
{// switch to next time-level
++level;
ENSURE (level == n.level);
timeLevel = scope(level).rank("same");
layers += timeLevel;
}
timeLevel.add (node(i));
}
// combine and render collected definitions as DOT-code
return digraph (nodes, layers, topology);
}
TestChainLoad&&
printTopologyDOT()
{
cout << "───═══───═══───═══───═══───═══───═══───═══───═══───═══───═══───\n"
<< generateTopologyDOT()
<< "───═══───═══───═══───═══───═══───═══───═══───═══───═══───═══───"
<< endl;
return move(*this);
}
private:
};

View file

@ -95851,9 +95851,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
<node CREATED="1700100288256" ID="ID_844700164" MODIFIED="1700100289765" TEXT="control_Topology">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700100290904" ID="ID_1991398605" MODIFIED="1700100351351" TEXT="brauche Hilfsmittel zur Visualisierung">
<node COLOR="#338800" CREATED="1700100290904" ID="ID_1991398605" MODIFIED="1700156439824" TEXT="brauche Hilfsmittel zur Visualisierung">
<arrowlink COLOR="#62819c" DESTINATION="ID_1464042796" ENDARROW="Default" ENDINCLINATION="21;-256;" ID="Arrow_ID_596151514" STARTARROW="None" STARTINCLINATION="787;55;"/>
<icon BUILTIN="pencil"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1700100356900" FOLDED="true" HGAP="45" ID="ID_216360062" LINK="#ID_764096140" MODIFIED="1700105412090" TEXT="erst mal einfaches Referenz-Skript (re)-generieren" VSHIFT="-5">
<icon BUILTIN="button_ok"/>
<node CREATED="1700100394556" ID="ID_587545230" MODIFIED="1700100416123" TEXT="die entsprechende Node-Struktur fest verdrahtet aufbauen"/>
@ -96011,11 +96011,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699971822836" ID="ID_1118263931" MODIFIED="1699971831481" TEXT="Diagnostik">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1699972014017" ID="ID_1464042796" MODIFIED="1700100343215" TEXT="Topologie sichtbar machen">
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1699971822836" ID="ID_1118263931" MODIFIED="1700156360589" TEXT="Diagnostik">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1699972014017" FOLDED="true" ID="ID_1464042796" MODIFIED="1700156443450" TEXT="Topologie sichtbar machen">
<linktarget COLOR="#62819c" DESTINATION="ID_1464042796" ENDARROW="Default" ENDINCLINATION="21;-256;" ID="Arrow_ID_596151514" SOURCE="ID_1991398605" STARTARROW="None" STARTINCLINATION="787;55;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1699972026007" ID="ID_551004748" MODIFIED="1700105381375" TEXT="Idee: DOT generieren (Graphviz)">
<arrowlink COLOR="#435fb4" DESTINATION="ID_1402372766" ENDARROW="Default" ENDINCLINATION="-1358;124;" ID="Arrow_ID_1189460163" STARTARROW="None" STARTINCLINATION="-1697;146;"/>
<icon BUILTIN="idea"/>
@ -96162,8 +96162,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1699983287679" ID="ID_1236079516" MODIFIED="1700105397578" TEXT="Ausgabestruktur erzeugen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1699983287679" ID="ID_1236079516" MODIFIED="1700156324205" TEXT="Ausgabestruktur erzeugen">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1699983387905" FOLDED="true" ID="ID_1906181979" MODIFIED="1700105376397" TEXT="mu&#xdf; Klammern und Gruppen erzeugen">
<icon BUILTIN="messagebox_warning"/>
<icon BUILTIN="hourglass"/>
@ -96415,23 +96415,36 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1699983654942" ID="ID_1968810638" MODIFIED="1700105304336" TEXT="lokale Spezialisierung hiervon im Arbeits-Scope">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1699983654942" ID="ID_1968810638" MODIFIED="1700156322919" TEXT="DSL verwenden zur Visualisierung">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1700105305528" ID="ID_1899482943" MODIFIED="1700105320553" TEXT="testweise direkt im verify_Topology() aufgebaut">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#435e98" CREATED="1700105322133" ID="ID_1080416201" MODIFIED="1700105347114" TEXT="einfache For-Schleife mit &#xbb;schleppendem&#xab; time-Level">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1700156293989" ID="ID_1727407041" MODIFIED="1700156304913" TEXT="Node-ID direkt aus Speicher-Offset ableiten">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1700156308658" ID="ID_646954295" MODIFIED="1700156321018" TEXT="Hash gek&#xfc;rzt darstellen (1byte)">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1700156287032" ID="ID_1166019368" MODIFIED="1700156292918" TEXT="Formate vorbelegen">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700147510434" ID="ID_1659345454" MODIFIED="1700151160461" TEXT="Extrahieren und reorganisieren">
<icon BUILTIN="pencil"/>
</node>
<node COLOR="#338800" CREATED="1700147510434" ID="ID_1659345454" MODIFIED="1700156327130" TEXT="Extrahieren und reorganisieren">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1700147703792" ID="ID_1662535458" MODIFIED="1700151155878" TEXT="separater Header: lib/dot-gen.hpp">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700151162860" ID="ID_479859970" MODIFIED="1700151187644" TEXT="Graph-generierungs-Code in eigenen Operator extrahieren">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1700151162860" ID="ID_479859970" MODIFIED="1700156416376" TEXT="Graph-generierungs-Code in eigenen Operator extrahieren">
<arrowlink COLOR="#42b360" DESTINATION="ID_1175949615" ENDARROW="Default" ENDINCLINATION="334;0;" ID="Arrow_ID_357935660" STARTARROW="None" STARTINCLINATION="-103;5;"/>
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1700156329113" ID="ID_1238209773" MODIFIED="1700156340930" TEXT="alternativ direkt nach SDOUT schreiben">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -96448,6 +96461,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1700156375137" ID="ID_1175949615" MODIFIED="1700156408543" TEXT="Topologie-Visualisierung">
<linktarget COLOR="#42b360" DESTINATION="ID_1175949615" ENDARROW="Default" ENDINCLINATION="334;0;" ID="Arrow_ID_357935660" SOURCE="ID_479859970" STARTARROW="None" STARTINCLINATION="-103;5;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700105549294" ID="ID_1778641158" MODIFIED="1700105554766" TEXT="Neuberechnung">
<icon BUILTIN="flag-yellow"/>
</node>