Since the cfg file really defines a data flow graph with connected plugins, is there a tool that will display the graph. This would be very useful in debugging cfg files and in understanding the examples.
I am used to coding for FPGAs where compute is done via data flow rather than instruction execution.
Hope there is a tool in openmha.
Dan..
can one produce a data flow graph
-
- Posts: 119
- Joined: Mon Jun 24, 2019 12:51 pm
Re: can one produce a data flow graph
openMHA does not have a flow graph visualizer. The closest that I could find is a rudimentary tool that scans running MHA instances, recognizes some special strings in the responses,, and produces .dot files which can then be processed by graphviz. E.g. this is the graph generated for openMHA example 18, altconfig.
It is not on our roadmap to maintain or extend this tool. It consists of ~190 lines of Octave code, I'm inserting it here:
Code: Select all
function sGraph = scan_graph( mha, dotname, showall )
% scan_graph - scan hierarchical structure of a MHA instance
%
% sGraph = scan_graph( mha, dotname, showall )
if nargin < 1
mha = [];
end
if nargin < 2
dotname = 'temp.dot';
end
if nargin < 3
showall = false;
end
mha = mha_ensure_mhahandle( mha );
sGraph = struct;
sGraph.nodes = cell(0,2);
sGraph.leaves = cell(0,2);
sGraph.connections = cell(0,2);
sGraph.pconnections = cell(0,2);
sGraph.aconnections = cell(0,2);
sGraph.chains = cell(0,1);
sGraph = scan_sub( mha, '', sGraph, '', struct('id','') );
write_dot_file( sGraph, dotname, showall );
system(sprintf('dot -Tpng %s > %s.png',dotname,dotname(1:end-4)));
function sGraph = scan_sub( mha, prefix, sGraph, parent, parentinfo )
info = mha_getinfo(mha,prefix);
info.fullpath = prefix;
info.cfgname = prefix;
info.cfgname(1:max(find(info.cfgname=='.'))) = [];
info.dll = '';
if strcmp(info.cfgname,'identity')
parent
parentinfo
end
if isfield(parentinfo,'chain_names')
idx = strmatch(info.cfgname,parentinfo.chain_names);
if ~isempty(idx)
info.dll = parentinfo.chain_dlls{idx};
end
end
if strcmp(info.id,'mhachain')
algo_names = mha_get(mha,[prefix,'.algos']);
algo_dlls = algo_names;
longalgo_names = algo_names;
for k=1:numel(algo_names)
if ~isempty(find(algo_names{k}==':'))
algo_names{k}(1:max(find(algo_names{k}==':'))) = [];
end
if ~isempty(find(algo_dlls{k}==':'))
algo_dlls{k}(max(find(algo_dlls{k}==':')):end) = [];
end
info.chain_names = algo_names;
info.chain_dlls = algo_dlls;
longalgo_names{k} = mhapath2dot([prefix,'.',algo_names{k}]);
end
for k=2:numel(algo_names)
sGraph.aconnections(end+1,:) = ...
{[longalgo_names{k-1},''],[longalgo_names{k},'']};
end
sGraph.aconnections(end+1,:) = ...
{[mhapath2dot(prefix),':sw'],[longalgo_names{1},':w']};
sGraph.aconnections(end+1,:) = ...
{[longalgo_names{end},':e'],[mhapath2dot(prefix),':se']};
sGraph.chains{end+1} = longalgo_names;
end
if strcmp(info.id,'split')
info.plugin = true;
algo_names = mha_get(mha,[prefix,'.algos']);
algo_dlls = algo_names;
longalgo_names = algo_names;
for k=1:numel(algo_names)
if ~isempty(find(algo_names{k}==':'))
algo_names{k}(1:max(find(algo_names{k}==':'))) = [];
end
if ~isempty(find(algo_dlls{k}==':'))
algo_dlls{k}(max(find(algo_dlls{k}==':')):end) = [];
end
info.chain_names = algo_names;
info.chain_dlls = algo_dlls;
longalgo_names{k} = mhapath2dot([prefix,'.',algo_names{k}]);
end
for k=1:numel(algo_names)
sGraph.aconnections(end+1,:) = ...
{[mhapath2dot(prefix),':sw'],[longalgo_names{k},':nw']};
sGraph.aconnections(end+1,:) = ...
{[longalgo_names{k},':ne'],[mhapath2dot(prefix),':se']};
end
sGraph.chains{end+1} = longalgo_names;
end
if strcmp(info.id,'altplugs')
algo_names = mha_get(mha,[prefix,'.plugs']);
algo_dlls = algo_names;
longalgo_names = algo_names;
for k=1:numel(algo_names)
if ~isempty(find(algo_names{k}==':'))
algo_names{k}(1:max(find(algo_names{k}==':'))) = [];
end
if ~isempty(find(algo_dlls{k}==':'))
algo_dlls{k}(max(find(algo_dlls{k}==':')):end) = [];
end
info.chain_names = algo_names;
info.chain_dlls = algo_dlls;
end
end
if strcmp(info.type,'parser')
%if (~strcmp(info.cfgname,'mhaconfig_in')) && (~strcmp(info.cfgname,'mhaconfig_out'))
entries = mha_mha2matlab( 'vector<string>', info.entries );
info.plugin = false;
if strmatch('mhaconfig_in',entries,'exact')
info.plugin = true;
info.mhaconfig_in = mha_get(mha,[prefix,'.mhaconfig_in']);
info.mhaconfig_out = mha_get(mha,[prefix,'.mhaconfig_out']);
end
if ~isempty(prefix)
sGraph.nodes(end+1,:) = {mhapath2dot(prefix),info};
if ~isempty(parent) && ~strcmp(parentinfo.id,'mhachain') && ~strcmp(parentinfo.id,'split')
sGraph.pconnections(end+1,:) = {mhapath2dot(parent), ...
mhapath2dot(prefix)};
end
end
for e = entries
if (~strcmp(e{:},'mhaconfig_in')) && (~strcmp(e{:},'mhaconfig_out'))
if isempty( prefix )
sSub = e{:};
else
sSub = [prefix,'.',e{:}];
sGraph.connections(end+1,:) = {...
mhapath2dot(prefix),...
mhapath2dot(sSub)...
};
end
sGraph = scan_sub( mha, sSub, sGraph, prefix, info );
end
end
%end
else
sGraph.leaves(end+1,:) = {mhapath2dot(prefix),info};
end
function sdot = mhapath2dot( smha )
sdot = strrep( smha, '.', '_');
function write_dot_file( sGraph, fname, showall )
f = fopen(fname,'w');
fprintf(f,'digraph mha {\n');
for k=1:size(sGraph.nodes,1)
%style="filled", fillcolor="lightblue"
sLabel = sGraph.nodes{k,2}.cfgname;
if ~isempty(sGraph.nodes{k,2}.id)
sLabel = sprintf('%s\\n(%s)',sLabel,sGraph.nodes{k,2}.id);
else
if ~isempty(sGraph.nodes{k,2}.dll)
sLabel = sprintf('%s\\n(%s)',sLabel,sGraph.nodes{k,2}.dll);
end
end
if isfield(sGraph.nodes{k,2},'mhaconfig_in')
sLabel = sprintf('%s\\n\\ni: %dc/%d/%g Hz\\no: %dc/%d/%g Hz',sLabel,...
sGraph.nodes{k,2}.mhaconfig_in.channels,sGraph.nodes{k,2}.mhaconfig_in.fragsize,sGraph.nodes{k,2}.mhaconfig_in.srate,...
sGraph.nodes{k,2}.mhaconfig_out.channels,sGraph.nodes{k,2}.mhaconfig_out.fragsize,sGraph.nodes{k,2}.mhaconfig_out.srate);
end
fprintf(f,' %s [label="%s", shape="box"',...
sGraph.nodes{k,1},sLabel);
if sGraph.nodes{k,2}.plugin
fprintf(f,', style="filled", fillcolor="lightblue"');
end
fprintf(f,'];\n');
end
if showall
for k=1:size(sGraph.leaves,1)
fprintf(f,' %s [label="%s"];\n',...
sGraph.leaves{k},...
sGraph.leaves{k,2}.cfgname);
end
for k=1:size(sGraph.connections,1)
fprintf(f,' %s -> %s [penwidth=1,arrowhead="none"];\n',sGraph.connections{k,1},sGraph.connections{k,2});
end
end
for k=1:size(sGraph.pconnections,1)
fprintf(f,' %s -> %s:n [penwidth=1,arrowhead="none"];\n',sGraph.pconnections{k,1},sGraph.pconnections{k,2});
end
for k=1:size(sGraph.aconnections,1)
fprintf(f,' %s -> %s [penwidth=3,arrowhead="normal",color="#A01010"];\n',sGraph.aconnections{k,1},sGraph.aconnections{k,2});
end
for k=1:numel(sGraph.chains)
fprintf(f,' { rank="same";\n');
for k1=1:numel(sGraph.chains{k})
fprintf(f,' %s;\n',sGraph.chains{k}{k1});
end
fprintf(f,' }\n');
end
fprintf(f,'}\n');
fclose(f);