LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
writeXML.m
1function writeXML(self,filename,useAbstractNames)
2% WRITEXML(SELF,FILENAME,USEAN)
3%
4% USEAN: if true replaces node names with abstract names eg E1, T1, ...
5%
6% Copyright (c) 2012-2026, Imperial College London
7% All rights reserved.
8
9if nargin<3
10 useAbstractNames=false;
11end
12nodeHashMap = containers.Map;
13
14tctr = 0;
15ectr = 0;
16actr = 0;
17if useAbstractNames
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);
23 tctr = tctr + 1;
24 nodeHashMap(curTask.name)=sprintf('T%d',tctr);
25 for e=1:length(curTask.entries)
26 curEntry = curTask.entries(e);
27 ectr = ectr + 1;
28 nodeHashMap(curEntry.name)=sprintf('E%d',ectr);
29 end
30 for a=1:length(curTask.activities)
31 curAct = curTask.activities(a);
32 actr = actr + 1;
33 nodeHashMap(curAct.name) = sprintf('A%d',actr);
34 end
35 end
36 end
37else
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;
47 end
48 for a=1:length(curTask.activities)
49 curAct = curTask.activities(a);
50 nodeHashMap(curAct.name)=curAct.name;
51 end
52 end
53 end
54end
55
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>
62import java.io.File;
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>
68
69precision = '%10.15e'; %precision for doubles
70docFactory = DocumentBuilderFactory.newInstance();
71docBuilder = docFactory.newDocumentBuilder();
72doc = docBuilder.newDocument();
73
74%Root Element
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));
80
81for p = 1:length(self.hosts)
82 %processor
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));
90 end
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);
95 end
96 if SchedStrategy.fromText(curProc.scheduling) == SchedStrategy.PS || SchedStrategy.fromText(curProc.scheduling) == SchedStrategy.PSPRIO
97 procElement.setAttribute('quantum', num2str(curProc.quantum));
98 end
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));
108 end
109 if SchedStrategy.fromText(curTask.scheduling) ~= SchedStrategy.INF
110 taskElement.setAttribute('multiplicity', num2str(curTask.multiplicity));
111 end
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));
124 end
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()));
134 end
135
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)));
142 end
143 end
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));
154 end
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));
159 end
160
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)));
166 end
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)));
172 end
173 end
174 for ap=1:length(curTask.precedences)
175 curActPrec = curTask.precedences(ap);
176 actPrecElement = doc.createElement('precedence');
177 taskActsElement.appendChild(actPrecElement);
178
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)));
183 end
184 for pra = 1:length(curActPrec.preActs)
185 preActElement = doc.createElement('activity');
186 preElement.appendChild(preActElement);
187 preActElement.setAttribute('name', nodeHashMap(curActPrec.preActs{pra}));
188 end
189
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)));
198 end
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)));
205 end
206 postElement.setAttribute('end', curActPrec.postActs{end});
207 else
208 for poa = 1:length(curActPrec.postActs)
209 postActElement = doc.createElement('activity');
210 postElement.appendChild(postActElement);
211 postActElement.setAttribute('name', nodeHashMap(curActPrec.postActs{poa}));
212 end
213 end
214 end
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);
220
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;
224
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));
228
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;
234 break;
235 end
236 end
237
238 if ~isCalledSync && ~isForwardingTarget
239 % Entry is only called asynchronously, skip reply-entry
240 continue;
241 end
242
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});
249 end
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}));
257 end
258 end
259 end
260 end
261end
262
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];
274end
275
276%if self.options.verbose
277% line_printf('\nLQN model: %s\n', filename);
278%end
279result = StreamResult(File(filename));
280transformer.transform(source, result);
281end
Definition Station.m:245