1function writeXML(self,filename,useAbstractNames)
2% WRITEXML(SELF,FILENAME,USEAN)
4% USEAN:
if true replaces node names with abstract names eg E1, T1, ...
6% Copyright (c) 2012-2026, Imperial College London
10 useAbstractNames=
false;
12nodeHashMap = containers.Map;
18 for p = 1:length(self.hosts)
19 curProc = self.hosts{p};
20 nodeHashMap(curProc.name)=sprintf(
'P%d',p);
21 for t=1:length(curProc.tasks)
22 curTask = curProc.tasks(t);
24 nodeHashMap(curTask.name)=sprintf('T%d',tctr);
25 for e=1:length(curTask.entries)
26 curEntry = curTask.entries(e);
28 nodeHashMap(curEntry.name)=sprintf('E%d',ectr);
30 for a=1:length(curTask.activities)
31 curAct = curTask.activities(a);
33 nodeHashMap(curAct.name) = sprintf('A%d',actr);
38 for p = 1:length(self.hosts)
39 curProc = self.hosts{p};
40 nodeHashMap(curProc.name)=curProc.name;
41 for t=1:length(curProc.tasks)
42 curTask = curProc.tasks(t);
43 nodeHashMap(curTask.name)=curTask.name;
44 for e=1:length(curTask.entries)
45 curEntry = curTask.entries(e);
46 nodeHashMap(curEntry.name)=curEntry.name;
48 for a=1:length(curTask.activities)
49 curAct = curTask.activities(a);
50 nodeHashMap(curAct.name)=curAct.name;
56import javax.xml.parsers.DocumentBuilderFactory; %
#ok<JAPIEXT629>
57import javax.xml.parsers.DocumentBuilder; %#ok<JAPIEXT629>
58import org.w3c.dom.Document; %#ok<JAPIEXT161>
59import org.w3c.dom.NodeList; %#ok<JAPIEXT161>
60import org.w3c.dom.Node; %#ok<JAPIEXT161>
61import org.w3c.dom.Element; %#ok<JAPIEXT161>
63import javax.xml.transform.Transformer; %#ok<JAPIEXT216>
64import javax.xml.transform.TransformerFactory; %#ok<JAPIEXT216>
65import javax.xml.transform.dom.DOMSource; %#ok<JAPIEXT216>
66import javax.xml.transform.stream.StreamResult; %#ok<JAPIEXT216>
67import javax.xml.transform.OutputKeys; %#ok<JAPIEXT216>
69precision =
'%10.15e'; %precision
for doubles
70docFactory = DocumentBuilderFactory.newInstance();
71docBuilder = docFactory.newDocumentBuilder();
72doc = docBuilder.newDocument();
75rootElement = doc.createElement(
'lqn-model');
76doc.appendChild(rootElement);
77rootElement.setAttribute(
'xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance');
78rootElement.setAttribute(
'xsi:noNamespaceSchemaLocation',
'lqn.xsd');
79rootElement.setAttribute(
'name', getName(self));
81for p = 1:length(self.hosts)
83 curProc = self.hosts{p};
84 procElement = doc.createElement(
'processor');
85 rootElement.appendChild(procElement);
86 procElement.setAttribute(
'name', nodeHashMap(curProc.name));
87 procElement.setAttribute(
'scheduling', curProc.scheduling);
88 if curProc.replication>1
89 procElement.setAttribute(
'replication', num2str(curProc.replication));
91 if SchedStrategy.fromText(curProc.scheduling) ~= SchedStrategy.INF
92 mult = num2str(curProc.multiplicity);
93 if isinf(mult), mult=1; end
94 procElement.setAttribute(
'multiplicity', mult);
96 if SchedStrategy.fromText(curProc.scheduling) == SchedStrategy.PS || SchedStrategy.fromText(curProc.scheduling) == SchedStrategy.PSPRIO
97 procElement.setAttribute(
'quantum', num2str(curProc.quantum));
99 procElement.setAttribute(
'speed-factor', num2str(curProc.speedFactor));
100 for t=1:length(curProc.tasks)
101 curTask = curProc.tasks(t);
102 taskElement = doc.createElement('task');
103 procElement.appendChild(taskElement);
104 taskElement.setAttribute('name', nodeHashMap(curTask.name));
105 taskElement.setAttribute('scheduling', curTask.scheduling);
106 if curTask.replication>1
107 taskElement.setAttribute('replication', num2str(curTask.replication));
109 if SchedStrategy.fromText(curTask.scheduling) ~= SchedStrategy.INF
110 taskElement.setAttribute('multiplicity', num2str(curTask.multiplicity));
112 % think-time may only be written for a reference task: lqns rejects
the
113 % file outright ('Task "X"
is not a reference task; it cannot have think
114 % time'). LINE does give a non-reference task's think time to its
115 % callers, so that value cannot survive this format and
the loss
is
116 % reported rather than left silent. Bridges that need it (PYLINE
117 % lang='python') reapply it after parseXML.
118 if SchedStrategy.fromText(curTask.scheduling) == SchedStrategy.REF
119 taskElement.setAttribute('think-time', num2str(curTask.thinkTimeMean));
120 elseif ~isempty(curTask.thinkTimeMean) && curTask.thinkTimeMean > 0
121 line_warning(mfilename, sprintf(['Task %s
is not a reference task, so its think time (%g) ', ...
122 '
is not written:
the LQN XML schema accepts think-time on reference tasks only.'], ...
123 curTask.name, curTask.thinkTimeMean));
125 for e=1:length(curTask.entries)
126 curEntry = curTask.entries(e);
127 entryElement = doc.createElement('entry');
128 taskElement.appendChild(entryElement);
129 entryElement.setAttribute('name', nodeHashMap(curEntry.name));
130 entryElement.setAttribute('type', 'NONE');
131 if ~isempty(curEntry.arrival) && isa(curEntry.arrival, 'Distribution') && ...
132 isfinite(curEntry.arrival.getMean()) && curEntry.arrival.getMean() > GlobalConstants.FineTol
133 entryElement.setAttribute('open-arrival-rate', num2str(1 / curEntry.arrival.getMean()));
136 % Write forwarding calls
137 for fw=1:length(curEntry.forwardingDests)
138 fwdElement = doc.createElement('forwarding');
139 entryElement.appendChild(fwdElement);
140 fwdElement.setAttribute('dest', nodeHashMap(curEntry.forwardingDests{fw}));
141 fwdElement.setAttribute(
'prob', num2str(curEntry.forwardingProbs(fw)));
144 taskActsElement = doc.createElement(
'task-activities');
145 taskElement.appendChild(taskActsElement);
146 for a=1:length(curTask.activities)
147 curAct = curTask.activities(a);
148 actElement = doc.createElement('activity');
149 taskActsElement.appendChild(actElement);
150 actElement.setAttribute('host-demand-mean', num2str(curAct.hostDemandMean));
151 actElement.setAttribute('host-demand-cvsq', num2str(curAct.hostDemandSCV));
152 if ~isempty(curAct.boundToEntry)
153 actElement.setAttribute('bound-to-entry', nodeHashMap(curAct.boundToEntry));
155 actElement.setAttribute('call-order', curAct.callOrder);
156 actElement.setAttribute('name', nodeHashMap(curAct.name));
157 if curAct.thinkTimeMean > GlobalConstants.FineTol
158 actElement.setAttribute('think-time', num2str(curAct.thinkTimeMean));
161 for sc=1:length(curAct.syncCallDests)
162 syncCallElement = doc.createElement('synch-call');
163 actElement.appendChild(syncCallElement);
164 syncCallElement.setAttribute('dest', nodeHashMap(curAct.syncCallDests{sc}));
165 syncCallElement.setAttribute(
'calls-mean', num2str(curAct.syncCallMeans(sc)));
167 for ac=1:length(curAct.asyncCallDests)
168 asyncCallElement = doc.createElement('asynch-call');
169 actElement.appendChild(asyncCallElement);
170 asyncCallElement.setAttribute('dest', nodeHashMap(curAct.asyncCallDests{ac}));
171 asyncCallElement.setAttribute(
'calls-mean', num2str(curAct.asyncCallMeans(ac)));
174 for ap=1:length(curTask.precedences)
175 curActPrec = curTask.precedences(ap);
176 actPrecElement = doc.createElement('precedence');
177 taskActsElement.appendChild(actPrecElement);
179 preElement = doc.createElement(ActivityPrecedenceType.toText(curActPrec.preType));
180 actPrecElement.appendChild(preElement);
181 if curActPrec.preType== ActivityPrecedenceType.PRE_AND && ~isempty(curActPrec.preParams)
182 preElement.setAttribute('quorum', num2str(curActPrec.preParams(1)));
184 for pra = 1:length(curActPrec.preActs)
185 preActElement = doc.createElement('activity');
186 preElement.appendChild(preActElement);
187 preActElement.setAttribute('name', nodeHashMap(curActPrec.preActs{pra}));
190 postElement = doc.createElement(ActivityPrecedenceType.toText(curActPrec.postType));
191 actPrecElement.appendChild(postElement);
192 if curActPrec.postType==ActivityPrecedenceType.POST_OR
193 for poa = 1:length(curActPrec.postActs)
194 postActElement = doc.createElement('activity');
195 postElement.appendChild(postActElement);
196 postActElement.setAttribute('name', nodeHashMap(curActPrec.postActs{poa}));
197 postActElement.setAttribute(
'prob', num2str(curActPrec.postParams(poa)));
199 elseif curActPrec.postType==ActivityPrecedenceType.POST_LOOP
200 for poa = 1:length(curActPrec.postActs)-1
201 postActElement = doc.createElement(
'activity');
202 postElement.appendChild(postActElement);
203 postActElement.setAttribute(
'name', nodeHashMap(curActPrec.postActs{poa}));
204 postActElement.setAttribute(
'count', num2str(curActPrec.postParams(poa)));
206 postElement.setAttribute(
'end', curActPrec.postActs{end});
208 for poa = 1:length(curActPrec.postActs)
209 postActElement = doc.createElement('activity');
210 postElement.appendChild(postActElement);
211 postActElement.setAttribute('name', nodeHashMap(curActPrec.postActs{poa}));
215 if SchedStrategy.fromText(curTask.scheduling) ~= SchedStrategy.REF
216 % Get
the model structure to check
for sync vs async calls
217 lsn = self.getStruct();
218 for e=1:length(curTask.entries)
219 curEntry = curTask.entries(e);
221 % Find this entry's index in
the model
222 eidx = find(cellfun(@(x) strcmp(x.name, curEntry.name), self.entries));
223 globalEidx = lsn.eshift + eidx;
225 % Check if this entry
is called synchronously or
is a forwarding target
226 % If only called asynchronously (and not a forwarding target), skip generating reply-entry
227 isCalledSync = any(lsn.issynccaller(:, globalEidx));
229 % Check if this entry
is a forwarding target (receives forwarded requests)
230 isForwardingTarget = false;
231 for cidx = 1:lsn.ncalls
232 if full(lsn.calltype(cidx)) == CallType.FWD && full(lsn.callpair(cidx, 2)) == globalEidx
233 isForwardingTarget = true;
238 if ~isCalledSync && ~isForwardingTarget
239 % Entry
is only called asynchronously, skip reply-entry
243 if isempty(curEntry.replyActivity)
244 %
the model was presumably loaded from a file without
245 % reply-activity specified by now lqns asks them so we
246 % need to calculate their location
247 racts = find(lsn.replygraph(:,eidx));
248 curEntry.replyActivity{1,end+1} = nodeHashMap(lsn.names{lsn.ashift+ racts});
250 entryReplyElement = doc.createElement(
'reply-entry');
251 taskActsElement.appendChild(entryReplyElement);
252 entryReplyElement.setAttribute(
'name', nodeHashMap(curEntry.name));
253 for r=1:length(curEntry.replyActivity)
254 entryReplyActElement = doc.createElement('reply-activity');
255 entryReplyElement.appendChild(entryReplyActElement);
256 entryReplyActElement.setAttribute('name', nodeHashMap(curEntry.replyActivity{r}));
263%write
the content into xml file
264transformerFactory = TransformerFactory.newInstance();
265transformer = transformerFactory.newTransformer();
266transformer.setOutputProperty(OutputKeys.INDENT,
'yes');
267transformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount",
"2");
268transformer.setOutputProperty(OutputKeys.VERSION,
"1.0");
269transformer.setOutputProperty(OutputKeys.ENCODING,
"UTF-8");
270transformer.setOutputProperty(OutputKeys.STANDALONE,
"no");
271source = DOMSource(doc);
272if isempty(fileparts(filename))
273 filename=[lineRootFolder,filesep,
'workspace',filesep,filename];
276%
if self.options.verbose
277% line_printf(
'\nLQN model: %s\n', filename);
279result = StreamResult(File(filename));
280transformer.transform(source, result);